diff --git a/DEPS b/DEPS
index a92e2b9..d9556a5 100644
--- a/DEPS
+++ b/DEPS
@@ -312,11 +312,11 @@
   # 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': 'c67d3ca33324c285890dae598cd55b096d10b73f',
+  'v8_revision': '82a498a1162a45f02fa3ce187d2232b5428a60a3',
   # 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': '54d094fe1de5da53a85523a68f898aeccb504a58',
+  'angle_revision': '3e25d37f23d0432aa1a43bf920ae4110f48fd36c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -423,7 +423,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': '3e1501af29365c74b18b7c9090a46b779a204bfb',
+  'dawn_revision': 'cc636273dad2d84c8d5a929d0276097f447437d2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -1661,7 +1661,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '5c42ac9c2c8efd77f14d56462d18eb644f36b78b',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '9e3155013cd72ac43b4e07e47823e6d00cef48e9',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1799,7 +1799,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/turbine',
-              'version': 'RXO2k7-PyXvbDjiK9EjbsheQfxXme2n0ABNX-MxR0JcC',
+              'version': 'rrpgWQ-uylo8c5IPgUVP464LwcVOmt29MqwsR59O_zkC',
           },
       ],
       'condition': 'checkout_android',
@@ -1846,7 +1846,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '74b1f15354f71608a0c08416b21988423e13b65b',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'ca7616f061763c668ce09b82a4e7ba49d9dc0fc3',
+    Var('webrtc_git') + '/src.git' + '@' + '5c9b7da038caa1972c6f3df83aa3028f3e4551da',
 
   # Wuffs' canonical repository is at github.com/google/wuffs, but we use
   # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file.
@@ -1916,7 +1916,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@ef12e0c34eecbd74dfb9468491f45d740b0e9179',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@ce03f1f74baab1a98523fa315e0e60b7639d5a26',
     'condition': 'checkout_src_internal',
   },
 
@@ -1946,7 +1946,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': 'f8ylwl_7HqTWTqihQRH3WL8iS0xuAWqrigwpSJJfwIYC',
+        'version': '-T3bPgx42mqt722T-5CKMbYi8v3Oy_dlZHkIhPvXgRoC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -1968,7 +1968,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/projector_app/app',
-        'version': 'fOPFXhlcio6ln-pWXAl5mjzBhbF88ooEtWFBfCFylk4C',
+        'version': 'Xy1Ztjw2_use1iQ_HX433qdtmSmwuCJy67uKkZtUpUAC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
index 535189d..0dc5382 100644
--- a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
+++ b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
@@ -153,9 +153,6 @@
             Flag.baseFeature(BlinkFeatures.GMS_CORE_EMOJI,
                     "Enables retrieval of the emoji font through GMS Core "
                             + "improving emoji glyph coverage."),
-            Flag.baseFeature(AutofillFeatures.AUTOFILL_SERVER_TYPE_TAKES_PRECEDENCE,
-                    "Enables server type marked as overrides to take precedence over the "
-                            + "autocomplete attribute."),
             Flag.baseFeature(AutofillFeatures.AUTOFILL_ACROSS_IFRAMES,
                     "Enable Autofill for frame-transcending forms (forms whose fields live in "
                             + "different frames)."),
@@ -381,6 +378,9 @@
                     CcFeatures.AVOID_RASTER_DURING_ELASTIC_OVERSCROLL, "No effect on webview"),
             Flag.baseFeature(BlinkFeatures.DOCUMENT_EVENT_NODE_PATH_CACHING,
                     "Enables a performance optimization that caches event paths."),
+            Flag.baseFeature(BlinkFeatures.WEB_RTC_METRONOME,
+                    "Inject a metronome into webrtc to allow task coalescing, "
+                            + " including synchronized decoding.")
             // Add new commandline switches and features above. The final entry should have a
             // trailing comma for cleaner diffs.
     };
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 6fab762e..47d7456d 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -481,7 +481,7 @@
 // Do we use the default LXD version or try LXD 4?
 BASE_FEATURE(kCrostiniUseLxd4,
              "CrostiniUseLxd4",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 // Enables experimental UI creating and managing multiple Crostini containers.
 BASE_FEATURE(kCrostiniMultiContainer,
@@ -2377,6 +2377,10 @@
   return base::FeatureList::IsEnabled(kDriveFsMirroring);
 }
 
+bool IsInlineSyncStatusEnabled() {
+  return base::FeatureList::IsEnabled(kFilesInlineSyncStatus);
+}
+
 bool IsEapGtcWifiAuthenticationEnabled() {
   return base::FeatureList::IsEnabled(kEapGtcWifiAuthentication);
 }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index f3e8d51..be0fdf3 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -654,6 +654,7 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsDragUnpinnedAppToPinEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsDragWindowToNewDeskEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsDriveFsMirroringEnabled();
+COMPONENT_EXPORT(ASH_CONSTANTS) bool IsInlineSyncStatusEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsEapGtcWifiAuthenticationEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsEcheSWAEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsEcheSWADebugModeEnabled();
diff --git a/ash/login/ui/media_controls_header_view.cc b/ash/login/ui/media_controls_header_view.cc
index c26c23b..404c8dd 100644
--- a/ash/login/ui/media_controls_header_view.cc
+++ b/ash/login/ui/media_controls_header_view.cc
@@ -120,7 +120,7 @@
 void MediaControlsHeaderView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
   // A valid role must be set prior to setting the name.
   node_data->role = ax::mojom::Role::kPane;
-  node_data->SetName(app_name_view_->GetText());
+  node_data->SetNameChecked(app_name_view_->GetText());
 }
 
 void MediaControlsHeaderView::OnViewFocused(views::View* observed_view) {
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1
index 1ff4b5b..c1c84e2 100644
--- a/build/fuchsia/linux_internal.sdk.sha1
+++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@
-9.20221009.3.1
+9.20221010.1.1
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/BackupSigninProcessor.java b/chrome/android/java/src/org/chromium/chrome/browser/BackupSigninProcessor.java
index 0b0b2f1..8b96b4c5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/BackupSigninProcessor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/BackupSigninProcessor.java
@@ -75,25 +75,25 @@
     private static void signinAndEnableSync(@NonNull Account account, Activity activity) {
         IdentityServicesProvider.get()
                 .getSigninManager(Profile.getLastUsedRegularProfile())
-                // TODO(crbug.com/1371130): Use a dedicated SigninAccessPoint.
-                .signinAndEnableSync(SigninAccessPoint.START_PAGE, account, new SignInCallback() {
-                    @Override
-                    public void onSignInComplete() {
-                        UnifiedConsentServiceBridge.setUrlKeyedAnonymizedDataCollectionEnabled(
-                                Profile.getLastUsedRegularProfile(), true);
-                        // TODO(crbug.com/1371130): Use a dedicated SyncFirstSetupCompleteSource.
-                        SyncService.get().setFirstSetupComplete(
-                                SyncFirstSetupCompleteSource.BASIC_FLOW);
-                        setBackupFlowSigninComplete();
-                    }
+                .signinAndEnableSync(SigninAccessPoint.POST_DEVICE_RESTORE_BACKGROUND_SIGNIN,
+                        account, new SignInCallback() {
+                            @Override
+                            public void onSignInComplete() {
+                                UnifiedConsentServiceBridge
+                                        .setUrlKeyedAnonymizedDataCollectionEnabled(
+                                                Profile.getLastUsedRegularProfile(), true);
+                                SyncService.get().setFirstSetupComplete(
+                                        SyncFirstSetupCompleteSource.ANDROID_BACKUP_RESTORE);
+                                setBackupFlowSigninComplete();
+                            }
 
-                    @Override
-                    public void onSignInAborted() {
-                        // If sign-in failed, give up and mark as complete.
-                        // TODO(crbug.com/1371130): Measure how often this happens.
-                        setBackupFlowSigninComplete();
-                    }
-                });
+                            @Override
+                            public void onSignInAborted() {
+                                // If sign-in failed, give up and mark as complete.
+                                // TODO(crbug.com/1371130): Measure how often this happens.
+                                setBackupFlowSigninComplete();
+                            }
+                        });
     }
 
     /**
diff --git a/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc b/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
index fe9c2c9..3581c17d 100644
--- a/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
@@ -1410,8 +1410,11 @@
 // and regains focus. Additionally, the webview does not process keypresses sent
 // while another window is focused.
 // http://crbug.com/660044.
+// Flaky on MacOSX, crbug.com/817067.
 // Flaky on linux, crbug.com/706830.
-#if BUILDFLAG(IS_LINUX)
+// Flaky on Windows, crbug.com/847201.
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC) || \
+    BUILDFLAG(IS_WIN)
 #define MAYBE_KeyboardFocusWindowCycle DISABLED_KeyboardFocusWindowCycle
 #else
 #define MAYBE_KeyboardFocusWindowCycle KeyboardFocusWindowCycle
diff --git a/chrome/browser/ash/crostini/crostini_manager.cc b/chrome/browser/ash/crostini/crostini_manager.cc
index 6d2a028..83991f39 100644
--- a/chrome/browser/ash/crostini/crostini_manager.cc
+++ b/chrome/browser/ash/crostini/crostini_manager.cc
@@ -306,12 +306,12 @@
       {mojom::InstallerState::kStart, base::Minutes(2)},
       {mojom::InstallerState::kInstallImageLoader,
        base::Hours(6)},  // May need to download DLC or component
-      {mojom::InstallerState::kCreateDiskImage, base::Minutes(8)},
+      {mojom::InstallerState::kCreateDiskImage, base::Minutes(5)},
       {mojom::InstallerState::kStartTerminaVm, kStartVmTimeout},
       {mojom::InstallerState::kStartLxd, base::Minutes(5)},
       // While CreateContainer may need to download a file, we get progress
       // messages that reset the countdown.
-      {mojom::InstallerState::kCreateContainer, base::Minutes(8)},
+      {mojom::InstallerState::kCreateContainer, base::Minutes(5)},
       {mojom::InstallerState::kSetupContainer, base::Minutes(5)},
       // StartContainer sends heartbeat messages on a 30-second interval, but
       // there's a bit of work that's not covered by heartbeat messages so to be
diff --git a/chrome/browser/ash/crostini/crostini_manager_unittest.cc b/chrome/browser/ash/crostini/crostini_manager_unittest.cc
index e24d47c9..e769649 100644
--- a/chrome/browser/ash/crostini/crostini_manager_unittest.cc
+++ b/chrome/browser/ash/crostini/crostini_manager_unittest.cc
@@ -1215,9 +1215,9 @@
                      base::Unretained(this), run_loop()->QuitClosure()),
       this);
 
-  task_environment_.FastForwardBy(base::Minutes(7));
+  task_environment_.FastForwardBy(base::Minutes(4));
   crostini_manager_->OnLxdContainerDownloading(signal);
-  task_environment_.FastForwardBy(base::Minutes(7));
+  task_environment_.FastForwardBy(base::Minutes(4));
   ASSERT_EQ(0, restart_crostini_callback_count_);
 
   task_environment_.FastForwardBy(base::Minutes(6));
diff --git a/chrome/browser/ash/file_manager/file_manager_string_util.cc b/chrome/browser/ash/file_manager/file_manager_string_util.cc
index 111f55e..b1f65dc 100644
--- a/chrome/browser/ash/file_manager/file_manager_string_util.cc
+++ b/chrome/browser/ash/file_manager/file_manager_string_util.cc
@@ -1069,6 +1069,9 @@
   dict->Set("DRIVEFS_MIRRORING",
             chromeos::features::IsDriveFsMirroringEnabled());
 
+  dict->Set("INLINE_SYNC_STATUS",
+            chromeos::features::IsInlineSyncStatusEnabled());
+
   dict->Set("GUEST_OS",
             base::FeatureList::IsEnabled(chromeos::features::kGuestOsFiles));
 
diff --git a/chrome/browser/ash/guest_os/guest_os_share_path.h b/chrome/browser/ash/guest_os/guest_os_share_path.h
index 67b4f57d..b0830346 100644
--- a/chrome/browser/ash/guest_os/guest_os_share_path.h
+++ b/chrome/browser/ash/guest_os/guest_os_share_path.h
@@ -15,7 +15,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/task/sequenced_task_runner.h"
-#include "chrome/browser/ash/crostini/crostini_manager.h"
 #include "chrome/browser/ash/file_manager/volume_manager_observer.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chromeos/ash/components/dbus/concierge/concierge_client.h"
diff --git a/chrome/browser/ash/guest_os/public/guest_os_mount_provider_registry.cc b/chrome/browser/ash/guest_os/public/guest_os_mount_provider_registry.cc
index 17caff89..736bb6a5 100644
--- a/chrome/browser/ash/guest_os/public/guest_os_mount_provider_registry.cc
+++ b/chrome/browser/ash/guest_os/public/guest_os_mount_provider_registry.cc
@@ -41,7 +41,7 @@
   Id id = next_id_++;
   providers_[id] = std::move(provider);
   for (auto& observer : observers_) {
-    observer.OnRegistered(id, provider.get());
+    observer.OnRegistered(id, providers_[id].get());
   }
   return id;
 }
diff --git a/chrome/browser/ash/guest_os/public/guest_os_mount_provider_registry_unittest.cc b/chrome/browser/ash/guest_os/public/guest_os_mount_provider_registry_unittest.cc
index 36308de..3c327de 100644
--- a/chrome/browser/ash/guest_os/public/guest_os_mount_provider_registry_unittest.cc
+++ b/chrome/browser/ash/guest_os/public/guest_os_mount_provider_registry_unittest.cc
@@ -21,6 +21,7 @@
  public:
   std::vector<Id> ids_;
   void OnRegistered(Id id, GuestOsMountProvider* provider) override {
+    DCHECK(provider);
     ids_.push_back(id);
   }
   void OnUnregistered(Id id) override {
diff --git a/chrome/browser/ash/login/saml/saml_browsertest.cc b/chrome/browser/ash/login/saml/saml_browsertest.cc
index 2686caa..34f4e989 100644
--- a/chrome/browser/ash/login/saml/saml_browsertest.cc
+++ b/chrome/browser/ash/login/saml/saml_browsertest.cc
@@ -2249,11 +2249,9 @@
 
 // Verify that device trust is available for URLs that match a pattern
 // from allowed URLs list.
-// TODO(b:249437331): Fix regex compatibility for Device Trust
-IN_PROC_BROWSER_TEST_P(SAMLDeviceTrustEnrolledTest,
-                       DISABLED_PolicyRegexSuccess) {
+IN_PROC_BROWSER_TEST_P(SAMLDeviceTrustEnrolledTest, PolicyRegexSuccess) {
   SetDeviceContextAwareAccessSignalsAllowlistPolicy(
-      {"[*.]" + fake_saml_idp()->GetIdpDomain()});
+      {fake_saml_idp()->GetIdpDomain()});
 
   StartSamlAndWaitForIdpPageLoad(
       saml_test_users::kSixthUserCorpExampleTestEmail);
diff --git a/chrome/browser/ash/login/screens/update_screen.cc b/chrome/browser/ash/login/screens/update_screen.cc
index cf7a9262..b46ac16 100644
--- a/chrome/browser/ash/login/screens/update_screen.cc
+++ b/chrome/browser/ash/login/screens/update_screen.cc
@@ -141,6 +141,14 @@
     exit_callback_.Run(VersionUpdater::Result::UPDATE_SKIPPED);
     return true;
   }
+
+  if (g_browser_process->local_state()->GetBoolean(
+          "EnrollmentRecoveryRequired")) {
+    LOG(WARNING) << "Skip OOBE Update because of recovery mode enrollment.";
+    exit_callback_.Run(VersionUpdater::Result::UPDATE_SKIPPED);
+    return true;
+  }
+
   return false;
 }
 
diff --git a/chrome/browser/ash/login/test/oobe_screens_utils.cc b/chrome/browser/ash/login/test/oobe_screens_utils.cc
index 072872b..71ef943 100644
--- a/chrome/browser/ash/login/test/oobe_screens_utils.cc
+++ b/chrome/browser/ash/login/test/oobe_screens_utils.cc
@@ -128,9 +128,6 @@
     TapEulaAccept();
   }
 
-  WaitForUpdateScreen();
-  ExitUpdateScreenNoUpdate();
-
   WaitFor(EnrollmentScreenView::kScreenId);
 }
 
diff --git a/chrome/browser/ash/policy/dlp/dlp_content_manager_ash_unittest.cc b/chrome/browser/ash/policy/dlp/dlp_content_manager_ash_unittest.cc
index 8c3000a6..cd00d74 100644
--- a/chrome/browser/ash/policy/dlp/dlp_content_manager_ash_unittest.cc
+++ b/chrome/browser/ash/policy/dlp/dlp_content_manager_ash_unittest.cc
@@ -601,9 +601,11 @@
 
   // No restrictions are enforced for web_contents: allow.
   std::unique_ptr<content::WebContents> web_contents = CreateWebContents();
+  content::GlobalRenderFrameHostId rfh_id =
+      web_contents->GetPrimaryMainFrame()->GetGlobalId();
   EXPECT_EQ(GetManager()->GetConfidentialRestrictions(web_contents.get()),
             kEmptyRestrictionSet);
-  GetManager()->CheckPrintingRestriction(web_contents.get(), cb.Get());
+  GetManager()->CheckPrintingRestriction(web_contents.get(), rfh_id, cb.Get());
   VerifyHistogramCounts(/*blocked_count=*/0, /*warned_count=*/0,
                         /*total_count=*/1,
                         /*blocked_suffix=*/dlp::kPrintingBlockedUMA,
@@ -613,7 +615,7 @@
   helper_.ChangeConfidentiality(web_contents.get(), kPrintingRestricted);
   EXPECT_EQ(GetManager()->GetConfidentialRestrictions(web_contents.get()),
             kPrintingRestricted);
-  GetManager()->CheckPrintingRestriction(web_contents.get(), cb.Get());
+  GetManager()->CheckPrintingRestriction(web_contents.get(), rfh_id, cb.Get());
   VerifyHistogramCounts(/*blocked_count=*/1, /*warned_count=*/0,
                         /*total_count=*/2,
                         /*blocked_suffix=*/dlp::kPrintingBlockedUMA,
@@ -629,7 +631,7 @@
   helper_.DestroyWebContents(web_contents.get());
   EXPECT_EQ(GetManager()->GetConfidentialRestrictions(web_contents.get()),
             kEmptyRestrictionSet);
-  GetManager()->CheckPrintingRestriction(web_contents.get(), cb.Get());
+  GetManager()->CheckPrintingRestriction(web_contents.get(), rfh_id, cb.Get());
   VerifyHistogramCounts(/*blocked_count=*/1, /*warned_count=*/0,
                         /*total_count=*/3,
                         /*blocked_suffix=*/dlp::kPrintingBlockedUMA,
@@ -652,12 +654,14 @@
   EXPECT_CALL(cb, Run(true)).Times(3);
 
   std::unique_ptr<content::WebContents> web_contents = CreateWebContents();
+  content::GlobalRenderFrameHostId rfh_id =
+      web_contents->GetPrimaryMainFrame()->GetGlobalId();
 
   // Warn restriction is enforced: allow and remember that the user proceeded.
   helper_.ChangeConfidentiality(web_contents.get(), kPrintingWarned);
   EXPECT_EQ(GetManager()->GetConfidentialRestrictions(web_contents.get()),
             kPrintingWarned);
-  GetManager()->CheckPrintingRestriction(web_contents.get(), cb.Get());
+  GetManager()->CheckPrintingRestriction(web_contents.get(), rfh_id, cb.Get());
 
   EXPECT_EQ(events_.size(), 2u);
   EXPECT_THAT(events_[0],
@@ -675,7 +679,7 @@
       GetDlpHistogramPrefix() + dlp::kPrintingWarnProceededUMA, true, 1);
 
   // Check again: allow based on cached user's response - no dialog is shown.
-  GetManager()->CheckPrintingRestriction(web_contents.get(), cb.Get());
+  GetManager()->CheckPrintingRestriction(web_contents.get(), rfh_id, cb.Get());
 
   EXPECT_EQ(events_.size(), 3u);
   EXPECT_THAT(events_[2],
@@ -694,7 +698,7 @@
   helper_.DestroyWebContents(web_contents.get());
   EXPECT_EQ(GetManager()->GetConfidentialRestrictions(web_contents.get()),
             kEmptyRestrictionSet);
-  GetManager()->CheckPrintingRestriction(web_contents.get(), cb.Get());
+  GetManager()->CheckPrintingRestriction(web_contents.get(), rfh_id, cb.Get());
 
   EXPECT_EQ(events_.size(), 3u);
   VerifyHistogramCounts(/*blocked_count=*/0, /*warned_count=*/2,
@@ -721,12 +725,14 @@
   EXPECT_CALL(cb, Run(true)).Times(1);   // WebContents destroyed.
 
   std::unique_ptr<content::WebContents> web_contents = CreateWebContents();
+  content::GlobalRenderFrameHostId rfh_id =
+      web_contents->GetPrimaryMainFrame()->GetGlobalId();
 
   // Warn restriction is enforced: reject since the user canceled.
   helper_.ChangeConfidentiality(web_contents.get(), kPrintingWarned);
   EXPECT_EQ(GetManager()->GetConfidentialRestrictions(web_contents.get()),
             kPrintingWarned);
-  GetManager()->CheckPrintingRestriction(web_contents.get(), cb.Get());
+  GetManager()->CheckPrintingRestriction(web_contents.get(), rfh_id, cb.Get());
   EXPECT_EQ(events_.size(), 1u);
   EXPECT_THAT(events_[0],
               IsDlpPolicyEvent(CreateDlpPolicyEvent(
@@ -740,7 +746,7 @@
       GetDlpHistogramPrefix() + dlp::kPrintingWarnProceededUMA, false, 1);
 
   // Check again: since the user previously cancelled, dialog is shown again.
-  GetManager()->CheckPrintingRestriction(web_contents.get(), cb.Get());
+  GetManager()->CheckPrintingRestriction(web_contents.get(), rfh_id, cb.Get());
   EXPECT_EQ(events_.size(), 2u);
   EXPECT_THAT(events_[1],
               IsDlpPolicyEvent(CreateDlpPolicyEvent(
@@ -757,7 +763,7 @@
   helper_.DestroyWebContents(web_contents.get());
   EXPECT_EQ(GetManager()->GetConfidentialRestrictions(web_contents.get()),
             kEmptyRestrictionSet);
-  GetManager()->CheckPrintingRestriction(web_contents.get(), cb.Get());
+  GetManager()->CheckPrintingRestriction(web_contents.get(), rfh_id, cb.Get());
   EXPECT_EQ(events_.size(), 2u);
   VerifyHistogramCounts(/*blocked_count=*/0, /*warned_count=*/2,
                         /*total_count=*/3,
diff --git a/chrome/browser/chromeos/extensions/file_manager/event_router.cc b/chrome/browser/chromeos/extensions/file_manager/event_router.cc
index 0512238..e4837c51 100644
--- a/chrome/browser/chromeos/extensions/file_manager/event_router.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/event_router.cc
@@ -31,6 +31,7 @@
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
 #include "chrome/browser/ash/arc/arc_util.h"
 #include "chrome/browser/ash/crostini/crostini_pref_names.h"
+#include "chrome/browser/ash/crostini/crostini_util.h"
 #include "chrome/browser/ash/drive/drive_integration_service.h"
 #include "chrome/browser/ash/drive/file_system_util.h"
 #include "chrome/browser/ash/file_manager/app_id.h"
diff --git a/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc b/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc
index cba9468..6f49bbe 100644
--- a/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc
+++ b/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc
@@ -366,6 +366,20 @@
       << message_;
 }
 
+IN_PROC_BROWSER_TEST_F(FileSystemProviderServiceWorkerApiTest, GetAll) {
+  ASSERT_TRUE(RunExtensionTest("file_system_provider/service_worker/get_all",
+                               {.extension_url = "test.html"},
+                               {.load_as_component = true}))
+      << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(FileSystemProviderServiceWorkerApiTest, ReadDirectory) {
+  ASSERT_TRUE(RunExtensionTest(
+      "file_system_provider/service_worker/read_directory",
+      {.extension_url = "test.html"}, {.load_as_component = true}))
+      << message_;
+}
+
 IN_PROC_BROWSER_TEST_F(FileSystemProviderServiceWorkerApiTest, ReadFile) {
   ASSERT_TRUE(RunExtensionTest("file_system_provider/service_worker/read_file",
                                {.extension_url = "test.html"},
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_content_manager.cc b/chrome/browser/chromeos/policy/dlp/dlp_content_manager.cc
index e1cce17..b376f915 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_content_manager.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_content_manager.cc
@@ -118,9 +118,10 @@
 
 void DlpContentManager::CheckPrintingRestriction(
     content::WebContents* web_contents,
+    content::GlobalRenderFrameHostId rfh_id,
     OnDlpRestrictionCheckedCallback callback) {
   const RestrictionLevelAndUrl restriction_info =
-      GetPrintingRestrictionInfo(web_contents);
+      GetPrintingRestrictionInfo(web_contents, rfh_id);
   MaybeReportEvent(restriction_info, DlpRulesManager::Restriction::kPrinting);
   DlpBooleanHistogram(dlp::kPrintingBlockedUMA, IsBlocked(restriction_info));
   DlpBooleanHistogram(dlp::kPrintingWarnedUMA, IsWarn(restriction_info));
@@ -547,11 +548,12 @@
 }
 
 RestrictionLevelAndUrl DlpContentManager::GetPrintingRestrictionInfo(
-    content::WebContents* web_contents) const {
+    content::WebContents* web_contents,
+    content::GlobalRenderFrameHostId rfh_id) const {
   // If we're viewing the PDF in a MimeHandlerViewGuest, use its embedded
   // WebContents.
   auto* guest_view =
-      extensions::MimeHandlerViewGuest::FromWebContents(web_contents);
+      extensions::MimeHandlerViewGuest::FromRenderFrameHostId(rfh_id);
   web_contents =
       guest_view ? guest_view->embedder_web_contents() : web_contents;
 
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_content_manager.h b/chrome/browser/chromeos/policy/dlp/dlp_content_manager.h
index ca4d9cd..332cb29 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_content_manager.h
+++ b/chrome/browser/chromeos/policy/dlp/dlp_content_manager.h
@@ -22,6 +22,7 @@
 #include "chrome/browser/ui/browser_list_observer.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "content/public/browser/desktop_media_id.h"
+#include "content/public/browser/global_routing_id.h"
 #include "content/public/browser/media_stream_request.h"
 #include "ui/views/widget/widget.h"
 #include "url/gurl.h"
@@ -65,6 +66,7 @@
   // Depending on the result, calls |callback| and passes an indicator whether
   // to proceed or not.
   void CheckPrintingRestriction(content::WebContents* web_contents,
+                                content::GlobalRenderFrameHostId rfh_id,
                                 OnDlpRestrictionCheckedCallback callback);
 
   // Returns whether screenshots should be restricted for extensions API.
@@ -305,7 +307,8 @@
   // Returns which level and url of printing restriction is currently enforced
   // for |web_contents|.
   RestrictionLevelAndUrl GetPrintingRestrictionInfo(
-      content::WebContents* web_contents) const;
+      content::WebContents* web_contents,
+      content::GlobalRenderFrameHostId rfh_id) const;
 
   // Returns confidential info for screen share of a single |web_contents|.
   ConfidentialContentsInfo GetScreenShareConfidentialContentsInfoForWebContents(
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_content_manager_browsertest.cc b/chrome/browser/chromeos/policy/dlp/dlp_content_manager_browsertest.cc
index 60c3799..4dbe0e3 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_content_manager_browsertest.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_content_manager_browsertest.cc
@@ -149,8 +149,9 @@
   base::MockCallback<OnDlpRestrictionCheckedCallback> cb;
   EXPECT_CALL(cb, Run(true)).Times(1);
 
-  helper_->GetContentManager()->CheckPrintingRestriction(web_contents,
-                                                         cb.Get());
+  helper_->GetContentManager()->CheckPrintingRestriction(
+      web_contents, web_contents->GetPrimaryMainFrame()->GetGlobalId(),
+      cb.Get());
 
   // Start printing and check that there is no notification when printing is not
   // restricted.
@@ -485,13 +486,15 @@
   EXPECT_CALL(cb, Run(true)).Times(1);
   EXPECT_CALL(cb, Run(false)).Times(1);
 
+  content::GlobalRenderFrameHostId rfh_id =
+      web_contents->GetPrimaryMainFrame()->GetGlobalId();
   // Printing should first be allowed.
-  helper_->GetContentManager()->CheckPrintingRestriction(web_contents,
+  helper_->GetContentManager()->CheckPrintingRestriction(web_contents, rfh_id,
                                                          cb.Get());
 
   // Set up printing restriction.
   helper_->ChangeConfidentiality(web_contents, kPrintRestricted);
-  helper_->GetContentManager()->CheckPrintingRestriction(web_contents,
+  helper_->GetContentManager()->CheckPrintingRestriction(web_contents, rfh_id,
                                                          cb.Get());
 
   // Setup the mock for the printing manager to invoke
@@ -533,8 +536,9 @@
   // CheckPrintingRestriction() directly or indirectly.
   base::MockCallback<OnDlpRestrictionCheckedCallback> cb;
   EXPECT_CALL(cb, Run(true)).Times(1);
-  helper_->GetContentManager()->CheckPrintingRestriction(web_contents,
-                                                         cb.Get());
+  helper_->GetContentManager()->CheckPrintingRestriction(
+      web_contents, web_contents->GetPrimaryMainFrame()->GetGlobalId(),
+      cb.Get());
 
   MockPrintManager* print_manager = GetPrintManager(web_contents);
   EXPECT_CALL(*print_manager, PrintPreviewAllowedForTesting).Times(1);
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 15df0a8..ebe2e58 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -2365,8 +2365,7 @@
 const char kConfirmationChipName[] = "Confirmation Chip Experiment";
 const char kConfirmationChipNameDescription[] =
     "Enables an experimental confirmation chip in the location bar after a "
-    "permission prompt shown with the chip UI has been decided by the user. "
-    "Requires #permission-chip to be enabled.";
+    "permission prompt shown has been decided by the user.";
 
 const char kPermissionChipGestureSensitiveName[] =
     "Gesture-sensitive Permissions Chip";
diff --git a/chrome/browser/mac/exception_processor_unittest.mm b/chrome/browser/mac/exception_processor_unittest.mm
index 2d64823..88cc552 100644
--- a/chrome/browser/mac/exception_processor_unittest.mm
+++ b/chrome/browser/mac/exception_processor_unittest.mm
@@ -210,8 +210,17 @@
   exit(1);
 }
 
+// Under LSAN this dies from leaking the run loop instead of how we expect it to
+// die, so the exit code is wrong.
+#if defined(LEAK_SANITIZER)
+#define MAYBE_ThrowExceptionInRunLoopWithoutProcessor \
+  DISABLED_ThrowExceptionInRunLoopWithoutProcessor
+#else
+#define MAYBE_ThrowExceptionInRunLoopWithoutProcessor \
+  ThrowExceptionInRunLoopWithoutProcessor
+#endif
 // Tests basic exception handling when the preprocessor is disabled.
-TEST(ExceptionProcessorTest, ThrowExceptionInRunLoopWithoutProcessor) {
+TEST(ExceptionProcessorTest, MAYBE_ThrowExceptionInRunLoopWithoutProcessor) {
   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
   EXPECT_EXIT(ThrowExceptionInRunLoopWithoutProcessor(),
               [](int exit_code) -> bool {
diff --git a/chrome/browser/printing/print_view_manager.cc b/chrome/browser/printing/print_view_manager.cc
index 75846d8..5d30286 100644
--- a/chrome/browser/printing/print_view_manager.cc
+++ b/chrome/browser/printing/print_view_manager.cc
@@ -231,14 +231,14 @@
   // `OnDlpPrintingRestrictionsChecked` as a wrapper callback to proceed with
   // scanning if needed afterwards.
   policy::DlpContentManager::Get()->CheckPrintingRestriction(
-      web_contents(),
+      web_contents(), rfh_id,
       base::BindOnce(&PrintViewManager::OnDlpPrintingRestrictionsChecked,
                      weak_factory_.GetWeakPtr(), rfh_id, std::move(callback)));
 #elif BUILDFLAG(IS_CHROMEOS)
   // Don't print DLP restricted content on Chrome OS, and use `callback`
   // directly since scanning isn't an option.
   policy::DlpContentManager::Get()->CheckPrintingRestriction(
-      web_contents(), std::move(callback));
+      web_contents(), rfh_id, std::move(callback));
 #elif BUILDFLAG(ENABLE_PRINT_CONTENT_ANALYSIS)
   RejectPrintPreviewRequestIfRestrictedByContentAnalysis(rfh_id,
                                                          std::move(callback));
diff --git a/chrome/browser/resources/new_tab_page/middle_slot_promo.ts b/chrome/browser/resources/new_tab_page/middle_slot_promo.ts
index 1b2a07f..007f73a 100644
--- a/chrome/browser/resources/new_tab_page/middle_slot_promo.ts
+++ b/chrome/browser/resources/new_tab_page/middle_slot_promo.ts
@@ -96,6 +96,7 @@
     if (image) {
       el = new CrAutoImgElement();
       el.autoSrc = image.imageUrl.url;
+      el.staticEncode = true;
       if (image.target) {
         const anchor = createAnchor(image.target);
         if (anchor) {
diff --git a/chrome/browser/ui/app_list/reorder/app_list_reorder_util.cc b/chrome/browser/ui/app_list/reorder/app_list_reorder_util.cc
index a9a40bf..4951e4a 100644
--- a/chrome/browser/ui/app_list/reorder/app_list_reorder_util.cc
+++ b/chrome/browser/ui/app_list/reorder/app_list_reorder_util.cc
@@ -11,7 +11,6 @@
 #include "third_party/skia/include/core/SkColorType.h"
 #include "third_party/skia/include/core/SkScalar.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/gfx/color_analysis.h"
 
 namespace app_list {
 namespace reorder {
diff --git a/chrome/browser/ui/app_list/search/files/file_search_provider.cc b/chrome/browser/ui/app_list/search/files/file_search_provider.cc
index 36e0814..6621058 100644
--- a/chrome/browser/ui/app_list/search/files/file_search_provider.cc
+++ b/chrome/browser/ui/app_list/search/files/file_search_provider.cc
@@ -6,21 +6,27 @@
 
 #include <cctype>
 #include <cmath>
+#include <utility>
 
+#include "ash/constants/ash_features.h"
+#include "ash/constants/ash_pref_names.h"
 #include "base/containers/fixed_flat_map.h"
 #include "base/files/file_enumerator.h"
 #include "base/i18n/case_conversion.h"
 #include "base/i18n/rtl.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/ranges/algorithm.h"
 #include "base/strings/strcat.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
 #include "base/time/time.h"
 #include "chrome/browser/ash/file_manager/path_util.h"
+#include "chrome/browser/ash/file_manager/trash_common_util.h"
 #include "chrome/browser/ash/input_method/diacritics_checker.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/search/files/file_result.h"
+#include "components/prefs/pref_service.h"
 
 namespace app_list {
 
@@ -89,7 +95,8 @@
 std::vector<FileSearchProvider::FileInfo> SearchFilesByPattern(
     const base::FilePath& root_path,
     const std::u16string& query,
-    const base::TimeTicks& query_start_time) {
+    const base::TimeTicks& query_start_time,
+    const std::vector<base::FilePath> trash_paths) {
   base::FileEnumerator enumerator(
       root_path,
       /*recursive=*/true,
@@ -101,6 +108,14 @@
   std::vector<FileSearchProvider::FileInfo> matched_paths;
   for (base::FilePath path = enumerator.Next(); !path.empty();
        path = enumerator.Next()) {
+    // Exclude any paths that are parented at an enabled trash location.
+    if (base::ranges::any_of(trash_paths,
+                             [&path](const base::FilePath& trash_path) {
+                               return trash_path.IsParent(path);
+                             })) {
+      continue;
+    }
+
     matched_paths.emplace_back(
         path, enumerator.GetInfo().IsDirectory(),
         base::Time::FromTimeT(enumerator.GetInfo().stat().st_atime));
@@ -116,6 +131,17 @@
   return matched_paths;
 }
 
+// Verify whether trash is enabled by feature flag and whether the enterprise
+// policy is not disabling the feature. This can dynamically disable the trash
+// functionality, so verify it every time.
+bool IsTrashEnabled(Profile* profile) {
+  if (!profile || !profile->GetPrefs()) {
+    return false;
+  }
+  return base::FeatureList::IsEnabled(chromeos::features::kFilesTrash) &&
+         profile->GetPrefs()->GetBoolean(ash::prefs::kFilesAppTrashEnabled);
+}
+
 }  // namespace
 
 FileSearchProvider::FileSearchProvider(Profile* profile)
@@ -144,10 +170,26 @@
   last_query_ = query;
   last_tokenized_query_.emplace(query, TokenizedString::Mode::kWords);
 
+  // Generate a vector of `base::FilePath`s that can be handed to the
+  // `SearchFilesByPattern`. Trash can be dynamically turned on/off via an
+  // enterprise policy, so this needs to be verified on search instead of
+  // precomputed.
+  if (trash_paths_.empty()) {
+    auto enabled_trash_locations =
+        file_manager::trash::GenerateEnabledTrashLocationsForProfile(
+            profile_, /*base_path=*/base::FilePath());
+    for (const auto& it : enabled_trash_locations) {
+      trash_paths_.emplace_back(
+          it.first.Append(it.second.relative_folder_path));
+    }
+  }
+
   base::ThreadPool::PostTaskAndReplyWithResult(
       FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING},
-      base::BindOnce(SearchFilesByPattern, root_path_, query,
-                     query_start_time_),
+      base::BindOnce(
+          SearchFilesByPattern, root_path_, query, query_start_time_,
+          (IsTrashEnabled(profile_) ? trash_paths_
+                                    : std::vector<base::FilePath>())),
       base::BindOnce(&FileSearchProvider::OnSearchComplete,
                      weak_factory_.GetWeakPtr()));
 }
diff --git a/chrome/browser/ui/app_list/search/files/file_search_provider.h b/chrome/browser/ui/app_list/search/files/file_search_provider.h
index 2b3b5bb8..62e62bb 100644
--- a/chrome/browser/ui/app_list/search/files/file_search_provider.h
+++ b/chrome/browser/ui/app_list/search/files/file_search_provider.h
@@ -66,6 +66,8 @@
   ash::ThumbnailLoader thumbnail_loader_;
   base::FilePath root_path_;
 
+  std::vector<base::FilePath> trash_paths_;
+
   SEQUENCE_CHECKER(sequence_checker_);
   base::WeakPtrFactory<FileSearchProvider> weak_factory_{this};
 };
diff --git a/chrome/browser/ui/app_list/search/files/file_search_provider_unittest.cc b/chrome/browser/ui/app_list/search/files/file_search_provider_unittest.cc
index ed8dd17f..265bfed 100644
--- a/chrome/browser/ui/app_list/search/files/file_search_provider_unittest.cc
+++ b/chrome/browser/ui/app_list/search/files/file_search_provider_unittest.cc
@@ -5,19 +5,26 @@
 #include "chrome/browser/ui/app_list/search/files/file_search_provider.h"
 #include <cctype>
 
+#include "ash/constants/ash_features.h"
+#include "ash/constants/ash_pref_names.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/test/test_app_list_color_provider.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/strings/strcat.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/task_environment.h"
 #include "base/time/time.h"
+#include "chrome/browser/ash/file_manager/path_util.h"
+#include "chrome/browser/ash/file_manager/trash_common_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/search/files/file_result.h"
 #include "chrome/browser/ui/app_list/search/test/test_search_controller.h"
 #include "chrome/test/base/testing_profile.h"
+#include "components/prefs/pref_service.h"
 #include "content/public/test/browser_task_environment.h"
+#include "storage/browser/file_system/external_mount_points.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -234,4 +241,67 @@
   EXPECT_LE(results[0]->relevance(), 1.0);
 }
 
+class FileSearchProviderTrashTest : public FileSearchProviderTest {
+ public:
+  FileSearchProviderTrashTest() {
+    std::vector<base::test::FeatureRef> enabled_features;
+    enabled_features.push_back(ash::features::kFilesTrash);
+    scoped_feature_list_.InitWithFeatures(enabled_features, {});
+  }
+
+  FileSearchProviderTrashTest(const FileSearchProviderTrashTest&) = delete;
+  FileSearchProviderTrashTest& operator=(const FileSearchProviderTrashTest&) =
+      delete;
+
+  void SetUp() override {
+    FileSearchProviderTest::SetUp();
+
+    // Ensure the My files and Downloads mount points are appropriately mocked
+    // to allow the trash locations to be parented at the test directory.
+    storage::ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
+        file_manager::util::GetDownloadsMountPointName(profile_.get()),
+        storage::kFileSystemTypeLocal, storage::FileSystemMountOption(),
+        scoped_temp_dir_.GetPath());
+
+    ToggleTrash(true);
+  }
+
+  void ToggleTrash(bool enabled) {
+    profile_->GetPrefs()->SetBoolean(ash::prefs::kFilesAppTrashEnabled,
+                                     enabled);
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+TEST_F(FileSearchProviderTrashTest, FilesInTrashAreIgnored) {
+  using file_manager::trash::kTrashFolderName;
+
+  CreateDirectory(kTrashFolderName);
+  WriteFile("file");
+  WriteFile(base::FilePath(kTrashFolderName).Append("trashed_file").value());
+
+  provider_->Start(u"file");
+  Wait();
+
+  EXPECT_THAT(LastResults(), UnorderedElementsAre(Title("file")));
+}
+
+TEST_F(FileSearchProviderTrashTest, FilesInTrashArentIgnoredIfTrashDisabled) {
+  using file_manager::trash::kTrashFolderName;
+
+  ToggleTrash(false);
+
+  CreateDirectory(kTrashFolderName);
+  WriteFile("file");
+  WriteFile(base::FilePath(kTrashFolderName).Append("trashed_file").value());
+
+  provider_->Start(u"file");
+  Wait();
+
+  EXPECT_THAT(LastResults(),
+              UnorderedElementsAre(Title("file"), Title("trashed_file")));
+}
+
 }  // namespace app_list
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 e69a09b..d0b794ee 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -591,6 +591,15 @@
   constexpr int kTextJogIndentDp = 11;
   int leading_edit_item_padding = should_indent ? kTextJogIndentDp : 0;
 
+  // Additionally, the text should be indented further if a chip is visible
+  // and the lock icon is hidden. This is treated separately, because the
+  // indentation constant has a distinct value.
+  if (chip_controller_ && chip_controller_->chip()->GetVisible() &&
+      ShouldChipOverrideLocationIcon()) {
+    constexpr int kTextIndentLocationBarIconOverriddenDp = 8;
+    leading_edit_item_padding += kTextIndentLocationBarIconOverriddenDp;
+  }
+
   // We always subtract the left padding of the OmniboxView itself to allow for
   // an extended I-beam click target without affecting actual layout.
   leading_edit_item_padding -= omnibox_view_->GetInsets().left();
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc
index 9e1b267..918a034 100644
--- a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc
+++ b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc
@@ -4548,5 +4548,133 @@
   helper_.InstallOmniboxIcon(InstallableSite::kScreenshots);
 }
 
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32StandaloneNotStartUrlWithShortcutWindowedWebShortcut_15Standalone_75StandaloneNotStartUrl_69StandaloneNotStartUrl_133StandaloneNotStartUrl) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kStandaloneNotStartUrl,
+                           ShortcutOptions::kWithShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebShortcut);
+  helper_.CheckAppNotInList(Site::kStandalone);
+  helper_.CheckAppInListIconCorrect(Site::kStandaloneNotStartUrl);
+  helper_.LaunchFromMenuOption(Site::kStandaloneNotStartUrl);
+  helper_.CheckAppNavigation(Site::kStandaloneNotStartUrl);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32StandaloneNotStartUrlWithShortcutWindowedWebShortcut_15Standalone_75StandaloneNotStartUrl_35StandaloneNotStartUrl_133StandaloneNotStartUrl) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kStandaloneNotStartUrl,
+                           ShortcutOptions::kWithShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebShortcut);
+  helper_.CheckAppNotInList(Site::kStandalone);
+  helper_.CheckAppInListIconCorrect(Site::kStandaloneNotStartUrl);
+  helper_.LaunchFromLaunchIcon(Site::kStandaloneNotStartUrl);
+  helper_.CheckAppNavigation(Site::kStandaloneNotStartUrl);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32StandaloneNotStartUrlWithShortcutWindowedWebShortcut_15Standalone_75StandaloneNotStartUrl_34StandaloneNotStartUrl_133StandaloneNotStartUrl) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kStandaloneNotStartUrl,
+                           ShortcutOptions::kWithShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebShortcut);
+  helper_.CheckAppNotInList(Site::kStandalone);
+  helper_.CheckAppInListIconCorrect(Site::kStandaloneNotStartUrl);
+  helper_.LaunchFromChromeApps(Site::kStandaloneNotStartUrl);
+  helper_.CheckAppNavigation(Site::kStandaloneNotStartUrl);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32StandaloneNotStartUrlWithShortcutWindowedWebApp_15StandaloneNotStartUrl_75Standalone_69Standalone_133Standalone) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kStandaloneNotStartUrl,
+                           ShortcutOptions::kWithShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckAppNotInList(Site::kStandaloneNotStartUrl);
+  helper_.CheckAppInListIconCorrect(Site::kStandalone);
+  helper_.LaunchFromMenuOption(Site::kStandalone);
+  helper_.CheckAppNavigation(Site::kStandalone);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32StandaloneNotStartUrlWithShortcutWindowedWebApp_15StandaloneNotStartUrl_75Standalone_35Standalone_133Standalone) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kStandaloneNotStartUrl,
+                           ShortcutOptions::kWithShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckAppNotInList(Site::kStandaloneNotStartUrl);
+  helper_.CheckAppInListIconCorrect(Site::kStandalone);
+  helper_.LaunchFromLaunchIcon(Site::kStandalone);
+  helper_.CheckAppNavigation(Site::kStandalone);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32StandaloneNotStartUrlWithShortcutWindowedWebApp_15StandaloneNotStartUrl_75Standalone_34Standalone_133Standalone) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kStandaloneNotStartUrl,
+                           ShortcutOptions::kWithShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckAppNotInList(Site::kStandaloneNotStartUrl);
+  helper_.CheckAppInListIconCorrect(Site::kStandalone);
+  helper_.LaunchFromChromeApps(Site::kStandalone);
+  helper_.CheckAppNavigation(Site::kStandalone);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32StandaloneNotStartUrlWithShortcutBrowserWebApp_15StandaloneNotStartUrl_75Standalone_34Standalone_134Standalone) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kStandaloneNotStartUrl,
+                           ShortcutOptions::kWithShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckAppNotInList(Site::kStandaloneNotStartUrl);
+  helper_.CheckAppInListIconCorrect(Site::kStandalone);
+  helper_.LaunchFromChromeApps(Site::kStandalone);
+  helper_.CheckBrowserNavigation(Site::kStandalone);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32StandaloneNotStartUrlWithShortcutBrowserWebShortcut_15Standalone_75StandaloneNotStartUrl_34StandaloneNotStartUrl_134StandaloneNotStartUrl) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kStandaloneNotStartUrl,
+                           ShortcutOptions::kWithShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebShortcut);
+  helper_.CheckAppNotInList(Site::kStandalone);
+  helper_.CheckAppInListIconCorrect(Site::kStandaloneNotStartUrl);
+  helper_.LaunchFromChromeApps(Site::kStandaloneNotStartUrl);
+  helper_.CheckBrowserNavigation(Site::kStandaloneNotStartUrl);
+}
+
 }  // namespace
 }  // namespace web_app::integration_tests
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac_win_linux.cc b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac_win_linux.cc
index 28ac9dc..9cce5423 100644
--- a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac_win_linux.cc
+++ b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac_win_linux.cc
@@ -2119,5 +2119,69 @@
   helper_.CheckWindowControlsOverlay(Site::kWco, IsOn::kOff);
 }
 
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32StandaloneNotStartUrlWithShortcutWindowedWebShortcut_15Standalone_75StandaloneNotStartUrl_1StandaloneNotStartUrl_133StandaloneNotStartUrl) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kStandaloneNotStartUrl,
+                           ShortcutOptions::kWithShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebShortcut);
+  helper_.CheckAppNotInList(Site::kStandalone);
+  helper_.CheckAppInListIconCorrect(Site::kStandaloneNotStartUrl);
+  helper_.LaunchFromPlatformShortcut(Site::kStandaloneNotStartUrl);
+  helper_.CheckAppNavigation(Site::kStandaloneNotStartUrl);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32StandaloneNotStartUrlWithShortcutWindowedWebApp_15StandaloneNotStartUrl_75Standalone_1Standalone_133Standalone) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kStandaloneNotStartUrl,
+                           ShortcutOptions::kWithShortcut,
+                           WindowOptions::kWindowed, InstallMode::kWebApp);
+  helper_.CheckAppNotInList(Site::kStandaloneNotStartUrl);
+  helper_.CheckAppInListIconCorrect(Site::kStandalone);
+  helper_.LaunchFromPlatformShortcut(Site::kStandalone);
+  helper_.CheckAppNavigation(Site::kStandalone);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32StandaloneNotStartUrlWithShortcutBrowserWebApp_15StandaloneNotStartUrl_75Standalone_1Standalone_134Standalone) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kStandaloneNotStartUrl,
+                           ShortcutOptions::kWithShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebApp);
+  helper_.CheckAppNotInList(Site::kStandaloneNotStartUrl);
+  helper_.CheckAppInListIconCorrect(Site::kStandalone);
+  helper_.LaunchFromPlatformShortcut(Site::kStandalone);
+  helper_.CheckBrowserNavigation(Site::kStandalone);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegration,
+    WAI_32StandaloneNotStartUrlWithShortcutBrowserWebShortcut_15Standalone_75StandaloneNotStartUrl_1StandaloneNotStartUrl_134StandaloneNotStartUrl) {
+  // Test contents are generated by script. Please do not modify!
+  // See `docs/webapps/why-is-this-test-failing.md` or
+  // `docs/webapps/integration-testing-framework` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyApp(Site::kStandaloneNotStartUrl,
+                           ShortcutOptions::kWithShortcut,
+                           WindowOptions::kBrowser, InstallMode::kWebShortcut);
+  helper_.CheckAppNotInList(Site::kStandalone);
+  helper_.CheckAppInListIconCorrect(Site::kStandaloneNotStartUrl);
+  helper_.LaunchFromPlatformShortcut(Site::kStandaloneNotStartUrl);
+  helper_.CheckBrowserNavigation(Site::kStandaloneNotStartUrl);
+}
+
 }  // namespace
 }  // namespace web_app::integration_tests
diff --git a/chrome/browser/ui/webui/sanitized_image_source.cc b/chrome/browser/ui/webui/sanitized_image_source.cc
index 52c152fb..6eb2b911 100644
--- a/chrome/browser/ui/webui/sanitized_image_source.cc
+++ b/chrome/browser/ui/webui/sanitized_image_source.cc
@@ -19,13 +19,13 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/common/webui_url_constants.h"
-#include "components/signin/public/identity_manager/access_token_info.h"
 #include "components/signin/public/identity_manager/primary_account_access_token_fetcher.h"
 #include "components/signin/public/identity_manager/scope_set.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/storage_partition.h"
 #include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/google_service_auth_error.h"
+#include "ipc/ipc_channel.h"
 #include "net/base/url_util.h"
 #include "net/http/http_response_headers.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
@@ -34,13 +34,22 @@
 #include "services/network/public/cpp/simple_url_loader.h"
 #include "services/network/public/mojom/url_response_head.mojom.h"
 #include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/encode/SkWebpEncoder.h"
 #include "ui/gfx/codec/png_codec.h"
+#include "ui/gfx/codec/webp_codec.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/image/image.h"
 #include "url/url_util.h"
 
 namespace {
 
+const int64_t kMaxImageSizeInBytes =
+    static_cast<int64_t>(IPC::Channel::kMaximumMessageSize);
+
+constexpr char kUrlKey[] = "url";
+constexpr char kStaticEncodeKey[] = "staticEncode";
+constexpr char kIsGooglePhotosKey[] = "isGooglePhotos";
+
 std::map<std::string, std::string> ParseParams(
     const std::string& param_string) {
   url::Component query(0, param_string.size());
@@ -77,19 +86,29 @@
 
 }  // namespace
 
+void SanitizedImageSource::DataDecoderDelegate::DecodeAnimation(
+    const std::string& data,
+    DecodeAnimationCallback callback) {
+  base::span<const uint8_t> bytes = base::make_span(
+      reinterpret_cast<const uint8_t*>(data.data()), data.size());
+
+  data_decoder::DecodeAnimation(&data_decoder_, bytes, /*shrink_to_fit=*/true,
+                                kMaxImageSizeInBytes, std::move(callback));
+}
+
 SanitizedImageSource::SanitizedImageSource(Profile* profile)
     : SanitizedImageSource(profile,
                            profile->GetDefaultStoragePartition()
                                ->GetURLLoaderFactoryForBrowserProcess(),
-                           std::make_unique<ImageDecoderImpl>()) {}
+                           std::make_unique<DataDecoderDelegate>()) {}
 
 SanitizedImageSource::SanitizedImageSource(
     Profile* profile,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-    std::unique_ptr<image_fetcher::ImageDecoder> image_decoder)
+    std::unique_ptr<DataDecoderDelegate> delegate)
     : identity_manager_(IdentityManagerFactory::GetForProfile(profile)),
       url_loader_factory_(url_loader_factory),
-      image_decoder_(std::move(image_decoder)) {}
+      data_decoder_delegate_(std::move(delegate)) {}
 
 SanitizedImageSource::~SanitizedImageSource() = default;
 
@@ -110,30 +129,36 @@
     return;
   }
 
+  RequestAttributes request_attributes;
   GURL image_url = GURL(image_url_or_params);
   bool send_auth_token = false;
   if (!image_url.is_valid()) {
     // Attempt to parse URL and additional options from params.
     auto params = ParseParams(image_url_or_params);
 
-    auto url_it = params.find("url");
+    auto url_it = params.find(kUrlKey);
     if (url_it == params.end()) {
       std::move(callback).Run(base::MakeRefCounted<base::RefCountedString>());
       return;
     }
     image_url = GURL(url_it->second);
 
-    auto google_photos_it = params.find("isGooglePhotos");
+    auto static_encode_it = params.find(kStaticEncodeKey);
+    if (static_encode_it != params.end()) {
+      request_attributes.static_encode = static_encode_it->second == "true";
+    }
+
+    auto google_photos_it = params.find(kIsGooglePhotosKey);
     if (google_photos_it != params.end() &&
         google_photos_it->second == "true" && IsGooglePhotosUrl(image_url)) {
       send_auth_token = true;
     }
   }
+  request_attributes.image_url = image_url;
 
   // Download the image body.
   if (!send_auth_token) {
-    StartImageDownload(std::move(image_url), std::move(callback),
-                       absl::nullopt);
+    StartImageDownload(std::move(request_attributes), std::move(callback));
     return;
   }
 
@@ -147,30 +172,37 @@
   fetcher_ptr->Start(base::BindOnce(
       [](const base::WeakPtr<SanitizedImageSource>& self,
          std::unique_ptr<signin::PrimaryAccountAccessTokenFetcher> fetcher,
-         GURL image_url, content::URLDataSource::GotDataCallback callback,
+         RequestAttributes request_attributes,
+         content::URLDataSource::GotDataCallback callback,
          GoogleServiceAuthError error,
          signin::AccessTokenInfo access_token_info) {
         if (error.state() != GoogleServiceAuthError::NONE) {
           LOG(ERROR) << "Failed to authenticate for Google Photos in order to "
                         "download "
-                     << image_url.spec()
+                     << request_attributes.image_url.spec()
                      << ". Error message: " << error.ToString();
           return;
         }
 
+        request_attributes.access_token_info = access_token_info;
+
         if (self) {
-          self->StartImageDownload(std::move(image_url), std::move(callback),
-                                   std::move(access_token_info));
+          self->StartImageDownload(std::move(request_attributes),
+                                   std::move(callback));
         }
       },
-      weak_ptr_factory_.GetWeakPtr(), std::move(fetcher), std::move(image_url),
-      std::move(callback)));
+      weak_ptr_factory_.GetWeakPtr(), std::move(fetcher),
+      std::move(request_attributes), std::move(callback)));
 }
 
+SanitizedImageSource::RequestAttributes::RequestAttributes() = default;
+SanitizedImageSource::RequestAttributes::RequestAttributes(
+    const RequestAttributes&) = default;
+SanitizedImageSource::RequestAttributes::~RequestAttributes() = default;
+
 void SanitizedImageSource::StartImageDownload(
-    GURL image_url,
-    content::URLDataSource::GotDataCallback callback,
-    absl::optional<signin::AccessTokenInfo> access_token_info) {
+    RequestAttributes request_attributes,
+    content::URLDataSource::GotDataCallback callback) {
   net::NetworkTrafficAnnotationTag traffic_annotation =
       net::DefineNetworkTrafficAnnotation("sanitized_image_source", R"(
         semantics {
@@ -194,11 +226,12 @@
             "disabling the requester WebUI."
         })");
   auto request = std::make_unique<network::ResourceRequest>();
-  request->url = image_url;
+  request->url = request_attributes.image_url;
   request->credentials_mode = network::mojom::CredentialsMode::kOmit;
-  if (access_token_info) {
-    request->headers.SetHeader(net::HttpRequestHeaders::kAuthorization,
-                               "Bearer " + access_token_info->token);
+  if (request_attributes.access_token_info) {
+    request->headers.SetHeader(
+        net::HttpRequestHeaders::kAuthorization,
+        "Bearer " + request_attributes.access_token_info->token);
   }
 
   auto loader =
@@ -208,7 +241,7 @@
       url_loader_factory_.get(),
       base::BindOnce(&SanitizedImageSource::OnImageLoaded,
                      weak_ptr_factory_.GetWeakPtr(), std::move(loader),
-                     std::move(callback)),
+                     std::move(request_attributes), std::move(callback)),
       network::SimpleURLLoader::kMaxBoundedStringDownloadSize);
 }
 
@@ -224,6 +257,7 @@
 
 void SanitizedImageSource::OnImageLoaded(
     std::unique_ptr<network::SimpleURLLoader> loader,
+    RequestAttributes request_attributes,
     content::URLDataSource::GotDataCallback callback,
     std::unique_ptr<std::string> body) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -233,20 +267,43 @@
     return;
   }
 
-  // Send image body to image decoder in isolated process.
-  image_decoder_->DecodeImage(
-      *body, gfx::Size() /* No particular size desired. */,
-      /*data_decoder=*/nullptr,
-      base::BindOnce(&SanitizedImageSource::OnImageDecoded,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+  data_decoder_delegate_->DecodeAnimation(
+      *body,
+      base::BindOnce(&SanitizedImageSource::OnAnimationDecoded,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     std::move(request_attributes), std::move(callback)));
 }
 
-void SanitizedImageSource::OnImageDecoded(
+void SanitizedImageSource::OnAnimationDecoded(
+    RequestAttributes request_attributes,
     content::URLDataSource::GotDataCallback callback,
-    const gfx::Image& image) {
+    std::vector<data_decoder::mojom::AnimationFramePtr> mojo_frames) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  // Re-encode vetted image as PNG and send to requester.
+  if (!mojo_frames.size()) {
+    std::move(callback).Run(base::MakeRefCounted<base::RefCountedString>());
+    return;
+  }
+
+#if BUILDFLAG(IS_CHROMEOS)
+  // Re-encode static image as PNG and send to requester.
+  if (request_attributes.static_encode || mojo_frames.size() == 1) {
+    EncodeAndReplyStaticImage(std::move(callback), mojo_frames[0]->bitmap);
+    return;
+  }
+
+  // The image is animated, re-encode as WebP animated image and send to
+  // requester.
+  EncodeAndReplyAnimatedImage(std::move(callback), std::move(mojo_frames));
+#else
+  // Re-encode as static image for non ChromeOS builds.
+  EncodeAndReplyStaticImage(std::move(callback), mojo_frames[0]->bitmap);
+#endif  // BUILDFLAG(IS_CHROMEOS)
+}
+
+void SanitizedImageSource::EncodeAndReplyStaticImage(
+    content::URLDataSource::GotDataCallback callback,
+    const SkBitmap& bitmap) {
   base::ThreadPool::PostTaskAndReplyWithResult(
       FROM_HERE,
       base::BindOnce(
@@ -257,6 +314,40 @@
                        ? encoded
                        : base::MakeRefCounted<base::RefCountedBytes>();
           },
-          image.AsBitmap()),
+          bitmap),
+      std::move(callback));
+  return;
+}
+
+void SanitizedImageSource::EncodeAndReplyAnimatedImage(
+    content::URLDataSource::GotDataCallback callback,
+    std::vector<data_decoder::mojom::AnimationFramePtr> mojo_frames) {
+  std::vector<gfx::WebpCodec::Frame> frames;
+  for (auto& mojo_frame : mojo_frames) {
+    gfx::WebpCodec::Frame frame;
+    frame.bitmap = mojo_frame->bitmap;
+    frame.duration = mojo_frame->duration.InMilliseconds();
+    frames.push_back(frame);
+  }
+
+  base::ThreadPool::PostTaskAndReplyWithResult(
+      FROM_HERE,
+      base::BindOnce(
+          [](const std::vector<gfx::WebpCodec::Frame>& frames) {
+            SkWebpEncoder::Options options;
+            options.fCompression = SkWebpEncoder::Compression::kLossless;
+            // Lower quality under kLosless compression means compress faster
+            // into larger files.
+            options.fQuality = 0;
+
+            auto encoded = gfx::WebpCodec::EncodeAnimated(frames, options);
+            if (encoded.has_value()) {
+              return base::MakeRefCounted<base::RefCountedBytes>(
+                  encoded.value());
+            }
+
+            return base::MakeRefCounted<base::RefCountedBytes>();
+          },
+          frames),
       std::move(callback));
 }
diff --git a/chrome/browser/ui/webui/sanitized_image_source.h b/chrome/browser/ui/webui/sanitized_image_source.h
index 731889d3..c35cb7a 100644
--- a/chrome/browser/ui/webui/sanitized_image_source.h
+++ b/chrome/browser/ui/webui/sanitized_image_source.h
@@ -10,17 +10,15 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
+#include "components/signin/public/identity_manager/access_token_info.h"
 #include "content/public/browser/url_data_source.h"
+#include "services/data_decoder/public/cpp/data_decoder.h"
+#include "services/data_decoder/public/cpp/decode_image.h"
+#include "services/data_decoder/public/mojom/image_decoder.mojom.h"
+#include "url/gurl.h"
 
 class Profile;
-
-namespace gfx {
-class Image;
-}  // namespace gfx
-
-namespace image_fetcher {
-class ImageDecoder;
-}  // namespace image_fetcher
+class SkBitmap;
 
 namespace network {
 class SharedURLLoaderFactory;
@@ -28,7 +26,6 @@
 }  // namespace network
 
 namespace signin {
-struct AccessTokenInfo;
 class IdentityManager;
 }  // namespace signin
 
@@ -36,24 +33,49 @@
 // WebUIs. For security reasons WebUIs are not allowed to download and decode
 // external images in their renderer process. The sanitized image source allows
 // external images in WebUIs by downloading the image in the browser process,
-// decoding the image in an isolated utility process, re-encoding the image as
-// PNG and sending the now sanitized image back to the requesting WebUI. You can
-// reach the image source via:
+// decoding the image in an isolated utility process, re-encoding the image and
+// sending the now sanitized image back to the requesting WebUI. You can reach
+// the image source via:
 //
 //   chrome://image?<external image URL>
 //
+// If the source is an animated image, it will be re-encoded as an animated
+// WebP image; otherwise it will be re-encoded as a static PNG image.
+// If static-encode attribute is set to true, it will always be re-encoded as
+// a static PNG image. See the example as follows:
+//   chrome://image?url=<external image URL>&staticEncode=true
+//
 // If the image source points to Google Photos storage, meaning it needs an auth
 // token to be downloaded, you can use the is-google-photos attribute as
 // follows:
 //   chrome://image?url=<external image URL>&isGooglePhotos=true
 class SanitizedImageSource : public content::URLDataSource {
  public:
+  using DecodeAnimationCallback =
+      data_decoder::mojom::ImageDecoder::DecodeAnimationCallback;
+
+  // A delegate class that is faked out for testing purposes.
+  class DataDecoderDelegate {
+   public:
+    DataDecoderDelegate() = default;
+    virtual ~DataDecoderDelegate() = default;
+
+    virtual void DecodeAnimation(const std::string& data,
+                                 DecodeAnimationCallback callback);
+
+   private:
+    // The instance of the Data Decoder used by this DataDecoderDelegate to
+    // perform any image decoding operations. The underlying service instance is
+    // started lazily when needed and torn down when not in use.
+    data_decoder::DataDecoder data_decoder_;
+  };
+
   explicit SanitizedImageSource(Profile* profile);
   // This constructor lets us pass mock dependencies for testing.
   SanitizedImageSource(
       Profile* profile,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-      std::unique_ptr<image_fetcher::ImageDecoder> image_decoder);
+      std::unique_ptr<DataDecoderDelegate> delegate);
   SanitizedImageSource(const SanitizedImageSource&) = delete;
   SanitizedImageSource& operator=(const SanitizedImageSource&) = delete;
   ~SanitizedImageSource() override;
@@ -73,22 +95,40 @@
   }
 
  private:
-  void StartImageDownload(
-      GURL image_url,
-      content::URLDataSource::GotDataCallback callback,
-      absl::optional<signin::AccessTokenInfo> access_token_info);
+  struct RequestAttributes {
+    RequestAttributes();
+    RequestAttributes(const RequestAttributes&);
+    ~RequestAttributes();
+
+    GURL image_url = GURL();
+    bool static_encode = false;
+    absl::optional<signin::AccessTokenInfo> access_token_info;
+  };
+
+  void StartImageDownload(RequestAttributes request_attributes,
+                          content::URLDataSource::GotDataCallback callback);
   void OnImageLoaded(std::unique_ptr<network::SimpleURLLoader> loader,
+                     RequestAttributes request_attributes,
                      content::URLDataSource::GotDataCallback callback,
                      std::unique_ptr<std::string> body);
-  void OnImageDecoded(content::URLDataSource::GotDataCallback callback,
-                      const gfx::Image& image);
+  void OnAnimationDecoded(
+      RequestAttributes request_attributes,
+      content::URLDataSource::GotDataCallback callback,
+      std::vector<data_decoder::mojom::AnimationFramePtr> mojo_frames);
+
+  void EncodeAndReplyStaticImage(
+      content::URLDataSource::GotDataCallback callback,
+      const SkBitmap& bitmap);
+  void EncodeAndReplyAnimatedImage(
+      content::URLDataSource::GotDataCallback callback,
+      std::vector<data_decoder::mojom::AnimationFramePtr> mojo_frames);
 
   // Owned by `IdentityManagerFactory` or `IdentityTestEnvironment`.
   raw_ptr<signin::IdentityManager> identity_manager_;
 
   const scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
 
-  std::unique_ptr<image_fetcher::ImageDecoder> image_decoder_;
+  std::unique_ptr<DataDecoderDelegate> data_decoder_delegate_;
 
   SEQUENCE_CHECKER(sequence_checker_);
   base::WeakPtrFactory<SanitizedImageSource> weak_ptr_factory_{this};
diff --git a/chrome/browser/ui/webui/sanitized_image_source_unittest.cc b/chrome/browser/ui/webui/sanitized_image_source_unittest.cc
index 98f40c4..eaecad3 100644
--- a/chrome/browser/ui/webui/sanitized_image_source_unittest.cc
+++ b/chrome/browser/ui/webui/sanitized_image_source_unittest.cc
@@ -10,7 +10,6 @@
 #include "base/test/mock_callback.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/test/base/testing_profile.h"
-#include "components/image_fetcher/core/image_decoder.h"
 #include "components/signin/public/identity_manager/identity_test_environment.h"
 #include "content/public/test/browser_task_environment.h"
 #include "net/http/http_status_code.h"
@@ -23,13 +22,21 @@
 #include "ui/gfx/image/image.h"
 #include "url/url_util.h"
 
+using data_decoder::mojom::AnimationFramePtr;
+
 namespace {
 
-gfx::Image MakeImage(SkColor color) {
+AnimationFramePtr MakeImageFrame(SkColor color) {
+  auto frame = data_decoder::mojom::AnimationFrame::New();
+
   SkBitmap bitmap;
   bitmap.allocN32Pixels(5, 5);
   bitmap.eraseColor(color);
-  return gfx::Image::CreateFrom1xBitmap(bitmap);
+
+  frame->bitmap = bitmap;
+  frame->duration = base::TimeDelta();
+
+  return frame;
 }
 
 }  // namespace
@@ -38,26 +45,25 @@
   return arg->Equals(other);
 }
 
-class MockImageDecoder : public image_fetcher::ImageDecoder {
+class MockDataDecoderDelegate
+    : public SanitizedImageSource::DataDecoderDelegate {
  public:
-  MOCK_METHOD4(DecodeImage,
-               void(const std::string&,
-                    const gfx::Size&,
-                    data_decoder::DataDecoder*,
-                    image_fetcher::ImageDecodedCallback));
+  MOCK_METHOD2(DecodeAnimation,
+               void(const std::string& data,
+                    SanitizedImageSource::DecodeAnimationCallback callback));
 };
 
 class SanitizedImageSourceTest : public testing::Test {
  public:
   void SetUp() override {
     profile_ = std::make_unique<TestingProfile>();
-    auto image_decoder = std::make_unique<MockImageDecoder>();
-    mock_image_decoder_ = image_decoder.get();
+    auto data_decoder_delegate = std::make_unique<MockDataDecoderDelegate>();
+    mock_data_decoder_delegate_ = data_decoder_delegate.get();
     sanitized_image_source_ = std::make_unique<SanitizedImageSource>(
         profile_.get(),
         base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
             &test_url_loader_factory_),
-        std::move(image_decoder));
+        std::move(data_decoder_delegate));
   }
 
   void TearDown() override {
@@ -70,7 +76,7 @@
   content::BrowserTaskEnvironment task_environment_;
   std::unique_ptr<TestingProfile> profile_;
   network::TestURLLoaderFactory test_url_loader_factory_;
-  raw_ptr<MockImageDecoder> mock_image_decoder_;
+  raw_ptr<MockDataDecoderDelegate> mock_data_decoder_delegate_;
   std::unique_ptr<SanitizedImageSource> sanitized_image_source_;
 };
 
@@ -88,16 +94,17 @@
     std::string url;
     std::string body;
     std::tie(color, url, body) = datum;
-    EXPECT_CALL(*mock_image_decoder_,
-                DecodeImage(body, gfx::Size(), nullptr, testing::_))
+    EXPECT_CALL(*mock_data_decoder_delegate_, DecodeAnimation(body, testing::_))
         .Times(1)
-        .WillOnce([color](const std::string&, const gfx::Size&,
-                          data_decoder::DataDecoder*,
-                          image_fetcher::ImageDecodedCallback callback) {
-          std::move(callback).Run(MakeImage(color));
-        });
-    EXPECT_CALL(callback, Run(MemoryEq(MakeImage(color).As1xPNGBytes())))
-        .Times(1);
+        .WillOnce(
+            [color](const std::string&,
+                    SanitizedImageSource::DecodeAnimationCallback callback) {
+              std::vector<AnimationFramePtr> frames;
+              frames.push_back(MakeImageFrame(color));
+              std::move(callback).Run(std::move(frames));
+            });
+    auto image = gfx::Image::CreateFrom1xBitmap(MakeImageFrame(color)->bitmap);
+    EXPECT_CALL(callback, Run(MemoryEq(image.As1xPNGBytes()))).Times(1);
   }
 
   // Issue requests.
@@ -133,8 +140,8 @@
 
   // Set up expectations and mock data.
   test_url_loader_factory_.AddResponse(kImageUrl, "", net::HTTP_NOT_FOUND);
-  EXPECT_CALL(*mock_image_decoder_,
-              DecodeImage(testing::_, testing::_, testing::_, testing::_))
+  EXPECT_CALL(*mock_data_decoder_delegate_,
+              DecodeAnimation(testing::_, testing::_))
       .Times(0);
   base::MockCallback<content::URLDataSource::GotDataCallback> callback;
   EXPECT_CALL(callback,
@@ -151,8 +158,8 @@
 // Verifies that the image source ignores requests with a wrong URL.
 TEST_F(SanitizedImageSourceTest, WrongUrl) {
   // Set up expectations and mock data.
-  EXPECT_CALL(*mock_image_decoder_,
-              DecodeImage(testing::_, testing::_, testing::_, testing::_))
+  EXPECT_CALL(*mock_data_decoder_delegate_,
+              DecodeAnimation(testing::_, testing::_))
       .Times(0);
   base::MockCallback<content::URLDataSource::GotDataCallback> callback;
   EXPECT_CALL(callback,
@@ -265,3 +272,123 @@
       test_url_loader_factory_.GetPendingRequest(4)->request.headers.HasHeader(
           net::HttpRequestHeaders::kAuthorization));
 }
+
+TEST_F(SanitizedImageSourceTest, StaticImage) {
+  const std::string test_body = "abc";
+  const std::string test_url = "https://foo.com/img.png";
+
+  // Set up expectations and mock data.
+  base::MockCallback<content::URLDataSource::GotDataCallback> callback;
+  EXPECT_CALL(*mock_data_decoder_delegate_,
+              DecodeAnimation(test_body, testing::_))
+      .Times(1)
+      .WillOnce([](const std::string&,
+                   SanitizedImageSource::DecodeAnimationCallback callback) {
+        std::vector<AnimationFramePtr> frames;
+        frames.push_back(MakeImageFrame(SK_ColorRED));
+        std::move(callback).Run(std::move(frames));
+      });
+  auto image =
+      gfx::Image::CreateFrom1xBitmap(MakeImageFrame(SK_ColorRED)->bitmap);
+  EXPECT_CALL(callback, Run(MemoryEq(image.As1xPNGBytes()))).Times(1);
+
+  // Issue requests.
+  sanitized_image_source_->StartDataRequest(
+      GURL(base::StrCat({chrome::kChromeUIImageURL, "?", test_url})),
+      content::WebContents::Getter(), callback.Get());
+
+  // Answer requests and check correctness.
+  auto* request = test_url_loader_factory_.GetPendingRequest(0);
+  EXPECT_EQ(network::mojom::CredentialsMode::kOmit,
+            request->request.credentials_mode);
+  EXPECT_EQ(test_url, request->request.url);
+  test_url_loader_factory_.SimulateResponseWithoutRemovingFromPendingList(
+      request, test_body);
+
+  task_environment_.RunUntilIdle();
+}
+
+#if BUILDFLAG(IS_CHROMEOS)
+TEST_F(SanitizedImageSourceTest, AnimatedImage) {
+  const std::string test_body = "abc";
+  const std::string test_url = "https://foo.com/img.png";
+
+  // Set up expectations and mock data.
+  base::MockCallback<content::URLDataSource::GotDataCallback> callback;
+  EXPECT_CALL(*mock_data_decoder_delegate_,
+              DecodeAnimation(test_body, testing::_))
+      .Times(1)
+      .WillOnce([](const std::string&,
+                   SanitizedImageSource::DecodeAnimationCallback callback) {
+        std::vector<AnimationFramePtr> frames;
+        frames.push_back(MakeImageFrame(SK_ColorRED));
+        frames.push_back(MakeImageFrame(SK_ColorBLUE));
+        frames.push_back(MakeImageFrame(SK_ColorGREEN));
+        std::move(callback).Run(std::move(frames));
+      });
+  auto image =
+      gfx::Image::CreateFrom1xBitmap(MakeImageFrame(SK_ColorRED)->bitmap);
+  EXPECT_CALL(callback, Run(testing::_))
+      .Times(1)
+      .WillOnce([](scoped_refptr<base::RefCountedMemory> bytes) {
+        std::string data_string(reinterpret_cast<char const*>(bytes->data()));
+        // Make sure the image is encoded into WebP format.
+        EXPECT_TRUE(base::StartsWith(data_string, "RIFF"));
+      });
+
+  // Issue requests.
+  sanitized_image_source_->StartDataRequest(
+      GURL(base::StrCat({chrome::kChromeUIImageURL, "?", test_url})),
+      content::WebContents::Getter(), callback.Get());
+
+  // Answer requests and check correctness.
+  auto* request = test_url_loader_factory_.GetPendingRequest(0);
+  EXPECT_EQ(network::mojom::CredentialsMode::kOmit,
+            request->request.credentials_mode);
+  EXPECT_EQ(test_url, request->request.url);
+  test_url_loader_factory_.SimulateResponseWithoutRemovingFromPendingList(
+      request, test_body);
+
+  task_environment_.RunUntilIdle();
+}
+
+TEST_F(SanitizedImageSourceTest, AnimatedImageWithStaticEncode) {
+  const std::string test_body = "abc";
+  const std::string test_url = "https://foo.com/img.png";
+
+  // Set up expectations and mock data.
+  base::MockCallback<content::URLDataSource::GotDataCallback> callback;
+  EXPECT_CALL(*mock_data_decoder_delegate_,
+              DecodeAnimation(test_body, testing::_))
+      .Times(1)
+      .WillOnce([](const std::string&,
+                   SanitizedImageSource::DecodeAnimationCallback callback) {
+        std::vector<AnimationFramePtr> frames;
+        frames.push_back(MakeImageFrame(SK_ColorRED));
+        frames.push_back(MakeImageFrame(SK_ColorBLUE));
+        frames.push_back(MakeImageFrame(SK_ColorGREEN));
+        std::move(callback).Run(std::move(frames));
+      });
+  auto image =
+      gfx::Image::CreateFrom1xBitmap(MakeImageFrame(SK_ColorRED)->bitmap);
+  // Make sure the image is encoded into static PNG bytes.
+  EXPECT_CALL(callback, Run(MemoryEq(image.As1xPNGBytes()))).Times(1);
+
+  // Issue requests.
+  sanitized_image_source_->StartDataRequest(
+      GURL(base::StrCat({chrome::kChromeUIImageURL, "?url=", test_url,
+                         "&staticEncode=true"})),
+      content::WebContents::Getter(), callback.Get());
+
+  // Answer requests and check correctness.
+  auto* request = test_url_loader_factory_.GetPendingRequest(0);
+  EXPECT_EQ(network::mojom::CredentialsMode::kOmit,
+            request->request.credentials_mode);
+  EXPECT_EQ(test_url, request->request.url);
+  test_url_loader_factory_.SimulateResponseWithoutRemovingFromPendingList(
+      request, test_body);
+
+  task_environment_.RunUntilIdle();
+}
+
+#endif  // BUILDFLAG(IS_CHROMEOS)
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler.cc b/chrome/browser/ui/webui/settings/site_settings_handler.cc
index 7392090..98354ba 100644
--- a/chrome/browser/ui/webui/settings/site_settings_handler.cc
+++ b/chrome/browser/ui/webui/settings/site_settings_handler.cc
@@ -47,6 +47,7 @@
 #include "chrome/browser/ui/webui/settings/site_settings_helper.h"
 #include "chrome/browser/usb/usb_chooser_context.h"
 #include "chrome/browser/usb/usb_chooser_context_factory.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
@@ -584,14 +585,18 @@
   // more than 3. Otherwise, the notification permission should not be added
   // to review list.
   double score = service->GetScore(url);
+  int low_engagement_notification_limit =
+      features::kSafetyCheckNotificationPermissionsLowEnagementLimit.Get();
   bool is_low_engagement =
       !site_engagement::SiteEngagementService::IsEngagementAtLeast(
           score, blink::mojom::EngagementLevel::MEDIUM) &&
-      notification_count > 3;
+      notification_count > low_engagement_notification_limit;
+  int min_engagement_notification_limit =
+      features::kSafetyCheckNotificationPermissionsMinEnagementLimit.Get();
   bool is_minimal_engagement =
       !site_engagement::SiteEngagementService::IsEngagementAtLeast(
           score, blink::mojom::EngagementLevel::LOW) &&
-      notification_count > 0;
+      notification_count > min_engagement_notification_limit;
 
   return is_minimal_engagement || is_low_engagement;
 }
diff --git a/chrome/browser/ui/webui/settings/site_settings_helper.cc b/chrome/browser/ui/webui/settings/site_settings_helper.cc
index 815e205..4dedb1f 100644
--- a/chrome/browser/ui/webui/settings/site_settings_helper.cc
+++ b/chrome/browser/ui/webui/settings/site_settings_helper.cc
@@ -760,6 +760,7 @@
     ContentSettingsType content_type) {
   ContentSettingsForOneType entries;
   map->GetSettingsForOneType(content_type, &entries);
+  // Exclude any entries that don't represent a single webby top-frame origin.
   base::EraseIf(entries, [](const ContentSettingPatternSource& e) {
     return !content_settings::PatternAppliesToSingleOrigin(
                e.primary_pattern, e.secondary_pattern) ||
diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc
index 68ad8997..2f7e68c 100644
--- a/chrome/browser/web_applications/web_app.cc
+++ b/chrome/browser/web_applications/web_app.cc
@@ -783,11 +783,7 @@
       base::Value& allowlist_json = *json_decl.SetKey(
           "allowed_origins", base::Value(base::Value::Type::LIST));
       for (const auto& origin_with_possible_wildcards : decl.allowed_origins) {
-        // TODO(crbug.com/1345994): Support wildcard matching.
-        if (!origin_with_possible_wildcards.has_subdomain_wildcard) {
-          allowlist_json.Append(
-              origin_with_possible_wildcards.origin.Serialize());
-        }
+        allowlist_json.Append(origin_with_possible_wildcards.Serialize());
       }
       json_decl.SetBoolKey("matches_all_origins", decl.matches_all_origins);
       json_decl.SetBoolKey("matches_opaque_src", decl.matches_opaque_src);
diff --git a/chrome/browser/web_applications/web_app_database.cc b/chrome/browser/web_applications/web_app_database.cc
index 4df77e3..48892b76 100644
--- a/chrome/browser/web_applications/web_app_database.cc
+++ b/chrome/browser/web_applications/web_app_database.cc
@@ -694,11 +694,8 @@
       const std::string feature_string(feature_name->second);
       proto_policy.set_feature(feature_string);
       for (const auto& origin_with_possible_wildcards : decl.allowed_origins) {
-        // TODO(crbug.com/1345994): Support wildcard matching.
-        if (!origin_with_possible_wildcards.has_subdomain_wildcard) {
-          proto_policy.add_allowed_origins(
-              origin_with_possible_wildcards.origin.Serialize());
-        }
+        proto_policy.add_allowed_origins(
+            origin_with_possible_wildcards.Serialize());
       }
       proto_policy.set_matches_all_origins(decl.matches_all_origins);
       proto_policy.set_matches_opaque_src(decl.matches_opaque_src);
@@ -1320,8 +1317,9 @@
       decl.feature = feature_enum->second;
 
       for (const std::string& origin : decl_proto.allowed_origins()) {
-        decl.allowed_origins.emplace_back(url::Origin::Create(GURL(origin)),
-                                          /*has_subdomain_wildcard=*/false);
+        decl.allowed_origins.emplace_back(
+            blink::OriginWithPossibleWildcards::Parse(
+                origin, blink::OriginWithPossibleWildcards::NodeType::kHeader));
       }
       decl.matches_all_origins = decl_proto.matches_all_origins();
       decl.matches_opaque_src = decl_proto.matches_opaque_src();
diff --git a/chrome/browser/web_applications/web_app_database_unittest.cc b/chrome/browser/web_applications/web_app_database_unittest.cc
index 5d70a74..4b7ffcd 100644
--- a/chrome/browser/web_applications/web_app_database_unittest.cc
+++ b/chrome/browser/web_applications/web_app_database_unittest.cc
@@ -40,6 +40,9 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/abseil-cpp/absl/types/variant.h"
+#include "third_party/blink/public/common/permissions_policy/origin_with_possible_wildcards.h"
+#include "third_party/blink/public/common/permissions_policy/permissions_policy_declaration.h"
+#include "third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom.h"
 #include "url/gurl.h"
 #include "url/origin.h"
 
@@ -590,7 +593,7 @@
             LaunchHandlerProto_ClientMode_FOCUS_EXISTING);
 }
 
-class WebAppDatabaseIsolationDataTest : public ::testing::Test {
+class WebAppDatabaseProtoDataTest : public ::testing::Test {
  public:
   std::unique_ptr<WebApp> CreateMinimalWebApp() {
     GURL start_url{"https://example.com/"};
@@ -602,19 +605,27 @@
     return web_app;
   }
 
-  std::unique_ptr<WebApp> CreateIsolatedWebApp(IsolationData isolation_data) {
+  std::unique_ptr<WebApp> CreateIsolatedWebApp(
+      const IsolationData& isolation_data) {
     std::unique_ptr<WebApp> web_app = CreateMinimalWebApp();
     web_app->SetIsolationData(isolation_data);
     return web_app;
   }
 
+  std::unique_ptr<WebApp> CreateWebAppWithPermissionsPolicy(
+      const blink::ParsedPermissionsPolicy& permissions_policy) {
+    std::unique_ptr<WebApp> web_app = CreateMinimalWebApp();
+    web_app->SetPermissionsPolicy(permissions_policy);
+    return web_app;
+  }
+
   std::unique_ptr<WebApp> ToAndFromProto(const WebApp& web_app) {
     return WebAppDatabase::CreateWebApp(
         *WebAppDatabase::CreateWebAppProto(web_app));
   }
 };
 
-TEST_F(WebAppDatabaseIsolationDataTest, DoesNotSetIsolationDataIfNotIsolated) {
+TEST_F(WebAppDatabaseProtoDataTest, DoesNotSetIsolationDataIfNotIsolated) {
   std::unique_ptr<WebApp> web_app = CreateMinimalWebApp();
 
   std::unique_ptr<WebApp> protoed_web_app = ToAndFromProto(*web_app);
@@ -624,7 +635,7 @@
                              absl::nullopt)));
 }
 
-TEST_F(WebAppDatabaseIsolationDataTest, SavesInstalledBundleIsolationData) {
+TEST_F(WebAppDatabaseProtoDataTest, SavesInstalledBundleIsolationData) {
   base::FilePath path(FILE_PATH_LITERAL("bundle_path"));
   std::unique_ptr<WebApp> web_app = CreateIsolatedWebApp(
       IsolationData(IsolationData::InstalledBundle{.path = path}));
@@ -636,7 +647,7 @@
                   "path", &IsolationData::InstalledBundle::path, Eq(path))));
 }
 
-TEST_F(WebAppDatabaseIsolationDataTest,
+TEST_F(WebAppDatabaseProtoDataTest,
        HandlesCorruptedInstalledBundleIsolationData) {
   base::FilePath path(FILE_PATH_LITERAL("bundle_path"));
   std::unique_ptr<WebApp> web_app = CreateIsolatedWebApp(
@@ -658,7 +669,7 @@
   EXPECT_THAT(protoed_web_app, IsNull());
 }
 
-TEST_F(WebAppDatabaseIsolationDataTest, SavesDevModeBundleIsolationData) {
+TEST_F(WebAppDatabaseProtoDataTest, SavesDevModeBundleIsolationData) {
   base::FilePath path(FILE_PATH_LITERAL("dev_bundle_path"));
   std::unique_ptr<WebApp> web_app = CreateIsolatedWebApp(
       IsolationData(IsolationData::DevModeBundle{.path = path}));
@@ -670,7 +681,7 @@
                   "path", &IsolationData::DevModeBundle::path, Eq(path))));
 }
 
-TEST_F(WebAppDatabaseIsolationDataTest,
+TEST_F(WebAppDatabaseProtoDataTest,
        HandlesCorruptedDevModeBundleIsolationData) {
   base::FilePath path(FILE_PATH_LITERAL("bundle_path"));
   std::unique_ptr<WebApp> web_app = CreateIsolatedWebApp(
@@ -692,7 +703,7 @@
   EXPECT_THAT(protoed_web_app, IsNull());
 }
 
-TEST_F(WebAppDatabaseIsolationDataTest, SavesDevModeProxyIsolationData) {
+TEST_F(WebAppDatabaseProtoDataTest, SavesDevModeProxyIsolationData) {
   std::unique_ptr<WebApp> web_app = CreateIsolatedWebApp(
       IsolationData(IsolationData::DevModeProxy{.proxy_url = "proxy"}));
 
@@ -704,4 +715,75 @@
           "proxy_url", &IsolationData::DevModeProxy::proxy_url, Eq("proxy"))));
 }
 
+TEST_F(WebAppDatabaseProtoDataTest, PermissionsPolicyRoundTrip) {
+  const blink::ParsedPermissionsPolicy policy = {
+      {blink::mojom::PermissionsPolicyFeature::kGyroscope,
+       {},
+       /*matches_all_origins=*/false,
+       /*matches_opaque_src=*/true},
+      {blink::mojom::PermissionsPolicyFeature::kGeolocation,
+       {},
+       /*matches_all_origins=*/true,
+       /*matches_opaque_src=*/false},
+      {blink::mojom::PermissionsPolicyFeature::kGamepad,
+       {{url::Origin::Create(GURL("https://example.com")),
+         /*has_subdomain_wildcard=*/false},
+        {url::Origin::Create(GURL("https://example.net")),
+         /*has_subdomain_wildcard=*/true},
+        {url::Origin::Create(GURL("https://*.example.net")),
+         /*has_subdomain_wildcard=*/false}},
+       /*matches_all_origins=*/false,
+       /*matches_opaque_src=*/false},
+  };
+  std::unique_ptr<WebApp> web_app = CreateWebAppWithPermissionsPolicy(policy);
+
+  std::unique_ptr<WebApp> protoed_web_app = ToAndFromProto(*web_app);
+  EXPECT_THAT(*web_app, Eq(*protoed_web_app));
+  EXPECT_EQ(policy, protoed_web_app->permissions_policy());
+}
+
+TEST_F(WebAppDatabaseProtoDataTest, PermissionsPolicyProto) {
+  const blink::ParsedPermissionsPolicy policy = {
+      {blink::mojom::PermissionsPolicyFeature::kGyroscope,
+       {},
+       /*matches_all_origins=*/false,
+       /*matches_opaque_src=*/true},
+      {blink::mojom::PermissionsPolicyFeature::kGeolocation,
+       {},
+       /*matches_all_origins=*/true,
+       /*matches_opaque_src=*/false},
+      {blink::mojom::PermissionsPolicyFeature::kGamepad,
+       {{url::Origin::Create(GURL("https://example.com")),
+         /*has_subdomain_wildcard=*/false},
+        {url::Origin::Create(GURL("https://example.net")),
+         /*has_subdomain_wildcard=*/true},
+        {url::Origin::Create(GURL("https://*.example.net")),
+         /*has_subdomain_wildcard=*/false}},
+       /*matches_all_origins=*/false,
+       /*matches_opaque_src=*/false},
+  };
+  std::unique_ptr<WebApp> web_app = CreateWebAppWithPermissionsPolicy(policy);
+
+  std::unique_ptr<WebAppProto> proto =
+      WebAppDatabase::CreateWebAppProto(*web_app);
+  ASSERT_EQ(proto->permissions_policy().size(), 3);
+  EXPECT_EQ(proto->permissions_policy().at(0).feature(), "gyroscope");
+  EXPECT_EQ(proto->permissions_policy().at(0).allowed_origins_size(), 0);
+  EXPECT_EQ(proto->permissions_policy().at(0).matches_all_origins(), false);
+  EXPECT_EQ(proto->permissions_policy().at(0).matches_opaque_src(), true);
+  EXPECT_EQ(proto->permissions_policy().at(1).feature(), "geolocation");
+  EXPECT_EQ(proto->permissions_policy().at(1).allowed_origins_size(), 0);
+  EXPECT_EQ(proto->permissions_policy().at(1).matches_all_origins(), true);
+  EXPECT_EQ(proto->permissions_policy().at(1).matches_opaque_src(), false);
+  EXPECT_EQ(proto->permissions_policy().at(2).feature(), "gamepad");
+  ASSERT_EQ(proto->permissions_policy().at(2).allowed_origins_size(), 3);
+  EXPECT_EQ(proto->permissions_policy().at(2).allowed_origins(0),
+            "https://example.com");
+  EXPECT_EQ(proto->permissions_policy().at(2).allowed_origins(1),
+            "https://*.example.net");
+  EXPECT_EQ(proto->permissions_policy().at(2).allowed_origins(2),
+            "https://%2A.example.net");
+  EXPECT_EQ(proto->permissions_policy().at(2).matches_all_origins(), false);
+  EXPECT_EQ(proto->permissions_policy().at(2).matches_opaque_src(), false);
+}
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_unittest.cc b/chrome/browser/web_applications/web_app_unittest.cc
index c4f8918..774c15d3 100644
--- a/chrome/browser/web_applications/web_app_unittest.cc
+++ b/chrome/browser/web_applications/web_app_unittest.cc
@@ -25,7 +25,11 @@
 #include "chrome/browser/web_applications/web_app_utils.h"
 #include "chrome/common/chrome_paths.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/permissions_policy/origin_with_possible_wildcards.h"
+#include "third_party/blink/public/common/permissions_policy/permissions_policy_declaration.h"
+#include "third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom.h"
 #include "url/gurl.h"
+#include "url/origin.h"
 
 namespace web_app {
 
@@ -333,4 +337,57 @@
   EXPECT_EQ(*debug_isolation_data, expected_isolation_data);
 }
 
+TEST(WebAppTest, PermissionsPolicyDebugValue) {
+  WebApp app{GenerateAppId(/*manifest_id=*/absl::nullopt,
+                           GURL("https://example.com"))};
+  app.SetPermissionsPolicy({
+      {blink::mojom::PermissionsPolicyFeature::kGyroscope,
+       {},
+       /*matches_all_origins=*/false,
+       /*matches_opaque_src=*/true},
+      {blink::mojom::PermissionsPolicyFeature::kGeolocation,
+       {},
+       /*matches_all_origins=*/true,
+       /*matches_opaque_src=*/false},
+      {blink::mojom::PermissionsPolicyFeature::kGamepad,
+       {{url::Origin::Create(GURL("https://example.com")),
+         /*has_subdomain_wildcard=*/false},
+        {url::Origin::Create(GURL("https://example.net")),
+         /*has_subdomain_wildcard=*/true},
+        {url::Origin::Create(GURL("https://*.example.net")),
+         /*has_subdomain_wildcard=*/false}},
+       /*matches_all_origins=*/false,
+       /*matches_opaque_src=*/false},
+  });
+
+  EXPECT_TRUE(!app.permissions_policy().empty());
+
+  base::Value expected_permissions_policy = base::JSONReader::Read(R"([
+        {
+          "allowed_origins": [  ],
+          "feature": "gyroscope",
+          "matches_all_origins": false,
+          "matches_opaque_src": true
+        }
+        , {
+          "allowed_origins": [  ],
+          "feature": "geolocation",
+          "matches_all_origins": true,
+          "matches_opaque_src": false
+        }
+        , {
+          "allowed_origins": [ "https://example.com", "https://*.example.net", "https://%2A.example.net" ],
+          "feature": "gamepad",
+          "matches_all_origins": false,
+          "matches_opaque_src": false
+        }
+      ])")
+                                                .value();
+
+  base::Value::Dict debug_app = app.AsDebugValue().GetDict().Clone();
+  base::Value::List* debug_permissions_policy =
+      debug_app.FindList("permissions_policy");
+  EXPECT_TRUE(debug_permissions_policy != nullptr);
+  EXPECT_EQ(*debug_permissions_policy, expected_permissions_policy);
+}
 }  // namespace web_app
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 26cb875..4c12c22 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1665359392-180123bdd1fedc45c1cbb781e2ad04bd98ab1546.profdata
+chrome-linux-main-1665381181-6c04357dc0107d559222bffd4a36ab2d7530ada7.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 1e2580d..bea4014 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1665359392-4a14ed054564e68f8953428d778ac749731d7712.profdata
+chrome-mac-main-1665381181-223e920cb0c878e32ef46fe4d4ce698272f4cd08.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index a68632b..aa47bcb2 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1665359392-9eee08f4c226c39fc910d8b503467505816c42d3.profdata
+chrome-win32-main-1665381181-b87eb3c35687591c4118434d3cb69a8319af5596.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index cd90720..d6c56d2a 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1665369929-a0e6e9828f70f683f8f1df95373b77667afe0494.profdata
+chrome-win64-main-1665391197-fdf024cfd15aa7581b9d75533f809e47b8504782.profdata
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 566f5b46..171cfe4 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -981,6 +981,15 @@
              "SafetyCheckNotificationPermissions",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+const base::FeatureParam<int>
+    kSafetyCheckNotificationPermissionsMinEnagementLimit{
+        &kSafetyCheckNotificationPermissions,
+        "min-engagement-notification-count", 0};
+const base::FeatureParam<int>
+    kSafetyCheckNotificationPermissionsLowEnagementLimit{
+        &kSafetyCheckNotificationPermissions,
+        "low-engagement-notification-count", 4};
+
 // Enables unused site permission module in Safety Check.
 BASE_FEATURE(kSafetyCheckUnusedSitePermissions,
              "SafetyCheckUnusedSitePermissions",
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 7fd4befb..dd401a53b 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -566,6 +566,12 @@
 #if !BUILDFLAG(IS_ANDROID)
 COMPONENT_EXPORT(CHROME_FEATURES)
 BASE_DECLARE_FEATURE(kSafetyCheckNotificationPermissions);
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::FeatureParam<int>
+    kSafetyCheckNotificationPermissionsMinEnagementLimit;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::FeatureParam<int>
+    kSafetyCheckNotificationPermissionsLowEnagementLimit;
 
 COMPONENT_EXPORT(CHROME_FEATURES)
 BASE_DECLARE_FEATURE(kSafetyCheckUnusedSitePermissions);
diff --git a/chrome/common/extensions/api/file_manager_private.idl b/chrome/common/extensions/api/file_manager_private.idl
index fa0bf1b..39a42ebe 100644
--- a/chrome/common/extensions/api/file_manager_private.idl
+++ b/chrome/common/extensions/api/file_manager_private.idl
@@ -548,7 +548,7 @@
   boolean? isArbitrarySyncFolder;
 
   // Sync status for files tracked by different cloud filesystem providers.
-  SyncStatus? sync_status;
+  SyncStatus? syncStatus;
 };
 
 // Information about total and remaining size on the mount point.
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/BUILD.gn b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/BUILD.gn
index 576a25e..825db6b 100644
--- a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/BUILD.gn
+++ b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/BUILD.gn
@@ -20,8 +20,12 @@
     "copy_entry/test.js",
     "delete_entry/sw.js",
     "delete_entry/test.js",
+    "get_all/sw.js",
+    "get_all/test.js",
     "helpers.js",
     "provider.js",
+    "read_directory/sw.js",
+    "read_directory/test.js",
     "read_file/sw.js",
     "read_file/test.js",
     "write_file/sw.js",
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/delete_entry/test.js b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/delete_entry/test.js
index dd5308dd..00228b2a 100644
--- a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/delete_entry/test.js
+++ b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/delete_entry/test.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {mountTestFileSystem} from '/_test_resources/api_test/file_system_provider/service_worker/helpers.js';
+import {mountTestFileSystem, remoteProvider} from '/_test_resources/api_test/file_system_provider/service_worker/helpers.js';
 // For shared constants.
 import {TestFileSystemProvider} from '/_test_resources/api_test/file_system_provider/service_worker/provider.js';
 
@@ -11,15 +11,46 @@
 
   const fileSystem = await mountTestFileSystem();
 
+  const TEST_DIR = 'non-empty-directory';
+  const TEST_FILE = 'file-delete.txt';
+
+  await remoteProvider.addFiles({
+    // Non-empty directory (can only be deleted recursively).
+    [`/${TEST_DIR}`]: {
+      metadata: {
+        isDirectory: true,
+        name: TEST_DIR,
+        modificationTime: new Date(2014, 4, 28, 10, 39, 15),
+      },
+    },
+    [`/${TEST_DIR}/readme.txt`]: {
+      metadata: {
+        isDirectory: false,
+        name: TEST_FILE,
+        modificationTime: new Date(2014, 4, 28, 10, 39, 15),
+        size: 0,
+      },
+      contents: '',
+    },
+    [`/${TEST_FILE}`]: {
+      metadata: {
+        isDirectory: false,
+        name: TEST_FILE,
+        modificationTime: new Date(2014, 4, 28, 10, 39, 15),
+        size: 0,
+      },
+      contents: '',
+    },
+  });
+
   chrome.test.runTests([
     // Delete a file. Should succeed.
-    async function deleteDirectorySuccessSimple() {
+    async function deleteFileSuccessSimple() {
       try {
-        const entry =
-            await fileSystem.getFileEntry(TestFileSystemProvider.FILE_DELETE, {
-              create: false,
-            });
-        chrome.test.assertEq(TestFileSystemProvider.FILE_DELETE, entry.name);
+        const entry = await fileSystem.getFileEntry(TEST_FILE, {
+          create: false,
+        });
+        chrome.test.assertEq(TEST_FILE, entry.name);
         chrome.test.assertFalse(entry.isDirectory);
         await new Promise((resolve, reject) => entry.remove(resolve, reject));
         chrome.test.succeed();
@@ -30,10 +61,9 @@
     // Delete a directory which has contents, non-recursively. Should fail.
     async function deleteDirectoryErrorNotEmpty() {
       try {
-        const entry = await fileSystem.getDirectoryEntry(
-            TestFileSystemProvider.TEST_DIR_DELETE_NONEMPTY, {create: false});
-        chrome.test.assertEq(
-            TestFileSystemProvider.TEST_DIR_DELETE_NONEMPTY, entry.name);
+        const entry =
+            await fileSystem.getDirectoryEntry(TEST_DIR, {create: false});
+        chrome.test.assertEq(TEST_DIR, entry.name);
         chrome.test.assertTrue(entry.isDirectory);
         try {
           await new Promise((resolve, reject) => entry.remove(resolve, reject));
@@ -50,10 +80,9 @@
     // Delete a directory which has contents, recursively. Should succeed.
     async function deleteDirectoryRecursively() {
       try {
-        const entry = await fileSystem.getDirectoryEntry(
-            TestFileSystemProvider.TEST_DIR_DELETE_NONEMPTY, {create: false});
-        chrome.test.assertEq(
-            TestFileSystemProvider.TEST_DIR_DELETE_NONEMPTY, entry.name);
+        const entry =
+            await fileSystem.getDirectoryEntry(TEST_DIR, {create: false});
+        chrome.test.assertEq(TEST_DIR, entry.name);
         chrome.test.assertTrue(entry.isDirectory);
         await new Promise(
             (resolve, reject) => entry.removeRecursively(resolve, reject));
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/get_all/manifest.json b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/get_all/manifest.json
new file mode 100644
index 0000000..0e559a9
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/get_all/manifest.json
@@ -0,0 +1,22 @@
+{
+  // chrome-extension://pkplfbidichfdicaijlchgnapepdginl
+  "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtDfX9dHNh948bt00YhZBm3P6E5QLaOt+v8kXVtibQfiPtOD2FTScB/f0wX/EQWVO7BkaSOsRkTPcPIgocyMPYr2FLgqGLFlYT9nQpKJZUFNF5oJ5rG6Nv7ppf4zEB3j6da1IBRTz2yOZ+6O1TMZxol/V62/QcqrJeggsHTEPGLdr9Ua4b1Ka0xKJnJngZljsbw93FI1o+P9dAh5BS6wTPiZI/vmJVjvMTkSTnaZ3n9Go2t7A0XLcSxLcVyuLAd2mAvSN0mIviOukdM66wr7llif71nKuUt+4qvlr/r9HfwzN6pA4jkwhtS1UD+3CmB+wsHwsnohNcuu4FIQ6rgq/7QIDAQAB",
+  "name": "chrome.fileSystemProvider.getAll",
+  "version": "0.1",
+  "manifest_version": 3,
+  "description": "Test for chrome.fileSystemProvider.getAll() in service workers.",
+  "permissions": [
+    "fileSystemProvider",
+    {
+      "fileSystem": ["requestFileSystem", "write"]
+    },
+    "fileManagerPrivate"
+  ],
+  "file_system_provider_capabilities": {
+    "source": "device"
+  },
+  "background": {
+    "service_worker": "sw.js",
+    "type": "module"
+  }
+}
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/get_all/sw.js b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/get_all/sw.js
new file mode 100644
index 0000000..ac074135
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/get_all/sw.js
@@ -0,0 +1,7 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {serviceWorkerMain} from '/_test_resources/api_test/file_system_provider/service_worker/provider.js';
+
+serviceWorkerMain(self);
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/get_all/test.html b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/get_all/test.html
new file mode 100644
index 0000000..9980fda0
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/get_all/test.html
@@ -0,0 +1 @@
+<script type="module" src="test.js"></script>
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/get_all/test.js b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/get_all/test.js
new file mode 100644
index 0000000..70aee353
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/get_all/test.js
@@ -0,0 +1,135 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {mountTestFileSystem, openFile, remoteProvider, startReadTextFromFile} from '/_test_resources/api_test/file_system_provider/service_worker/helpers.js';
+// For shared constants.
+import {TestFileSystemProvider} from '/_test_resources/api_test/file_system_provider/service_worker/provider.js';
+
+// Wrappers for chrome.fileSystemProvider.* are still needed for Closure to
+// work, as it's not aware they are returning promises if callbacks are omitted.
+
+/**
+ * @returns {!Promise<!Array<!chrome.fileSystemProvider.FileSystemInfo>>}
+ * @suppress {checkTypes}
+ */
+async function getAllFsInfos() {
+  return chrome.fileSystemProvider.getAll();
+}
+
+/**
+ * @param {string} fileSystemId
+ * @returns {!Promise<!chrome.fileSystemProvider.FileSystemInfo>}
+ * @suppress {checkTypes}
+ */
+async function getFsInfoById(fileSystemId) {
+  return chrome.fileSystemProvider.get(fileSystemId);
+}
+
+/**
+ * @param {string} fileSystemId
+ * @returns {!Promise<void>}
+ * @suppress {checkTypes}
+ */
+async function unmount(fileSystemId) {
+  return chrome.fileSystemProvider.unmount({fileSystemId});
+}
+
+async function main() {
+  await navigator.serviceWorker.ready;
+
+  chrome.test.runTests([
+    // Verifies if getAll() returns the mounted file system.
+    async function mountSuccess() {
+      try {
+        const fileSystem = await mountTestFileSystem(/*openedFileLimit*/ 2);
+        // Start a read so we have at least one file open.
+        const fileEntry = await fileSystem.getFileEntry(
+            TestFileSystemProvider.FILE_BLOCKS_FOREVER, {create: false});
+        const file = await openFile(fileEntry);
+        startReadTextFromFile(file);
+        await remoteProvider.waitForEvent('onOpenFileRequested');
+
+        const fsInfos = await getAllFsInfos();
+        chrome.test.assertEq(1, fsInfos.length);
+        chrome.test.assertEq(
+            TestFileSystemProvider.FILESYSTEM_ID, fsInfos[0].fileSystemId);
+        chrome.test.assertEq('Test Filesystem', fsInfos[0].displayName);
+        chrome.test.assertTrue(fsInfos[0].writable);
+        chrome.test.assertEq(2, fsInfos[0].openedFilesLimit);
+        chrome.test.assertEq(1, fsInfos[0].openedFiles.length);
+        chrome.test.assertEq(
+            `/${TestFileSystemProvider.FILE_BLOCKS_FOREVER}`,
+            fsInfos[0].openedFiles[0].filePath);
+        chrome.test.assertEq(
+            chrome.fileSystemProvider.OpenFileMode.READ,
+            fsInfos[0].openedFiles[0].mode);
+
+        const fsInfo =
+            await getFsInfoById(TestFileSystemProvider.FILESYSTEM_ID);
+        chrome.test.assertEq(
+            TestFileSystemProvider.FILESYSTEM_ID, fsInfo.fileSystemId);
+        chrome.test.assertEq('Test Filesystem', fsInfo.displayName);
+        chrome.test.assertTrue(fsInfo.writable);
+        chrome.test.assertEq(2, fsInfo.openedFilesLimit);
+        chrome.test.assertEq(1, fsInfo.openedFiles.length);
+        chrome.test.assertEq(
+            `/${TestFileSystemProvider.FILE_BLOCKS_FOREVER}`,
+            fsInfo.openedFiles[0].filePath);
+        chrome.test.assertEq(
+            chrome.fileSystemProvider.OpenFileMode.READ,
+            fsInfo.openedFiles[0].mode);
+
+        chrome.test.succeed();
+      } catch (e) {
+        chrome.test.fail(e);
+      }
+    },
+
+    // Verifies that after unmounting, the file system is not available in
+    // getAll() list.
+    async function unmountSuccess() {
+      try {
+        await unmount(TestFileSystemProvider.FILESYSTEM_ID);
+
+        chrome.test.assertEq([], await getAllFsInfos());
+        try {
+          await getFsInfoById(TestFileSystemProvider.FILESYSTEM_ID);
+          chrome.test.fail('Found the filesystem that was unmounted.');
+        } catch (e) {
+          chrome.test.assertEq('NOT_FOUND', e.message);
+          chrome.test.succeed();
+        }
+      } catch (e) {
+        chrome.test.fail(e);
+      }
+    },
+
+    // Verifies that if mounting fails, then the file system is not added to the
+    // getAll() list.
+    async function mountError() {
+      try {
+        try {
+          /** @suppress {checkTypes} */
+          await chrome.fileSystemProvider.mount(
+              {fileSystemId: '', displayName: ''});
+          chrome.test.fail('Mount operation should have failed.');
+        } catch (e) {
+          chrome.test.assertEq('INVALID_OPERATION', e.message);
+        }
+        chrome.test.assertEq([], await getAllFsInfos());
+        try {
+          await getFsInfoById(TestFileSystemProvider.FILESYSTEM_ID);
+          chrome.test.fail('Found the filesystem that was unmounted.');
+        } catch (e) {
+          chrome.test.assertEq('NOT_FOUND', e.message);
+        }
+        chrome.test.succeed();
+      } catch (e) {
+        chrome.test.fail(e);
+      }
+    },
+  ]);
+}
+
+main();
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/helpers.js b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/helpers.js
index 61e8a2b..c664461 100644
--- a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/helpers.js
+++ b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/helpers.js
@@ -71,6 +71,38 @@
   return fileSystem;
 };
 
+/**
+ * @param {!FileEntry} fileEntry
+ * @returns {!Promise<!File>}
+ */
+export async function openFile(fileEntry) {
+  return new Promise((resolve, reject) => fileEntry.file(resolve, reject));
+}
+
+/**
+ * @param {!File} file
+ * @returns {!Promise<string>}
+ */
+export async function readTextFromFile(file) {
+  const {promise} = startReadTextFromFile(file);
+  return promise;
+}
+
+/**
+ * @param {!File} file
+ * @returns {{promise: !Promise<string>, reader: !FileReader}}
+ */
+export function startReadTextFromFile(file) {
+  const reader = new FileReader();
+  const promise = new Promise((resolve, reject) => {
+    reader.onload = e => resolve(reader.result);
+    reader.onerror = e => reject(reader.error);
+    reader.onabort = e => reject(reader.error);
+    reader.readAsText(file);
+  });
+  return {reader, promise};
+}
+
 export class MountedTestFileSystem {
   /** @param {!FileSystem} fileSystem */
   constructor(fileSystem) {
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/provider.js b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/provider.js
index 2d57511..f4019d2 100644
--- a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/provider.js
+++ b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/provider.js
@@ -44,6 +44,69 @@
   }
 };
 
+/**
+ * Splits the path into dir name and base name, e.g. '/a/b/c' -> '/a/b', 'c'.
+ *
+ * @param {string} pathString
+ * @returns {{dirPath: string, fileName:string}}
+ */
+function splitPath(pathString) {
+  const path = pathString.split('/');
+  const fileName = path.pop();
+  return {dirPath: path.join('/'), fileName};
+}
+
+class Entry {
+  /**
+   * @param {{
+   *  name: string,
+   *  isDirectory: boolean,
+   *  size: (number|undefined),
+   *  modificationTime: !Date
+   * }} metadata
+   * @param {?string} contents
+   * @param {Array<!Entry>} children
+   */
+  constructor(metadata, contents, children) {
+    this.metadata = metadata;
+    this.contents = contents;
+    /** @type {!Object<string, !Entry>} */
+    this.children =
+        Object.fromEntries((children || []).map(e => [e.metadata.name, e]));
+  }
+
+  /**
+   * @param {string} name
+   * @param {!Date} modificationTime
+   * @param {string} contents
+   */
+  static file(name, modificationTime, contents) {
+    return new Entry(
+        {
+          name,
+          isDirectory: false,
+          size: contents.length,
+          modificationTime,
+        },
+        contents, null);
+  }
+
+  /**
+   * @param {string} name
+   * @param {!Date} modificationTime
+   * @param {!Array<!Entry>} children
+   */
+  static dir(name, modificationTime, children) {
+    return new Entry(
+        {
+          name,
+          isDirectory: true,
+          modificationTime,
+        },
+        null, children);
+  }
+};
+
 export class TestFileSystemProvider {
   constructor(fileSystemId) {
     this.fileSystemId = fileSystemId;
@@ -51,84 +114,34 @@
      * Filesystem contents (data and metadata). The key is a full path, and the
      * value is an object containing metadata and file contents.
      *
-     * @private {!Object<string, !Object>}
+     * @private {!Entry}
      */
-    this.files = {
-      '/': {
-        metadata: {
-          isDirectory: true,
-          name: '',
-          size: 0,
-          modificationTime: new Date(2014, 4, 28, 10, 39, 15)
-        },
-      },
-      ['/' + TestFileSystemProvider.TEST_DIR_DELETE_NONEMPTY]: {
-        metadata: {
-          isDirectory: true,
-          name: TestFileSystemProvider.TEST_DIR_DELETE_NONEMPTY,
-          size: 0,
-          modificationTime: new Date(2014, 4, 28, 10, 39, 15),
-        },
-      },
-      ['/' + TestFileSystemProvider.FILE_DELETE]: {
-        metadata: {
-          isDirectory: false,
-          name: TestFileSystemProvider.FILE_DELETE,
-          size: 0,
-          modificationTime: new Date(2014, 4, 28, 10, 39, 15),
-        },
-      },
+    this.root = Entry.dir('', new Date(2014, 4, 28, 10, 39, 15), [
       // Read error
-      ['/' + TestFileSystemProvider.FILE_FAIL]: {
-        metadata: {
-          isDirectory: false,
-          name: TestFileSystemProvider.FILE_FAIL,
-          size: TestFileSystemProvider.INITIAL_TEXT.length,
-          modificationTime: new Date(2014, 1, 25, 7, 36, 12),
-        },
-        contents: TestFileSystemProvider.INITIAL_TEXT,
-      },
+      Entry.file(
+          TestFileSystemProvider.FILE_FAIL, new Date(2014, 1, 25, 7, 36, 12),
+          TestFileSystemProvider.INITIAL_TEXT),
       // Read and write blocks indefinitely.
-      ['/' + TestFileSystemProvider.FILE_BLOCKS_FOREVER]: {
-        metadata: {
-          isDirectory: false,
-          name: TestFileSystemProvider.FILE_BLOCKS_FOREVER,
-          size: TestFileSystemProvider.INITIAL_TEXT.length,
-          modificationTime: new Date(2014, 1, 26, 8, 37, 13),
-        },
-        contents: TestFileSystemProvider.INITIAL_TEXT,
-      },
+      Entry.file(
+          TestFileSystemProvider.FILE_BLOCKS_FOREVER,
+          new Date(2014, 1, 26, 8, 37, 13),
+          TestFileSystemProvider.INITIAL_TEXT),
       // Open blocks until unblocked manually.
-      ['/' + TestFileSystemProvider.FILE_STALL_OPEN]: {
-        metadata: {
-          isDirectory: false,
-          name: TestFileSystemProvider.FILE_STALL_OPEN,
-          size: TestFileSystemProvider.INITIAL_TEXT.length,
-          modificationTime: new Date(2014, 1, 26, 8, 37, 13),
-        },
-        contents: TestFileSystemProvider.INITIAL_TEXT,
-      },
+      Entry.file(
+          TestFileSystemProvider.FILE_STALL_OPEN,
+          new Date(2014, 1, 26, 8, 37, 13),
+          TestFileSystemProvider.INITIAL_TEXT),
       // Read blocks until unblocked manually.
-      ['/' + TestFileSystemProvider.FILE_STALL_READ]: {
-        metadata: {
-          isDirectory: false,
-          name: TestFileSystemProvider.FILE_STALL_READ,
-          size: TestFileSystemProvider.INITIAL_TEXT.length,
-          modificationTime: new Date(2014, 1, 26, 8, 37, 13),
-        },
-        contents: TestFileSystemProvider.INITIAL_TEXT,
-      },
+      Entry.file(
+          TestFileSystemProvider.FILE_STALL_READ,
+          new Date(2014, 1, 26, 8, 37, 13),
+          TestFileSystemProvider.INITIAL_TEXT),
       // Read returns data in chunks.
-      ['/' + TestFileSystemProvider.FILE_READ_SUCCESS]: {
-        metadata: {
-          isDirectory: false,
-          name: TestFileSystemProvider.FILE_READ_SUCCESS,
-          size: TestFileSystemProvider.INITIAL_TEXT.length,
-          modificationTime: new Date(2014, 1, 25, 7, 36, 12)
-        },
-        contents: TestFileSystemProvider.INITIAL_TEXT,
-      },
-    };
+      Entry.file(
+          TestFileSystemProvider.FILE_READ_SUCCESS,
+          new Date(2014, 1, 25, 7, 36, 12),
+          TestFileSystemProvider.INITIAL_TEXT),
+    ]);
 
     /**
      * Map of opened files, from a `openRequestId` to `filePath`.
@@ -178,6 +191,7 @@
     this.setHandlerEnabled('onDeleteEntryRequested', true);
     this.setHandlerEnabled('onGetMetadataRequested', true);
     this.setHandlerEnabled('onOpenFileRequested', true);
+    this.setHandlerEnabled('onReadDirectoryRequested', true);
     this.setHandlerEnabled('onReadFileRequested', true);
     this.setHandlerEnabled('onRemoveWatcherRequested', true);
     this.setHandlerEnabled('onWriteFileRequested', true);
@@ -229,24 +243,29 @@
 
   /**
    * Called by the test. Add files to the provider's filesystem.
-   * @param {!Object<string, !Object>} files
+   *
+   * @param {!Object<string, !Entry>} files a map of paths to entries.
    */
   addFiles(files) {
-    // Restore Date objects after receiving data via postMessage.
-    for (const file of Object.values(files)) {
+    for (const path of Object.keys(files)) {
+      const file = files[path];
+      const {dirPath} = splitPath(path);
+      // Restore Date objects after receiving data via postMessage.
       file.metadata.modificationTime = new Date(file.metadata.modificationTime);
+      const entry = new Entry(file.metadata, file.contents, null);
+      this.findEntryByPath(dirPath).children[entry.metadata.name] = entry;
     }
-    this.files = {...this.files, ...files};
   }
 
   /**
    * Called by the test. Gets contents of a given file.
    *
    * @param {string} filePath
-   * @returns The current text contents of the file.
+   * @returns {string|null} The current text contents of the file.
    */
   getFileContents(filePath) {
-    return this.files[filePath].contents;
+    const entry = this.findEntryByPath(filePath);
+    return entry ? entry.contents : null;
   }
 
   /**
@@ -325,6 +344,32 @@
     this.stalledRequests = {};
   }
 
+  /**
+   * Finds a file or directory entry by path.
+   *
+   * @param {string} pathString
+   * @returns {?Entry}
+   */
+  findEntryByPath(pathString) {
+    let path = pathString.split('/');
+    if (path[0] != '') {
+      // Must start with "/"
+      return null;
+    }
+    path = path.slice(1);
+
+    let entry = this.root;
+    for (const fileName of path) {
+      const child = entry.children[fileName];
+      if (child) {
+        entry = child;
+      } else {
+        return null;
+      }
+    }
+    return entry;
+  }
+
   onAbortRequested(options, onSuccess, onError) {
     this.recordEvent('onAbortRequested', options);
     if (options.fileSystemId !== this.fileSystemId) {
@@ -349,7 +394,7 @@
       return;
     }
 
-    if (options.entryPath in this.files) {
+    if (this.findEntryByPath(options.entryPath)) {
       onSuccess();
       return;
     }
@@ -357,7 +402,6 @@
     onError(chrome.fileSystemProvider.ProviderError.NOT_FOUND);
   };
 
-
   /**
    * FSP: implementation for the file close request event. The file,
    * previously opened with <code>openRequestId</code> will be closed.
@@ -401,22 +445,23 @@
       return;
     }
 
-    if (!(options.sourcePath in this.files)) {
+    const source = this.findEntryByPath(options.sourcePath);
+    if (!source) {
       onError(chrome.fileSystemProvider.ProviderError.NOT_FOUND);
       return;
     }
 
-    if (options.targetPath in this.files) {
+    if (this.findEntryByPath(options.targetPath)) {
       onError(chrome.fileSystemProvider.ProviderError.EXISTS);
       return;
     }
 
     // Copy the metadata, but change the 'name' field.
-    const source = this.files[options.sourcePath];
     /** @suppress {undefinedVars} */
     const dest = structuredClone(source);
-    dest.name = options.targetPath.split('/').pop();
-    this.files[options.targetPath] = dest;
+    const {dirPath, fileName} = splitPath(options.targetPath);
+    dest.name = fileName;
+    this.findEntryByPath(dirPath).children[dest.name] = dest;
 
     onSuccess();
   }
@@ -441,21 +486,19 @@
       return;
     }
 
-    if (options.filePath in this.files) {
+    if (this.findEntryByPath(options.filePath)) {
       onError(chrome.fileSystemProvider.ProviderError.EXISTS);
       return;
     }
 
-    this.files[options.filePath] = {
-      metadata: {
-        isDirectory: false,
-        name: options.filePath.split('/').pop(),
-        size: 0,
-        modificationTime: new Date()
-      },
-      contents: '',
-    };
+    const {dirPath, fileName} = splitPath(options.filePath);
+    const dir = this.findEntryByPath(dirPath);
+    if (!dir) {
+      onError(chrome.fileSystemProvider.ProviderError.NOT_FOUND);
+      return;
+    }
 
+    dir.children[fileName] = Entry.file(fileName, new Date(), '');
     onSuccess();
   };
 
@@ -475,12 +518,13 @@
       return;
     }
 
-    if (!(options.entryPath in this.files)) {
+    const entry = this.findEntryByPath(options.entryPath);
+    if (!entry) {
       onError(chrome.fileSystemProvider.ProviderError.NOT_FOUND);
       return;
     }
 
-    onSuccess(this.files[options.entryPath].metadata);
+    onSuccess(entry.metadata);
   };
 
   /**
@@ -501,8 +545,8 @@
       return;
     }
 
-    const metadata = this.files[options.filePath].metadata;
-    if (!metadata || metadata.is_directory) {
+    const entry = this.findEntryByPath(options.filePath);
+    if (!entry || entry.metadata.isDirectory) {
       onError(chrome.fileSystemProvider.ProviderError.NOT_FOUND);
       return;
     }
@@ -520,6 +564,38 @@
   };
 
   /**
+   * Returns entries in the requested directory.
+   *
+   * @param {!chrome.fileSystemProvider.ReadDirectoryRequestedOptions} options
+   *     Options.
+   * @param {function(Array<Object>, boolean)} onSuccess Success callback with
+   *     a list of entries. May be called multiple times.
+   * @param {function(chrome.fileSystemProvider.ProviderError)} onError Error
+   *     callback with an error code.
+   */
+  onReadDirectoryRequested(options, onSuccess, onError) {
+    if (options.fileSystemId !== this.fileSystemId) {
+      onError(chrome.fileSystemProvider.ProviderError.SECURITY);
+      return;
+    }
+
+    const entry = this.findEntryByPath(options.directoryPath);
+    if (!entry.metadata.isDirectory) {
+      onError(chrome.fileSystemProvider.ProviderError.NOT_FOUND);
+      return;
+    }
+
+    const children = Object.values(entry.children);
+    // Send one-by-one to have multiple result callbacks.
+    for (let i = 0; i < children.length; i++) {
+      onSuccess(
+          [children[i].metadata],
+          /*hasMore=*/ i < children.length - 1);
+    }
+  }
+
+
+  /**
    * FSP: requests reading contents of a file, previously opened with <code>
    * openRequestId</code>.
    *
@@ -550,7 +626,8 @@
 
     const filePath = this.openedFiles[options.openRequestId];
     if (filePath === '/' + TestFileSystemProvider.FILE_READ_SUCCESS) {
-      sendFileInChunks(this.files[filePath]);
+      const entry = this.findEntryByPath(filePath);
+      sendFileInChunks(entry);
       return;
     }
 
@@ -571,9 +648,9 @@
 
     if (filePath === '/' + TestFileSystemProvider.FILE_STALL_READ) {
       // Block the read until it's unblocked.
-      const file = this.files[filePath];
+      const entry = this.findEntryByPath(filePath);
       this.stallRequest('onReadFileRequested', options)
-          .then(() => sendFileInChunks(file));
+          .then(() => sendFileInChunks(entry));
       return;
     }
 
@@ -594,7 +671,7 @@
       return;
     }
 
-    if (options.entryPath in this.files) {
+    if (!this.findEntryByPath(options.entryPath)) {
       onSuccess();
       return;
     }
@@ -622,13 +699,18 @@
     }
 
     const filePath = this.openedFiles[options.openRequestId];
-    if (!(filePath in this.files)) {
+    const entry = this.findEntryByPath(filePath);
+    if (!entry) {
       onError(chrome.fileSystemProvider.ProviderError.INVALID_OPERATION);
       return;
     }
 
-    const file = this.files[filePath];
-    const metadata = file.metadata;
+    const metadata = entry.metadata;
+
+    if (metadata.isDirectory) {
+      onError(chrome.fileSystemProvider.ProviderError.INVALID_OPERATION);
+      return;
+    }
 
     if (filePath === '/' + TestFileSystemProvider.FILE_FAIL) {
       onError(chrome.fileSystemProvider.ProviderError.FAILED);
@@ -652,7 +734,7 @@
     }
 
     // Create an array with enough space for new data.
-    const oldArray = new TextEncoder().encode(file.contents || '');
+    const oldArray = new TextEncoder().encode(entry.contents || '');
     const newLength =
         Math.max(oldArray.length, options.offset + options.data.byteLength);
     const newArray = new Uint8Array(new ArrayBuffer(newLength));
@@ -661,7 +743,7 @@
     newArray.set(new Uint8Array(options.data), options.offset);
     // Save the new file as text.
     const newContents = new TextDecoder().decode(newArray);
-    file.contents = newContents;
+    entry.contents = newContents;
     metadata.size = newContents.length;
     onSuccess();
   }
@@ -686,21 +768,24 @@
       return;
     }
 
-    if (options.entryPath ===
-        '/' + TestFileSystemProvider.TEST_DIR_DELETE_NONEMPTY) {
-      if (options.recursive)
-        onSuccess();
-      else
-        onError(chrome.fileSystemProvider.ProviderError.INVALID_OPERATION);
+    const entry = this.findEntryByPath(options.entryPath);
+    if (!entry) {
+      onError(chrome.fileSystemProvider.ProviderError.NOT_FOUND);
       return;
     }
 
-    if (options.entryPath === '/' + TestFileSystemProvider.FILE_DELETE) {
-      onSuccess();
+    if (entry.metadata.isDirectory &&
+        (!options.recursive && Object.keys(entry.children).length > 0)) {
+      // Don't allow non-recursive deletion of non-empty directories.
+      onError(chrome.fileSystemProvider.ProviderError.INVALID_OPERATION);
       return;
     }
 
-    onError(chrome.fileSystemProvider.ProviderError.NOT_FOUND);
+    const {dirPath, fileName} = splitPath(options.entryPath);
+    const parentEntry = this.findEntryByPath(dirPath);
+    delete parentEntry.children[fileName];
+
+    onSuccess();
   }
 };
 
@@ -766,22 +851,6 @@
  */
 TestFileSystemProvider.INITIAL_TEXT = 'Hello world. How are you today?';
 
-/**
- * Non-empty directory. Can only be deleted recursively.
- *
- * @type {string}
- * @const
- */
-TestFileSystemProvider.TEST_DIR_DELETE_NONEMPTY = 'non-empty-directory';
-
-/**
- * File to be deleted.
- *
- * @type {string}
- * @const
- */
-TestFileSystemProvider.FILE_DELETE = 'file-delete.txt';
-
 // Service worker entry point.
 export function serviceWorkerMain(serviceWorker) {
   const provider =
@@ -789,4 +858,4 @@
 
   provider.setUpProviderListeners();
   provider.setUpCommandListener(serviceWorker);
-}
\ No newline at end of file
+}
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/read_directory/manifest.json b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/read_directory/manifest.json
new file mode 100644
index 0000000..93e1481
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/read_directory/manifest.json
@@ -0,0 +1,23 @@
+{
+  // chrome-extension://pkplfbidichfdicaijlchgnapepdginl
+  "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtDfX9dHNh948bt00YhZBm3P6E5QLaOt+v8kXVtibQfiPtOD2FTScB/f0wX/EQWVO7BkaSOsRkTPcPIgocyMPYr2FLgqGLFlYT9nQpKJZUFNF5oJ5rG6Nv7ppf4zEB3j6da1IBRTz2yOZ+6O1TMZxol/V62/QcqrJeggsHTEPGLdr9Ua4b1Ka0xKJnJngZljsbw93FI1o+P9dAh5BS6wTPiZI/vmJVjvMTkSTnaZ3n9Go2t7A0XLcSxLcVyuLAd2mAvSN0mIviOukdM66wr7llif71nKuUt+4qvlr/r9HfwzN6pA4jkwhtS1UD+3CmB+wsHwsnohNcuu4FIQ6rgq/7QIDAQAB",
+  "name": "chrome.fileSystemProvider.onReadDirectoryRequested",
+  "version": "0.1",
+  "manifest_version": 3,
+  "description":
+      "Test for chrome.fileSystemProvider.onReadDirectoryRequested() for service workers.",
+  "permissions": [
+    "fileSystemProvider",
+    {
+      "fileSystem": ["requestFileSystem", "write"]
+    },
+    "fileManagerPrivate"
+  ],
+  "file_system_provider_capabilities": {
+    "source": "device"
+  },
+  "background": {
+    "service_worker": "sw.js",
+    "type": "module"
+  }
+}
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/read_directory/sw.js b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/read_directory/sw.js
new file mode 100644
index 0000000..ac074135
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/read_directory/sw.js
@@ -0,0 +1,7 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {serviceWorkerMain} from '/_test_resources/api_test/file_system_provider/service_worker/provider.js';
+
+serviceWorkerMain(self);
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/read_directory/test.html b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/read_directory/test.html
new file mode 100644
index 0000000..9980fda0
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/read_directory/test.html
@@ -0,0 +1 @@
+<script type="module" src="test.js"></script>
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/read_directory/test.js b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/read_directory/test.js
new file mode 100644
index 0000000..4f690f26
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/read_directory/test.js
@@ -0,0 +1,103 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+import {mountTestFileSystem, remoteProvider} from '/_test_resources/api_test/file_system_provider/service_worker/helpers.js';
+// For shared constants.
+import {TestFileSystemProvider} from '/_test_resources/api_test/file_system_provider/service_worker/provider.js';
+
+const TESTING_HELLO_DIR = Object.freeze({
+  isDirectory: true,
+  name: 'hello',
+  modificationTime: new Date(2014, 1, 26, 8, 37, 13),
+});
+
+/**
+ * @type {Object}
+ * @const
+ */
+const TESTING_CANDIES_DIR = Object.freeze({
+  isDirectory: true,
+  name: 'candies',
+  modificationTime: new Date(2014, 1, 26, 8, 37, 13),
+});
+
+/**
+ * @type {Object}
+ * @const
+ */
+const TESTING_TIRAMISU_FILE = Object.freeze({
+  isDirectory: false,
+  name: 'tiramisu.txt',
+  modificationTime: new Date(2014, 1, 26, 8, 37, 13),
+});
+
+/**
+ * Read all entries from a directory.
+ *
+ * @param {!DirectoryEntry} dirEntry
+ * @returns {!Promise<!Array<!FileEntry>>}
+ */
+async function readAllEntries(dirEntry) {
+  const allEntries = [];
+  const reader = dirEntry.createReader();
+  for (;;) {
+    const entries = await new Promise(
+        (resolve, reject) => reader.readEntries(resolve, reject));
+    if (entries.length == 0) {
+      break;
+    }
+    allEntries.push(...entries);
+  }
+  return allEntries;
+}
+
+async function main() {
+  await navigator.serviceWorker.ready;
+  const fileSystem = await mountTestFileSystem();
+  await remoteProvider.addFiles({
+    [`/${TESTING_HELLO_DIR.name}`]: {
+      metadata: TESTING_HELLO_DIR,
+    },
+    [`/${TESTING_HELLO_DIR.name}/${TESTING_TIRAMISU_FILE.name}`]: {
+      metadata: TESTING_TIRAMISU_FILE,
+    },
+    [`/${TESTING_HELLO_DIR.name}/${TESTING_CANDIES_DIR.name}`]: {
+      metadata: TESTING_CANDIES_DIR,
+    },
+  });
+
+  chrome.test.runTests([
+    // Read contents of the /hello directory. This directory exists, so it
+    // should succeed.
+    async function readEntriesSuccess() {
+      try {
+        const dirEntry = await fileSystem.getDirectoryEntry(
+            TESTING_HELLO_DIR.name, {create: false});
+        const entries = await readAllEntries(dirEntry);
+        chrome.test.assertEq(2, entries.length);
+        chrome.test.assertTrue(entries[0].isFile);
+        chrome.test.assertEq('tiramisu.txt', entries[0].name);
+        chrome.test.assertEq('/hello/tiramisu.txt', entries[0].fullPath);
+        chrome.test.assertTrue(entries[1].isDirectory);
+        chrome.test.assertEq('candies', entries[1].name);
+        chrome.test.assertEq('/hello/candies', entries[1].fullPath);
+        chrome.test.succeed();
+      } catch (e) {
+        chrome.test.fail(e);
+      }
+    },
+    // Read contents of a directory which does not exist, what should return an
+    // error.
+    async function readEntriesError() {
+      try {
+        await fileSystem.getDirectoryEntry('cranberries', {create: false});
+        chrome.test.fail('Succeeded getting a non-existent directory entry.');
+      } catch (e) {
+        chrome.test.assertEq('NotFoundError', e.name);
+        chrome.test.succeed();
+      }
+    }
+  ]);
+}
+
+main();
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/read_file/test.js b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/read_file/test.js
index 3c35b75..cf1d510 100644
--- a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/read_file/test.js
+++ b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/read_file/test.js
@@ -1,42 +1,10 @@
 // Copyright 2022 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-import {mountTestFileSystem, remoteProvider} from '/_test_resources/api_test/file_system_provider/service_worker/helpers.js';
+import {mountTestFileSystem, openFile, readTextFromFile, remoteProvider, startReadTextFromFile} from '/_test_resources/api_test/file_system_provider/service_worker/helpers.js';
 // For shared constants.
 import {TestFileSystemProvider} from '/_test_resources/api_test/file_system_provider/service_worker/provider.js';
 
-/**
- * @param {!FileEntry} fileEntry
- * @returns {!Promise<!File>}
- */
-async function openFile(fileEntry) {
-  return new Promise((resolve, reject) => fileEntry.file(resolve, reject));
-}
-
-/**
- * @param {!File} file
- * @returns {!Promise<string>}
- */
-async function readTextFromFile(file) {
-  const {promise} = startReadTextFromFile(file);
-  return promise;
-}
-
-/**
- * @param {!File} file
- * @returns {{promise: !Promise<string>, reader: !FileReader}}
- */
-function startReadTextFromFile(file) {
-  const reader = new FileReader();
-  const promise = new Promise((resolve, reject) => {
-    reader.onload = e => resolve(reader.result);
-    reader.onerror = e => reject(reader.error);
-    reader.onabort = e => reject(reader.error);
-    reader.readAsText(file);
-  });
-  return {reader, promise};
-}
-
 async function main() {
   await navigator.serviceWorker.ready;
   const fileSystem = await mountTestFileSystem();
diff --git a/chrome/test/data/webui/chromeos/diagnostics/diagnostics_browsertest.js b/chrome/test/data/webui/chromeos/diagnostics/diagnostics_browsertest.js
index 402b542..46e9858 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/diagnostics_browsertest.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/diagnostics_browsertest.js
@@ -113,7 +113,8 @@
   'WifiInfo',
 ];
 
-TEST_F('DiagnosticsApp', 'BrowserTest', function() {
+// Flaky: https://crbug.com/1372958
+TEST_F('DiagnosticsApp', 'DISABLED_BrowserTest', function() {
   assertDeepEquals(
       debug_suites_list, Object.keys(test_suites_list),
       'List of registered tests suites and debug suites do not match.\n' +
@@ -122,11 +123,13 @@
   mocha.run();
 });
 
-TEST_F('DiagnosticsAppWithNetwork', 'BrowserTest', function() {
+// Flaky: https://crbug.com/1372958
+TEST_F('DiagnosticsAppWithNetwork', 'DISABLED_BrowserTest', function() {
   mocha.run();
 });
 
-TEST_F('DiagnosticsAppWithInput', 'BrowserTest', function() {
+// Flaky: https://crbug.com/1372958
+TEST_F('DiagnosticsAppWithInput', 'DISABLED_BrowserTest', function() {
   mocha.run();
 });
 
diff --git a/chrome/test/data/webui/cr_elements/cr_auto_img_test.ts b/chrome/test/data/webui/cr_elements/cr_auto_img_test.ts
index 57b4d440..a44f451 100644
--- a/chrome/test/data/webui/cr_elements/cr_auto_img_test.ts
+++ b/chrome/test/data/webui/cr_elements/cr_auto_img_test.ts
@@ -135,4 +135,66 @@
 
         assertEquals(newSrc, img.src, 'src attribute is set to new value');
       });
+
+  test(
+      'setting staticEncode creates a URL with autoSrc and staticEncode as params',
+      () => {
+        const autoSrc = 'https://foo.com/img.png';
+
+        // Act.
+        img.staticEncode = true;
+        img.autoSrc = autoSrc;
+
+        // Assert.
+        assertEquals(
+            `chrome://image/?url=${
+                encodeURIComponent(autoSrc)}&staticEncode=true`,
+            img.src);
+
+        // Act.
+        img.staticEncode = false;
+
+        // Assert.
+        assertEquals(`chrome://image/?${autoSrc}`, img.src);
+      });
+
+  test(
+      'setting static-encode creates a URL with autoSrc and staticEncode as params',
+      () => {
+        const autoSrc = 'https://foo.com/img.png';
+
+        // Act.
+        img.setAttribute('static-encode', '');
+        img.autoSrc = autoSrc;
+
+        // Assert.
+        assertEquals(
+            `chrome://image/?url=${
+                encodeURIComponent(autoSrc)}&staticEncode=true`,
+            img.src);
+
+        // Act.
+        img.removeAttribute('static-encode');
+
+        // Assert.
+        assertEquals(`chrome://image/?${autoSrc}`, img.src);
+      });
+
+  test(
+      'setting multiple attributes creates a URL with all of the params',
+      () => {
+        const autoSrc = 'https://foo.com/img.png';
+
+        // Act.
+        img.setAttribute('static-encode', '');
+        img.isGooglePhotos = true;
+        img.autoSrc = autoSrc;
+
+        // Assert.
+        assertEquals(
+            `chrome://image/?url=${
+                encodeURIComponent(
+                    autoSrc)}&isGooglePhotos=true&staticEncode=true`,
+            img.src);
+      });
 });
diff --git a/chrome/test/webapps/coverage/coverage_cros.tsv b/chrome/test/webapps/coverage/coverage_cros.tsv
index c12658c..d8da383 100644
--- a/chrome/test/webapps/coverage/coverage_cros.tsv
+++ b/chrome/test/webapps/coverage/coverage_cros.tsv
@@ -1,5 +1,5 @@
 # This is a generated file.
-# Full coverage: 51%, with partial coverage: 69%
+# Full coverage: 50%, with partial coverage: 69%
 create_shortcut_Standalone_Windowed🌕	launch_from_menu_option_Standalone🌕	check_app_title_Standalone_StandaloneOriginal🌑
 create_shortcut_Standalone_Windowed🌕	launch_from_launch_icon_Standalone🌕	check_app_title_Standalone_StandaloneOriginal🌑
 create_shortcut_Standalone_Windowed🌕	launch_from_chrome_apps_Standalone🌓	check_app_title_Standalone_StandaloneOriginal🌑
@@ -538,6 +538,22 @@
 install_policy_app_Standalone_NoShortcut_Browser_WebApp🌓	create_shortcut_Standalone_Windowed🌕	uninstall_policy_app_Standalone🌕	check_platform_shortcut_and_icon_Standalone🌓
 install_policy_app_Standalone_NoShortcut_Browser_WebApp🌓	install_omnibox_icon_Standalone🌕	uninstall_policy_app_Standalone🌕	check_platform_shortcut_and_icon_Standalone🌓
 install_policy_app_Standalone_NoShortcut_Browser_WebApp🌓	install_menu_option_Standalone🌕	uninstall_policy_app_Standalone🌕	check_platform_shortcut_and_icon_Standalone🌓
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebShortcut🌓	launch_from_menu_option_StandaloneNotStartUrl🌕	check_app_navigation_StandaloneNotStartUrl🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebShortcut🌓	launch_from_launch_icon_StandaloneNotStartUrl🌕	check_app_navigation_StandaloneNotStartUrl🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebShortcut🌓	launch_from_chrome_apps_StandaloneNotStartUrl🌓	check_app_navigation_StandaloneNotStartUrl🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebShortcut🌓	launch_from_platform_shortcut_StandaloneNotStartUrl🌑	check_app_navigation_StandaloneNotStartUrl🌑
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebApp🌓	launch_from_menu_option_Standalone🌕	check_app_navigation_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebApp🌓	launch_from_launch_icon_Standalone🌕	check_app_navigation_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebApp🌓	launch_from_chrome_apps_Standalone🌓	check_app_navigation_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebApp🌓	launch_from_platform_shortcut_Standalone🌑	check_app_navigation_Standalone🌑
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Browser_WebApp🌓	launch_from_chrome_apps_Standalone🌓	check_browser_navigation_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Browser_WebApp🌓	launch_from_platform_shortcut_Standalone🌑	check_browser_navigation_Standalone🌑
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Browser_WebShortcut🌓	launch_from_chrome_apps_StandaloneNotStartUrl🌓	check_browser_navigation_StandaloneNotStartUrl🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Browser_WebShortcut🌓	launch_from_platform_shortcut_StandaloneNotStartUrl🌑	check_browser_navigation_StandaloneNotStartUrl🌑
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebApp🌓	check_app_not_in_list_StandaloneNotStartUrl🌓	check_app_in_list_icon_correct_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Browser_WebApp🌓	check_app_not_in_list_StandaloneNotStartUrl🌓	check_app_in_list_icon_correct_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebShortcut🌓	check_app_not_in_list_Standalone🌓	check_app_in_list_icon_correct_StandaloneNotStartUrl🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Browser_WebShortcut🌓	check_app_not_in_list_Standalone🌓	check_app_in_list_icon_correct_StandaloneNotStartUrl🌕
 create_shortcut_Standalone_Windowed🌕	manifest_update_colors_Standalone🌑	await_manifest_update_Standalone🌑	launch_from_menu_option_Standalone🌑	check_window_color_correct_Standalone🌑
 create_shortcut_Standalone_Windowed🌕	manifest_update_colors_Standalone🌑	await_manifest_update_Standalone🌑	launch_from_launch_icon_Standalone🌑	check_window_color_correct_Standalone🌑
 create_shortcut_Standalone_Windowed🌕	manifest_update_colors_Standalone🌑	await_manifest_update_Standalone🌑	launch_from_chrome_apps_Standalone🌑	check_window_color_correct_Standalone🌑
diff --git a/chrome/test/webapps/coverage/coverage_linux.tsv b/chrome/test/webapps/coverage/coverage_linux.tsv
index e58ad8e..eb7282a 100644
--- a/chrome/test/webapps/coverage/coverage_linux.tsv
+++ b/chrome/test/webapps/coverage/coverage_linux.tsv
@@ -755,6 +755,22 @@
 install_policy_app_Standalone_NoShortcut_Browser_WebApp🌓	create_shortcut_Standalone_Windowed🌕	uninstall_policy_app_Standalone🌕	check_platform_shortcut_and_icon_Standalone🌓
 install_policy_app_Standalone_NoShortcut_Browser_WebApp🌓	install_omnibox_icon_Standalone🌕	uninstall_policy_app_Standalone🌕	check_platform_shortcut_and_icon_Standalone🌓
 install_policy_app_Standalone_NoShortcut_Browser_WebApp🌓	install_menu_option_Standalone🌕	uninstall_policy_app_Standalone🌕	check_platform_shortcut_and_icon_Standalone🌓
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebShortcut🌓	launch_from_menu_option_StandaloneNotStartUrl🌕	check_app_navigation_StandaloneNotStartUrl🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebShortcut🌓	launch_from_launch_icon_StandaloneNotStartUrl🌕	check_app_navigation_StandaloneNotStartUrl🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebShortcut🌓	launch_from_chrome_apps_StandaloneNotStartUrl🌓	check_app_navigation_StandaloneNotStartUrl🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebShortcut🌓	launch_from_platform_shortcut_StandaloneNotStartUrl🌓	check_app_navigation_StandaloneNotStartUrl🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebApp🌓	launch_from_menu_option_Standalone🌕	check_app_navigation_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebApp🌓	launch_from_launch_icon_Standalone🌕	check_app_navigation_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebApp🌓	launch_from_chrome_apps_Standalone🌓	check_app_navigation_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebApp🌓	launch_from_platform_shortcut_Standalone🌓	check_app_navigation_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Browser_WebApp🌓	launch_from_chrome_apps_Standalone🌓	check_browser_navigation_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Browser_WebApp🌓	launch_from_platform_shortcut_Standalone🌓	check_browser_navigation_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Browser_WebShortcut🌓	launch_from_chrome_apps_StandaloneNotStartUrl🌓	check_browser_navigation_StandaloneNotStartUrl🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Browser_WebShortcut🌓	launch_from_platform_shortcut_StandaloneNotStartUrl🌓	check_browser_navigation_StandaloneNotStartUrl🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebApp🌓	check_app_not_in_list_StandaloneNotStartUrl🌓	check_app_in_list_icon_correct_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Browser_WebApp🌓	check_app_not_in_list_StandaloneNotStartUrl🌓	check_app_in_list_icon_correct_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebShortcut🌓	check_app_not_in_list_Standalone🌓	check_app_in_list_icon_correct_StandaloneNotStartUrl🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Browser_WebShortcut🌓	check_app_not_in_list_Standalone🌓	check_app_in_list_icon_correct_StandaloneNotStartUrl🌕
 create_shortcut_Standalone_Windowed🌕	manifest_update_colors_Standalone🌑	await_manifest_update_Standalone🌑	launch_from_menu_option_Standalone🌑	check_window_color_correct_Standalone🌑
 create_shortcut_Standalone_Windowed🌕	manifest_update_colors_Standalone🌑	await_manifest_update_Standalone🌑	launch_from_launch_icon_Standalone🌑	check_window_color_correct_Standalone🌑
 create_shortcut_Standalone_Windowed🌕	manifest_update_colors_Standalone🌑	await_manifest_update_Standalone🌑	launch_from_chrome_apps_Standalone🌑	check_window_color_correct_Standalone🌑
diff --git a/chrome/test/webapps/coverage/coverage_mac.tsv b/chrome/test/webapps/coverage/coverage_mac.tsv
index 7994eda..75e0ab0 100644
--- a/chrome/test/webapps/coverage/coverage_mac.tsv
+++ b/chrome/test/webapps/coverage/coverage_mac.tsv
@@ -755,6 +755,22 @@
 install_policy_app_Standalone_NoShortcut_Browser_WebApp🌓	create_shortcut_Standalone_Windowed🌕	uninstall_policy_app_Standalone🌕	check_platform_shortcut_and_icon_Standalone🌕
 install_policy_app_Standalone_NoShortcut_Browser_WebApp🌓	install_omnibox_icon_Standalone🌕	uninstall_policy_app_Standalone🌕	check_platform_shortcut_and_icon_Standalone🌕
 install_policy_app_Standalone_NoShortcut_Browser_WebApp🌓	install_menu_option_Standalone🌕	uninstall_policy_app_Standalone🌕	check_platform_shortcut_and_icon_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebShortcut🌓	launch_from_menu_option_StandaloneNotStartUrl🌕	check_app_navigation_StandaloneNotStartUrl🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebShortcut🌓	launch_from_launch_icon_StandaloneNotStartUrl🌕	check_app_navigation_StandaloneNotStartUrl🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebShortcut🌓	launch_from_chrome_apps_StandaloneNotStartUrl🌓	check_app_navigation_StandaloneNotStartUrl🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebShortcut🌓	launch_from_platform_shortcut_StandaloneNotStartUrl🌓	check_app_navigation_StandaloneNotStartUrl🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebApp🌓	launch_from_menu_option_Standalone🌕	check_app_navigation_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebApp🌓	launch_from_launch_icon_Standalone🌕	check_app_navigation_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebApp🌓	launch_from_chrome_apps_Standalone🌓	check_app_navigation_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebApp🌓	launch_from_platform_shortcut_Standalone🌓	check_app_navigation_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Browser_WebApp🌓	launch_from_chrome_apps_Standalone🌓	check_browser_navigation_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Browser_WebApp🌓	launch_from_platform_shortcut_Standalone🌓	check_browser_navigation_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Browser_WebShortcut🌓	launch_from_chrome_apps_StandaloneNotStartUrl🌓	check_browser_navigation_StandaloneNotStartUrl🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Browser_WebShortcut🌓	launch_from_platform_shortcut_StandaloneNotStartUrl🌓	check_browser_navigation_StandaloneNotStartUrl🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebApp🌓	check_app_not_in_list_StandaloneNotStartUrl🌓	check_app_in_list_icon_correct_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Browser_WebApp🌓	check_app_not_in_list_StandaloneNotStartUrl🌓	check_app_in_list_icon_correct_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebShortcut🌓	check_app_not_in_list_Standalone🌓	check_app_in_list_icon_correct_StandaloneNotStartUrl🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Browser_WebShortcut🌓	check_app_not_in_list_Standalone🌓	check_app_in_list_icon_correct_StandaloneNotStartUrl🌕
 create_shortcut_Standalone_Windowed🌕	manifest_update_colors_Standalone🌑	await_manifest_update_Standalone🌑	launch_from_menu_option_Standalone🌑	check_window_color_correct_Standalone🌑
 create_shortcut_Standalone_Windowed🌕	manifest_update_colors_Standalone🌑	await_manifest_update_Standalone🌑	launch_from_launch_icon_Standalone🌑	check_window_color_correct_Standalone🌑
 create_shortcut_Standalone_Windowed🌕	manifest_update_colors_Standalone🌑	await_manifest_update_Standalone🌑	launch_from_chrome_apps_Standalone🌑	check_window_color_correct_Standalone🌑
diff --git a/chrome/test/webapps/coverage/coverage_win.tsv b/chrome/test/webapps/coverage/coverage_win.tsv
index 909665c..28507c0 100644
--- a/chrome/test/webapps/coverage/coverage_win.tsv
+++ b/chrome/test/webapps/coverage/coverage_win.tsv
@@ -1,5 +1,5 @@
 # This is a generated file.
-# Full coverage: 60%, with partial coverage: 80%
+# Full coverage: 59%, with partial coverage: 80%
 create_shortcut_Standalone_Windowed🌕	launch_from_menu_option_Standalone🌕	check_app_title_Standalone_StandaloneOriginal🌑
 create_shortcut_Standalone_Windowed🌕	launch_from_launch_icon_Standalone🌕	check_app_title_Standalone_StandaloneOriginal🌑
 create_shortcut_Standalone_Windowed🌕	launch_from_chrome_apps_Standalone🌓	check_app_title_Standalone_StandaloneOriginal🌑
@@ -755,6 +755,22 @@
 install_policy_app_Standalone_NoShortcut_Browser_WebApp🌓	create_shortcut_Standalone_Windowed🌕	uninstall_policy_app_Standalone🌕	check_platform_shortcut_and_icon_Standalone🌓
 install_policy_app_Standalone_NoShortcut_Browser_WebApp🌓	install_omnibox_icon_Standalone🌕	uninstall_policy_app_Standalone🌕	check_platform_shortcut_and_icon_Standalone🌓
 install_policy_app_Standalone_NoShortcut_Browser_WebApp🌓	install_menu_option_Standalone🌕	uninstall_policy_app_Standalone🌕	check_platform_shortcut_and_icon_Standalone🌓
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebShortcut🌓	launch_from_menu_option_StandaloneNotStartUrl🌕	check_app_navigation_StandaloneNotStartUrl🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebShortcut🌓	launch_from_launch_icon_StandaloneNotStartUrl🌕	check_app_navigation_StandaloneNotStartUrl🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebShortcut🌓	launch_from_chrome_apps_StandaloneNotStartUrl🌓	check_app_navigation_StandaloneNotStartUrl🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebShortcut🌓	launch_from_platform_shortcut_StandaloneNotStartUrl🌓	check_app_navigation_StandaloneNotStartUrl🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebApp🌓	launch_from_menu_option_Standalone🌕	check_app_navigation_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebApp🌓	launch_from_launch_icon_Standalone🌕	check_app_navigation_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebApp🌓	launch_from_chrome_apps_Standalone🌓	check_app_navigation_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebApp🌓	launch_from_platform_shortcut_Standalone🌓	check_app_navigation_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Browser_WebApp🌓	launch_from_chrome_apps_Standalone🌓	check_browser_navigation_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Browser_WebApp🌓	launch_from_platform_shortcut_Standalone🌓	check_browser_navigation_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Browser_WebShortcut🌓	launch_from_chrome_apps_StandaloneNotStartUrl🌓	check_browser_navigation_StandaloneNotStartUrl🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Browser_WebShortcut🌓	launch_from_platform_shortcut_StandaloneNotStartUrl🌓	check_browser_navigation_StandaloneNotStartUrl🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebApp🌓	check_app_not_in_list_StandaloneNotStartUrl🌓	check_app_in_list_icon_correct_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Browser_WebApp🌓	check_app_not_in_list_StandaloneNotStartUrl🌓	check_app_in_list_icon_correct_Standalone🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Windowed_WebShortcut🌓	check_app_not_in_list_Standalone🌓	check_app_in_list_icon_correct_StandaloneNotStartUrl🌕
+install_policy_app_StandaloneNotStartUrl_WithShortcut_Browser_WebShortcut🌓	check_app_not_in_list_Standalone🌓	check_app_in_list_icon_correct_StandaloneNotStartUrl🌕
 create_shortcut_Standalone_Windowed🌕	manifest_update_colors_Standalone🌑	await_manifest_update_Standalone🌑	launch_from_menu_option_Standalone🌑	check_window_color_correct_Standalone🌑
 create_shortcut_Standalone_Windowed🌕	manifest_update_colors_Standalone🌑	await_manifest_update_Standalone🌑	launch_from_launch_icon_Standalone🌑	check_window_color_correct_Standalone🌑
 create_shortcut_Standalone_Windowed🌕	manifest_update_colors_Standalone🌑	await_manifest_update_Standalone🌑	launch_from_chrome_apps_Standalone🌑	check_window_color_correct_Standalone🌑
diff --git a/chrome/test/webapps/data/critical_user_journeys.md b/chrome/test/webapps/data/critical_user_journeys.md
index 7bca3d0d37..2a34b3e 100644
--- a/chrome/test/webapps/data/critical_user_journeys.md
+++ b/chrome/test/webapps/data/critical_user_journeys.md
@@ -199,6 +199,16 @@
 | WMLC | install_or_shortcut_by_user_windowed | install_policy_app(Standalone, ShortcutOptions::All, WindowOptions::All, WebApp) | uninstall_policy_app | check_platform_shortcut_and_icon |
 | WMLC | install_policy_app(Standalone, ShortcutOptions::All, Browser, WebApp) | install_or_shortcut_by_user_windowed | uninstall_policy_app | check_app_in_list_windowed |
 | WMLC | install_policy_app(Standalone, ShortcutOptions::All, Browser, WebApp) | install_or_shortcut_by_user_windowed | uninstall_policy_app | check_platform_shortcut_and_icon |
+| WMLC | install_policy_app(StandaloneNotStartUrl, WithShortcut, Windowed, WebShortcut) | launch(StandaloneNotStartUrl) | check_app_navigation(StandaloneNotStartUrl) |
+| WMLC | install_policy_app(StandaloneNotStartUrl, WithShortcut, Windowed, WebApp) | launch(Standalone) | check_app_navigation(Standalone) |
+| WMLC | install_policy_app(StandaloneNotStartUrl, WithShortcut, Browser, WebApp) | launch_from_chrome_apps(Standalone) | check_browser_navigation(Standalone) |
+| WMLC | install_policy_app(StandaloneNotStartUrl, WithShortcut, Browser, WebApp) | launch_from_platform_shortcut(Standalone) | check_browser_navigation(Standalone) |
+| WMLC | install_policy_app(StandaloneNotStartUrl, WithShortcut, Browser, WebShortcut) | launch_from_chrome_apps(StandaloneNotStartUrl) | check_browser_navigation(StandaloneNotStartUrl) |
+| WMLC | install_policy_app(StandaloneNotStartUrl, WithShortcut, Browser, WebShortcut) | launch_from_platform_shortcut(StandaloneNotStartUrl) | check_browser_navigation(StandaloneNotStartUrl) |
+| WMLC | install_policy_app(StandaloneNotStartUrl, WithShortcut, WindowOptions::All, WebApp) | check_app_not_in_list(StandaloneNotStartUrl) | check_app_in_list_icon_correct(Standalone) |
+| WMLC | install_policy_app(StandaloneNotStartUrl, WithShortcut, WindowOptions::All, WebShortcut) | check_app_not_in_list(Standalone) | check_app_in_list_icon_correct(StandaloneNotStartUrl) |
+
+
 
 ## Manifest update tests
 | #Platforms | Test -> | | | | | | | | | | | | | | | | |
diff --git a/chrome/test/webapps/data/framework_supported_actions.csv b/chrome/test/webapps/data/framework_supported_actions.csv
index b80ff8d..7db4b982 100644
--- a/chrome/test/webapps/data/framework_supported_actions.csv
+++ b/chrome/test/webapps/data/framework_supported_actions.csv
@@ -65,5 +65,6 @@
 check_run_on_os_login_disabled,                        🌕, 🌕,  🌕,   🌑,
 open_app_settings_from_chrome_apps,                    🌕, 🌕,  🌕,   🌑,
 open_app_settings_from_app_menu,                       🌕, 🌕,  🌕,   🌑,
+check_browser_navigation,                              🌕, 🌕,  🌕,   🌕,
 check_browser_navigation_is_app_settings,              🌕, 🌕,  🌕,   🌑,
 await_manifest_update,                                 🌕, 🌕,  🌕,   🌕,
diff --git a/chromeos/ash/components/dbus/session_manager/fake_session_manager_client.cc b/chromeos/ash/components/dbus/session_manager/fake_session_manager_client.cc
index 3783561..b886616 100644
--- a/chromeos/ash/components/dbus/session_manager/fake_session_manager_client.cc
+++ b/chromeos/ash/components/dbus/session_manager/fake_session_manager_client.cc
@@ -435,6 +435,12 @@
   return true;
 }
 
+bool FakeSessionManagerClient::BlockingRequestBrowserDataBackwardMigration(
+    const cryptohome::AccountIdentifier& cryptohome_id) {
+  request_browser_data_backward_migration_called_ = true;
+  return true;
+}
+
 void FakeSessionManagerClient::RetrieveActiveSessions(
     ActiveSessionsCallback callback) {
   PostReply(FROM_HERE, std::move(callback), user_sessions_);
diff --git a/chromeos/ash/components/dbus/session_manager/fake_session_manager_client.h b/chromeos/ash/components/dbus/session_manager/fake_session_manager_client.h
index f320118..3f7a98d 100644
--- a/chromeos/ash/components/dbus/session_manager/fake_session_manager_client.h
+++ b/chromeos/ash/components/dbus/session_manager/fake_session_manager_client.h
@@ -113,6 +113,8 @@
   bool RequestBrowserDataMigration(
       const cryptohome::AccountIdentifier& cryptohome_id,
       const std::string& mode) override;
+  bool BlockingRequestBrowserDataBackwardMigration(
+      const cryptohome::AccountIdentifier& cryptohome_id) override;
   void RetrieveActiveSessions(ActiveSessionsCallback callback) override;
   void RetrieveDevicePolicy(RetrievePolicyCallback callback) override;
   RetrievePolicyResponseType BlockingRetrieveDevicePolicy(
@@ -353,6 +355,10 @@
     return request_browser_data_migration_mode_value_;
   }
 
+  bool request_browser_data_backward_migration_called() const {
+    return request_browser_data_migration_called_;
+  }
+
  private:
   // Called in response to writing owner key file specified in new device
   // policy - used for in-memory fake only.
@@ -431,6 +437,8 @@
   bool request_browser_data_migration_mode_called_ = false;
   std::string request_browser_data_migration_mode_value_ = "invalid";
 
+  bool request_browser_data_backward_migration_called_ = false;
+
   // Contains last request passed to StartArcMiniContainer
   arc::StartArcMiniInstanceRequest last_start_arc_mini_container_request_;
 
diff --git a/chromeos/ash/components/dbus/session_manager/session_manager_client.cc b/chromeos/ash/components/dbus/session_manager/session_manager_client.cc
index f84fc65..4009ec5 100644
--- a/chromeos/ash/components/dbus/session_manager/session_manager_client.cc
+++ b/chromeos/ash/components/dbus/session_manager/session_manager_client.cc
@@ -466,6 +466,29 @@
     return true;
   }
 
+  bool BlockingRequestBrowserDataBackwardMigration(
+      const cryptohome::AccountIdentifier& cryptohome_id) override {
+    dbus::MethodCall method_call(
+        login_manager::kSessionManagerInterface,
+        login_manager::kSessionManagerStartBrowserDataBackwardMigration);
+    dbus::MessageWriter writer(&method_call);
+    writer.AppendString(cryptohome_id.account_id());
+    dbus::ScopedDBusError error;
+    std::unique_ptr<dbus::Response> response =
+        blocking_method_caller_->CallMethodAndBlockWithError(&method_call,
+                                                             &error);
+    if (!response) {
+      LOG(ERROR) << "BlockingRequestBrowserDataBackwardMigration failed"
+                 << (error.is_set()
+                         ? base::StringPrintf(" :%s:%s", error.name(),
+                                              error.message())
+                         : ".");
+      return false;
+    }
+
+    return true;
+  }
+
   void RetrieveActiveSessions(ActiveSessionsCallback callback) override {
     dbus::MethodCall method_call(
         login_manager::kSessionManagerInterface,
diff --git a/chromeos/ash/components/dbus/session_manager/session_manager_client.h b/chromeos/ash/components/dbus/session_manager/session_manager_client.h
index 88c5ab8..708df09 100644
--- a/chromeos/ash/components/dbus/session_manager/session_manager_client.h
+++ b/chromeos/ash/components/dbus/session_manager/session_manager_client.h
@@ -270,10 +270,19 @@
   // upon next ash-chrome restart. The method returns true if the DBus call was
   // successful. The callback is passed true if the DBus call is successful and
   // false otherwise.
+  // This method is blocking. Do not use unless necessary.
   virtual bool RequestBrowserDataMigration(
       const cryptohome::AccountIdentifier& cryptohome_id,
       const std::string& mode) = 0;
 
+  // Makes session_manager add some flags to carry out browser data backward
+  // migration upon next ash-chrome restart. The method returns true if the DBus
+  // call was successful. The callback is passed true if the DBus call is
+  // successful and false otherwise.
+  // This method is blocking. Do not use unless necessary.
+  virtual bool BlockingRequestBrowserDataBackwardMigration(
+      const cryptohome::AccountIdentifier& cryptohome_id) = 0;
+
   // Map that is used to describe the set of active user sessions where |key|
   // is cryptohome id and |value| is user_id_hash.
   using ActiveSessionsMap = std::map<std::string, std::string>;
diff --git a/chromeos/ash/components/drivefs/drivefs_host.cc b/chromeos/ash/components/drivefs/drivefs_host.cc
index 2ea8f70..4107c6f3 100644
--- a/chromeos/ash/components/drivefs/drivefs_host.cc
+++ b/chromeos/ash/components/drivefs/drivefs_host.cc
@@ -104,12 +104,7 @@
   }
 
   SyncStatus GetSyncStatusForPath(const base::FilePath& drive_path) {
-    base::FilePath absolutePath = host_->GetMountPath();
-    if (!base::FilePath("/").AppendRelativePath(drive_path, &absolutePath)) {
-      LOG(ERROR) << "Failed to make path relative to drive root";
-      return SyncStatus::kNotFound;
-    }
-    return sync_status_tracker_->GetSyncStatusForPath(absolutePath);
+    return sync_status_tracker_->GetSyncStatusForPath(drive_path);
   }
 
  private:
@@ -141,11 +136,11 @@
                                                        SyncStatus::kInProgress);
             break;
           case mojom::ItemEvent::State::kFailed:
+            // TODO(msalomao): Post a delayed task to remove the path.
             sync_status_tracker_->AddSyncStatusForPath(path,
                                                        SyncStatus::kError);
             break;
           case mojom::ItemEvent::State::kCompleted:
-            // TODO(msalomao): Post a delayed task to remove the path.
             sync_status_tracker_->RemovePath(path);
             break;
           default:
diff --git a/chromeos/ash/components/drivefs/drivefs_host_unittest.cc b/chromeos/ash/components/drivefs/drivefs_host_unittest.cc
index b3b657d..7aa8e99e 100644
--- a/chromeos/ash/components/drivefs/drivefs_host_unittest.cc
+++ b/chromeos/ash/components/drivefs/drivefs_host_unittest.cc
@@ -894,9 +894,9 @@
       mojom::ItemEventReason::kTransfer);
   delegate_->OnSyncingStatusUpdate(std::move(first_status));
   delegate_.FlushForTesting();
-  EXPECT_EQ(
-      host_->GetSyncStatusForPath(base::FilePath("/foo/bar/filename.txt")),
-      SyncStatus::kInProgress);
+  EXPECT_EQ(host_->GetSyncStatusForPath(
+                host_->GetMountPath().Append("foo/bar/filename.txt")),
+            SyncStatus::kInProgress);
 
   auto second_status = mojom::SyncingStatus::New();
   second_status->item_events.emplace_back(
@@ -906,13 +906,14 @@
   delegate_->OnSyncingStatusUpdate(std::move(second_status));
   delegate_.FlushForTesting();
   EXPECT_EQ(host_->GetSyncStatusForPath(
-                base::FilePath("/foo/bar/filename_error.txt")),
+                host_->GetMountPath().Append("foo/bar/filename_error.txt")),
             SyncStatus::kError);
+  EXPECT_EQ(host_->GetSyncStatusForPath(
+                host_->GetMountPath().Append("foo/bar/filename.txt")),
+            SyncStatus::kInProgress);
   EXPECT_EQ(
-      host_->GetSyncStatusForPath(base::FilePath("/foo/bar/filename.txt")),
-      SyncStatus::kInProgress);
-  EXPECT_EQ(host_->GetSyncStatusForPath(base::FilePath("/foo/bar")),
-            SyncStatus::kError);
+      host_->GetSyncStatusForPath(host_->GetMountPath().Append("foo/bar")),
+      SyncStatus::kError);
 
   auto third_status = mojom::SyncingStatus::New();
   third_status->item_events.emplace_back(
@@ -922,10 +923,11 @@
   delegate_->OnSyncingStatusUpdate(std::move(third_status));
   delegate_.FlushForTesting();
   EXPECT_EQ(host_->GetSyncStatusForPath(
-                base::FilePath("/foo/bar/filename_error.txt")),
+                host_->GetMountPath().Append("foo/bar/filename_error.txt")),
             SyncStatus::kNotFound);
-  EXPECT_EQ(host_->GetSyncStatusForPath(base::FilePath("/foo/bar")),
-            SyncStatus::kInProgress);
+  EXPECT_EQ(
+      host_->GetSyncStatusForPath(host_->GetMountPath().Append("foo/bar")),
+      SyncStatus::kInProgress);
 
   auto fourth_status = mojom::SyncingStatus::New();
   fourth_status->item_events.emplace_back(
@@ -935,7 +937,8 @@
   delegate_->OnSyncingStatusUpdate(std::move(fourth_status));
   delegate_.FlushForTesting();
 
-  EXPECT_EQ(host_->GetSyncStatusForPath(base::FilePath("relative/path.txt")),
+  EXPECT_EQ(host_->GetSyncStatusForPath(
+                host_->GetMountPath().Append("relative/path.txt")),
             SyncStatus::kNotFound);
 }
 
diff --git a/components/autofill/core/browser/autofill_field.cc b/components/autofill/core/browser/autofill_field.cc
index 76c0089..5db7dd7e 100644
--- a/components/autofill/core/browser/autofill_field.cc
+++ b/components/autofill/core/browser/autofill_field.cc
@@ -212,17 +212,12 @@
 }
 
 AutofillType AutofillField::Type() const {
-  // If the corresponding feature is enabled, server predictions that are an
-  // override are granted precedence unconditionally.
-  if (base::FeatureList::IsEnabled(
-          features::kAutofillServerTypeTakesPrecedence) &&
-      server_type_prediction_is_override() && server_type() != NO_SERVER_DATA) {
+  // Server Overrides are granted precedence unconditionally.
+  if (server_type_prediction_is_override() && server_type() != NO_SERVER_DATA)
     return AutofillType(server_type());
-  }
 
-  if (overall_type_.GetStorableType() != NO_SERVER_DATA) {
+  if (overall_type_.GetStorableType() != NO_SERVER_DATA)
     return overall_type_;
-  }
   return ComputedType();
 }
 
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc
index 91eaf04..399c353 100644
--- a/components/autofill/core/browser/form_structure.cc
+++ b/components/autofill/core/browser/form_structure.cc
@@ -1859,9 +1859,7 @@
                   {", html: ", FieldTypeToStringPiece(field->html_type())})
             : "";
     if (field->html_type() == HtmlFieldType::kUnrecognized &&
-        (!base::FeatureList::IsEnabled(
-             features::kAutofillServerTypeTakesPrecedence) ||
-         !field->server_type_prediction_is_override())) {
+        !field->server_type_prediction_is_override()) {
       html_type_description += " (disabling autofill)";
     }
 
@@ -1936,9 +1934,7 @@
                   {", html: ", FieldTypeToStringPiece(field->html_type())})
             : "";
     if (field->html_type() == HtmlFieldType::kUnrecognized &&
-        (!base::FeatureList::IsEnabled(
-             features::kAutofillServerTypeTakesPrecedence) ||
-         !field->server_type_prediction_is_override())) {
+        !field->server_type_prediction_is_override()) {
       html_type_description += " (disabling autofill)";
     }
 
diff --git a/components/autofill/core/browser/form_structure_sectioning_util.cc b/components/autofill/core/browser/form_structure_sectioning_util.cc
index 23d2cdf..e0e14c8 100644
--- a/components/autofill/core/browser/form_structure_sectioning_util.cc
+++ b/components/autofill/core/browser/form_structure_sectioning_util.cc
@@ -8,6 +8,7 @@
 #include <memory>
 #include <utility>
 
+#include "base/ranges/algorithm.h"
 #include "components/autofill/core/browser/autofill_field.h"
 #include "components/autofill/core/browser/field_types.h"
 #include "components/autofill/core/common/autofill_features.h"
@@ -104,13 +105,19 @@
 }
 
 void ExpandSections(base::span<const std::unique_ptr<AutofillField>> fields) {
-  Section previous_section;
-  for (const auto& field : fields) {
-    if (!IsSectionable(*field))
-      continue;
-    if (!field->section && previous_section)
-      field->section = previous_section;
-    previous_section = field->section;
+  auto HasSection = [](auto& field) {
+    return IsSectionable(*field) && field->section;
+  };
+  auto it = base::ranges::find_if(fields, HasSection);
+  while (it != fields.end()) {
+    auto end = base::ranges::find_if(it + 1, fields.end(), HasSection);
+    if (end != fields.end() && (*it)->section == (*end)->section) {
+      for (auto& field : base::make_span(it + 1, end)) {
+        if (IsSectionable(*field))
+          field->section = (*it)->section;
+      }
+    }
+    it = end;
   }
 }
 
diff --git a/components/autofill/core/browser/form_structure_sectioning_util.h b/components/autofill/core/browser/form_structure_sectioning_util.h
index fd7a3e5..ad77236 100644
--- a/components/autofill/core/browser/form_structure_sectioning_util.h
+++ b/components/autofill/core/browser/form_structure_sectioning_util.h
@@ -88,9 +88,12 @@
 //   ------------------------------------------------------+-------------------
 //
 // c. `kAutofillSectioningModeExpand`: The conditions from above apply.
-//    Additionally, sections based on conditions 1 and 2 are propagated
-//    downwards to focusable or <select> fields, ignoring all the usual
-//    sectioning rules.
+//    Additionally, we look at gaps between fields with sections based on
+//    conditions 1 and 2. If the gap is enclosed by the same section, this
+//    section is expanded to all the fields inside the gap. If there are no such
+//    gaps, this mode degenerates to the regular sectioning algorithm.
+//    In the example below, the "Name" and "Country" fields between the last two
+//    credit card fields are affected.
 //
 //    Example:
 //   ------------------------------------------------------+-------------------
@@ -99,7 +102,7 @@
 //   Name:      <input id=1>                               | field 1 based
 //   Country:   <input id=2>                               | field 1 based
 //   Name:      <input id=3 autocomplete=”section-A name”> | A
-//   Street:    <input id=4>                               | A
+//   Street:    <input id=4>                               | field 1 based
 //   CC number: <input id=5>                               | field 5 based
 //   CC number: <input id=6 style="display:none">          | field 5 based
 //   Name:      <input id=7>                               | field 5 based
diff --git a/components/autofill/core/browser/form_structure_sectioning_util_unittest.cc b/components/autofill/core/browser/form_structure_sectioning_util_unittest.cc
index db13214..5d8eff52 100644
--- a/components/autofill/core/browser/form_structure_sectioning_util_unittest.cc
+++ b/components/autofill/core/browser/form_structure_sectioning_util_unittest.cc
@@ -202,8 +202,7 @@
                   Section::FromFieldIdentifier(*fields[0], frame_token_ids),
                   Section::FromAutocomplete(
                       {.section = fields[2]->parsed_autocomplete->section}),
-                  Section::FromAutocomplete(
-                      {.section = fields[2]->parsed_autocomplete->section}),
+                  Section::FromFieldIdentifier(*fields[0], frame_token_ids),
                   Section::FromFieldIdentifier(*fields[4], frame_token_ids),
                   Section::FromFieldIdentifier(*fields[4], frame_token_ids),
                   Section::FromFieldIdentifier(*fields[4], frame_token_ids),
diff --git a/components/autofill/core/browser/form_structure_unittest.cc b/components/autofill/core/browser/form_structure_unittest.cc
index 5ed7dcb0..900c183 100644
--- a/components/autofill/core/browser/form_structure_unittest.cc
+++ b/components/autofill/core/browser/form_structure_unittest.cc
@@ -5015,8 +5015,7 @@
             uploads.front().single_username_data().prompt_edit());
 }
 
-// Test that server predictions get precedence over htmll types if they are
-// overrides.
+// Test that server overrides get precedence over HTML types.
 TEST_F(FormStructureTestImpl, ParseQueryResponse_ServerPredictionIsOverride) {
   FormData form_data;
   FormFieldData field;
@@ -5042,77 +5041,38 @@
 
   std::string response_string = SerializeAndEncode(response);
 
-  // Disable the feature which gives overrides precedence.
-  {
-    base::test::ScopedFeatureList scoped_feature;
-    scoped_feature.InitAndDisableFeature(
-        features::kAutofillServerTypeTakesPrecedence);
+  // Parse the response and update the field type predictions.
+  FormStructure form(form_data);
+  form.DetermineHeuristicTypes(nullptr, nullptr);
+  std::vector<FormStructure*> forms{&form};
+  FormStructure::ParseApiQueryResponse(response_string, forms,
+                                       test::GetEncodedSignatures(forms),
+                                       nullptr, nullptr);
+  ASSERT_EQ(form.field_count(), 2U);
 
-    // Parse the response and update the field type predictions.
-    FormStructure form(form_data);
-    form.DetermineHeuristicTypes(nullptr, nullptr);
-    std::vector<FormStructure*> forms{&form};
-    FormStructure::ParseApiQueryResponse(response_string, forms,
-                                         test::GetEncodedSignatures(forms),
-                                         nullptr, nullptr);
-    ASSERT_EQ(form.field_count(), 2U);
+  // Validate the type predictions.
+  EXPECT_EQ(UNKNOWN_TYPE, form.field(0)->heuristic_type());
+  EXPECT_EQ(HtmlFieldType::kName, form.field(0)->html_type());
+  EXPECT_EQ(NAME_FIRST, form.field(0)->server_type());
+  EXPECT_EQ(UNKNOWN_TYPE, form.field(1)->heuristic_type());
+  EXPECT_EQ(HtmlFieldType::kName, form.field(1)->html_type());
+  EXPECT_EQ(NAME_LAST, form.field(1)->server_type());
 
-    // Validate the type predictions.
-    EXPECT_EQ(UNKNOWN_TYPE, form.field(0)->heuristic_type());
-    EXPECT_EQ(HtmlFieldType::kName, form.field(0)->html_type());
-    EXPECT_EQ(NAME_FIRST, form.field(0)->server_type());
-    EXPECT_EQ(UNKNOWN_TYPE, form.field(1)->heuristic_type());
-    EXPECT_EQ(HtmlFieldType::kName, form.field(1)->html_type());
-    EXPECT_EQ(NAME_LAST, form.field(1)->server_type());
+  // Validate that the overrides are set correctly.
+  EXPECT_TRUE(form.field(0)->server_type_prediction_is_override());
+  EXPECT_FALSE(form.field(1)->server_type_prediction_is_override());
 
-    // Validate that the overrides are set correctly.
-    EXPECT_TRUE(form.field(0)->server_type_prediction_is_override());
-    EXPECT_FALSE(form.field(1)->server_type_prediction_is_override());
+  // Validate that the server prediction won for the first field.
+  EXPECT_EQ(form.field(0)->Type().GetStorableType(), NAME_FIRST);
+  EXPECT_EQ(form.field(1)->Type().GetStorableType(), NAME_FULL);
 
-    // Validate that the html prediction won.
-    EXPECT_EQ(form.field(0)->Type().GetStorableType(), NAME_FULL);
-    EXPECT_EQ(form.field(1)->Type().GetStorableType(), NAME_FULL);
-  }
+  // Validate that the server override cannot be altered.
+  form.field(0)->SetTypeTo(AutofillType(NAME_FULL));
+  EXPECT_EQ(form.field(0)->Type().GetStorableType(), NAME_FIRST);
 
-  // Enable the feature to give overrides precedence.
-  {
-    base::test::ScopedFeatureList scoped_feature;
-    scoped_feature.InitAndEnableFeature(
-        features::kAutofillServerTypeTakesPrecedence);
-
-    // Parse the response and update the field type predictions.
-    FormStructure form(form_data);
-    form.DetermineHeuristicTypes(nullptr, nullptr);
-    std::vector<FormStructure*> forms{&form};
-    FormStructure::ParseApiQueryResponse(response_string, forms,
-                                         test::GetEncodedSignatures(forms),
-                                         nullptr, nullptr);
-    ASSERT_EQ(form.field_count(), 2U);
-
-    // Validate the type predictions.
-    EXPECT_EQ(UNKNOWN_TYPE, form.field(0)->heuristic_type());
-    EXPECT_EQ(HtmlFieldType::kName, form.field(0)->html_type());
-    EXPECT_EQ(NAME_FIRST, form.field(0)->server_type());
-    EXPECT_EQ(UNKNOWN_TYPE, form.field(1)->heuristic_type());
-    EXPECT_EQ(HtmlFieldType::kName, form.field(1)->html_type());
-    EXPECT_EQ(NAME_LAST, form.field(1)->server_type());
-
-    // Validate that the overrides are set correctly.
-    EXPECT_TRUE(form.field(0)->server_type_prediction_is_override());
-    EXPECT_FALSE(form.field(1)->server_type_prediction_is_override());
-
-    // Validate that the server prediction won for the first field.
-    EXPECT_EQ(form.field(0)->Type().GetStorableType(), NAME_FIRST);
-    EXPECT_EQ(form.field(1)->Type().GetStorableType(), NAME_FULL);
-
-    // Validate that the server override cannot be altered.
-    form.field(0)->SetTypeTo(AutofillType(NAME_FULL));
-    EXPECT_EQ(form.field(0)->Type().GetStorableType(), NAME_FIRST);
-
-    // Validate that that the non-override can be altered.
-    form.field(1)->SetTypeTo(AutofillType(NAME_FIRST));
-    EXPECT_EQ(form.field(1)->Type().GetStorableType(), NAME_FIRST);
-  }
+  // Validate that that the non-override can be altered.
+  form.field(1)->SetTypeTo(AutofillType(NAME_FIRST));
+  EXPECT_EQ(form.field(1)->Type().GetStorableType(), NAME_FIRST);
 }
 
 // Test the heuristic prediction for NAME_LAST_SECOND overrides server
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc
index 0b514e9..2482bb5 100644
--- a/components/autofill/core/browser/personal_data_manager.cc
+++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -1507,7 +1507,7 @@
 
   image_fetcher_->FetchImagesForUrls(
       updated_urls, base::BindOnce(&PersonalDataManager::OnCardArtImagesFetched,
-                                   weak_factory_.GetWeakPtr()));
+                                   weak_factory_.GetMutableWeakPtr()));
 }
 
 const std::string& PersonalDataManager::GetDefaultCountryCodeForNewAddress()
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc
index 703728af..9df33b8 100644
--- a/components/autofill/core/common/autofill_features.cc
+++ b/components/autofill/core/common/autofill_features.cc
@@ -370,13 +370,6 @@
              "AutofillHighlightOnlyChangedValuesInPreviewMode",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-// Controls if a server prediction with a prediction source |OVERRIDE| is
-// granted precedence over html type attributes.
-// TODO(crbug.com/1170384) Remove once launched
-BASE_FEATURE(kAutofillServerTypeTakesPrecedence,
-             "AutofillServerTypeTakesPrecedence",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 // When enabled, Autofill suggestions are displayed in the keyboard accessory
 // instead of the regular popup.
 BASE_FEATURE(kAutofillKeyboardAccessory,
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h
index 73558277..b4d19ccd 100644
--- a/components/autofill/core/common/autofill_features.h
+++ b/components/autofill/core/common/autofill_features.h
@@ -127,8 +127,6 @@
 BASE_DECLARE_FEATURE(kAutofillImprovedLabelForInference);
 COMPONENT_EXPORT(AUTOFILL)
 BASE_DECLARE_FEATURE(kAutofillHighlightOnlyChangedValuesInPreviewMode);
-COMPONENT_EXPORT(AUTOFILL)
-BASE_DECLARE_FEATURE(kAutofillServerTypeTakesPrecedence);
 COMPONENT_EXPORT(AUTOFILL) BASE_DECLARE_FEATURE(kAutofillKeyboardAccessory);
 COMPONENT_EXPORT(AUTOFILL) BASE_DECLARE_FEATURE(kAutofillLabelAffixRemoval);
 COMPONENT_EXPORT(AUTOFILL)
diff --git a/components/autofill_assistant/browser/basic_interactions.cc b/components/autofill_assistant/browser/basic_interactions.cc
index 3b2cdc6..92291c15 100644
--- a/components/autofill_assistant/browser/basic_interactions.cc
+++ b/components/autofill_assistant/browser/basic_interactions.cc
@@ -427,6 +427,20 @@
   return true;
 }
 
+bool ArrayLength(UserModel* user_model,
+                 const std::string& result_model_identifier,
+                 const ArrayLengthProto& proto) {
+  auto value = user_model->GetValue(proto.value());
+  if (!value.has_value()) {
+    DVLOG(2) << "Failed to find value in user model";
+    return false;
+  }
+  user_model->SetValue(
+      result_model_identifier,
+      SimpleValue(GetValueSize(*value), ContainsClientOnlyValue({*value})));
+  return true;
+}
+
 }  // namespace
 
 base::WeakPtr<BasicInteractions> BasicInteractions::GetWeakPtr() {
@@ -533,6 +547,15 @@
       }
       return StringEmpty(execution_delegate_->GetUserModel(),
                          proto.result_model_identifier(), proto.string_empty());
+    case ComputeValueProto::kArrayLength: {
+      if (!proto.array_length().has_value()) {
+        DVLOG(2)
+            << "Error computing ComputeValue::ArrayLength: no value specified";
+        return false;
+      }
+      return ArrayLength(execution_delegate_->GetUserModel(),
+                         proto.result_model_identifier(), proto.array_length());
+    }
     case ComputeValueProto::KIND_NOT_SET:
       DVLOG(2) << "Error computing value: kind not set";
       return false;
diff --git a/components/autofill_assistant/browser/basic_interactions_unittest.cc b/components/autofill_assistant/browser/basic_interactions_unittest.cc
index dc56b78..3782627 100644
--- a/components/autofill_assistant/browser/basic_interactions_unittest.cc
+++ b/components/autofill_assistant/browser/basic_interactions_unittest.cc
@@ -525,6 +525,38 @@
   EXPECT_TRUE(user_model_.GetValue("result")->is_client_side_only());
 }
 
+TEST_F(BasicInteractionsTest, ComputeValueArrayLength) {
+  ComputeValueProto proto;
+  proto.set_result_model_identifier("result");
+  proto.mutable_array_length();
+
+  // Missing fields.
+  EXPECT_FALSE(basic_interactions_.ComputeValue(proto));
+
+  // Add missing field, but |value| doesn't exist in |user_model_|
+  proto.mutable_array_length()->mutable_value()->set_model_identifier("value");
+  EXPECT_FALSE(basic_interactions_.ComputeValue(proto));
+
+  // Empty value
+  user_model_.SetValue("value", ValueProto());
+  EXPECT_TRUE(basic_interactions_.ComputeValue(proto));
+  EXPECT_EQ(user_model_.GetValue("result"), SimpleValue(0));
+
+  // Empty array
+  ValueProto value;
+  value.mutable_ints();
+  user_model_.SetValue("value", value);
+  EXPECT_TRUE(basic_interactions_.ComputeValue(proto));
+  EXPECT_EQ(user_model_.GetValue("result"), SimpleValue(0));
+
+  // Non-Empty array
+  value.mutable_ints()->add_values(5);
+  value.mutable_ints()->add_values(6);
+  user_model_.SetValue("value", value);
+  EXPECT_TRUE(basic_interactions_.ComputeValue(proto));
+  EXPECT_EQ(user_model_.GetValue("result"), SimpleValue(2));
+}
+
 TEST_F(BasicInteractionsTest, EndActionWithoutCallbackFails) {
   EndActionProto proto;
   EXPECT_FALSE(basic_interactions_.EndAction(ClientStatus(INVALID_ACTION)));
diff --git a/components/autofill_assistant/browser/generic_ui.proto b/components/autofill_assistant/browser/generic_ui.proto
index de5854c..0030ba2 100644
--- a/components/autofill_assistant/browser/generic_ui.proto
+++ b/components/autofill_assistant/browser/generic_ui.proto
@@ -139,6 +139,8 @@
     CreateLoginOptionResponseProto create_login_option_response = 9;
     // Check if a string value is empty.
     StringEmptyProto string_empty = 10;
+    // Writes the length of array model_identifier to the result.
+    ArrayLengthProto array_length = 11;
   }
 
   // The model identifier to write the result to.
@@ -250,6 +252,15 @@
   reserved 1, 2;
 }
 
+// Computes the length of a list |value|.
+// If |value| doesn't point to a list, e.g. if it points to
+// |credit_card_response|, we simply return 1.
+message ArrayLengthProto {
+  // |value| is a required field.
+  // If not present, |result_model_identifier| won't be written.
+  optional ValueReferenceProto value = 1;
+}
+
 // Creates a safe-to-transmit CreditCardResponseProto for the input |value|.
 message CreateCreditCardResponseProto {
   // The input CreditCardProto.
diff --git a/components/autofill_assistant/browser/generic_ui_replace_placeholders.cc b/components/autofill_assistant/browser/generic_ui_replace_placeholders.cc
index a6146a0..07a47bd3 100644
--- a/components/autofill_assistant/browser/generic_ui_replace_placeholders.cc
+++ b/components/autofill_assistant/browser/generic_ui_replace_placeholders.cc
@@ -334,6 +334,14 @@
                                        placeholders);
           }
           return;
+        case ComputeValueProto::kArrayLength:
+          if (in_out_proto->compute_value().array_length().has_value()) {
+            ReplacePlaceholdersInValue(in_out_proto->mutable_compute_value()
+                                           ->mutable_array_length()
+                                           ->mutable_value(),
+                                       placeholders);
+          }
+          return;
         case ComputeValueProto::KIND_NOT_SET:
           return;
       }
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/FourStateCookieSettingsPreference.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/FourStateCookieSettingsPreference.java
index e5a27c1..8f9fa932 100644
--- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/FourStateCookieSettingsPreference.java
+++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/FourStateCookieSettingsPreference.java
@@ -82,6 +82,11 @@
     private RadioGroup mRadioGroup;
     private TextViewWithCompoundDrawables mManagedView;
 
+    // Sometimes UI is initialized before the initializationParams are set. We keep this viewHolder
+    // to properly adjust UI once initializationParams are set. See crbug.com/1371236.
+    // TODO(tommasin) Remove this holder once the FirstPartySets UI will be enabled by default.
+    private PreferenceViewHolder mViewHolder;
+
     public FourStateCookieSettingsPreference(Context context, AttributeSet attrs) {
         super(context, attrs);
 
@@ -98,6 +103,7 @@
      */
     public void setState(Params state) {
         if (mRadioGroup != null) {
+            setRadioButtonsVisibility(state);
             configureRadioButtons(state);
         } else {
             mInitializationParams = state;
@@ -138,33 +144,8 @@
     public void onBindViewHolder(PreferenceViewHolder holder) {
         super.onBindViewHolder(holder);
 
+        mViewHolder = holder;
         mAllowButton = (RadioButtonWithDescription) holder.findViewById(R.id.allow);
-
-        if (mInitializationParams.isPrivacySandboxFirstPartySetsUIEnabled) {
-            holder.findViewById(R.id.block_third_party_incognito).setVisibility(View.GONE);
-            holder.findViewById(R.id.block_third_party).setVisibility(View.GONE);
-            mBlockThirdPartyIncognitoButton =
-                    (RadioButtonWithDescriptionAndAuxButton) holder.findViewById(
-                            R.id.block_third_party_incognito_with_aux);
-            mBlockThirdPartyButton = (RadioButtonWithDescriptionAndAuxButton) holder.findViewById(
-                    R.id.block_third_party_with_aux);
-            mBlockThirdPartyIncognitoButton.setVisibility(View.VISIBLE);
-            mBlockThirdPartyButton.setVisibility(View.VISIBLE);
-            setBlockThirdPartyCookieDescription();
-            // TODO(crbug.com/1349370): Change the buttons class into a
-            // RadioButtonWithDescriptionAndAuxButton and remove the following casts when the
-            // PrivacySandboxFirstPartySetsUI feature is launched
-            ((RadioButtonWithDescriptionAndAuxButton) mBlockThirdPartyIncognitoButton)
-                    .setAuxButtonClickedListener(this);
-            ((RadioButtonWithDescriptionAndAuxButton) mBlockThirdPartyButton)
-                    .setAuxButtonClickedListener(this);
-        } else {
-            mBlockThirdPartyIncognitoButton = (RadioButtonWithDescription) holder.findViewById(
-                    R.id.block_third_party_incognito);
-            mBlockThirdPartyButton =
-                    (RadioButtonWithDescription) holder.findViewById(R.id.block_third_party);
-        }
-
         mBlockButton = (RadioButtonWithDescription) holder.findViewById(R.id.block);
         mRadioGroup = (RadioGroup) holder.findViewById(R.id.radio_button_layout);
         mRadioGroup.setOnCheckedChangeListener(this);
@@ -177,15 +158,44 @@
                 managedIcon, drawables[1], drawables[2], drawables[3]);
 
         if (mInitializationParams != null) {
+            setRadioButtonsVisibility(mInitializationParams);
             configureRadioButtons(mInitializationParams);
         }
     }
 
-    private void setBlockThirdPartyCookieDescription() {
+    private void setRadioButtonsVisibility(Params params) {
+        if (params.isPrivacySandboxFirstPartySetsUIEnabled) {
+            mViewHolder.findViewById(R.id.block_third_party_incognito).setVisibility(View.GONE);
+            mViewHolder.findViewById(R.id.block_third_party).setVisibility(View.GONE);
+            mBlockThirdPartyIncognitoButton =
+                    (RadioButtonWithDescriptionAndAuxButton) mViewHolder.findViewById(
+                            R.id.block_third_party_incognito_with_aux);
+            mBlockThirdPartyButton =
+                    (RadioButtonWithDescriptionAndAuxButton) mViewHolder.findViewById(
+                            R.id.block_third_party_with_aux);
+            mBlockThirdPartyIncognitoButton.setVisibility(View.VISIBLE);
+            mBlockThirdPartyButton.setVisibility(View.VISIBLE);
+            setBlockThirdPartyCookieDescription(params);
+            // TODO(crbug.com/1349370): Change the buttons class into a
+            // RadioButtonWithDescriptionAndAuxButton and remove the following casts when the
+            // PrivacySandboxFirstPartySetsUI feature is launched
+            ((RadioButtonWithDescriptionAndAuxButton) mBlockThirdPartyIncognitoButton)
+                    .setAuxButtonClickedListener(this);
+            ((RadioButtonWithDescriptionAndAuxButton) mBlockThirdPartyButton)
+                    .setAuxButtonClickedListener(this);
+        } else {
+            mBlockThirdPartyIncognitoButton = (RadioButtonWithDescription) mViewHolder.findViewById(
+                    R.id.block_third_party_incognito);
+            mBlockThirdPartyButton =
+                    (RadioButtonWithDescription) mViewHolder.findViewById(R.id.block_third_party);
+        }
+    }
+
+    private void setBlockThirdPartyCookieDescription(Params params) {
         Resources resources = getContext().getResources();
         String defaultDescription = resources.getString(
                 R.string.website_settings_category_cookie_block_third_party_addition);
-        if (mInitializationParams.isFirstPartySetsDataAccessEnabled) {
+        if (params.isFirstPartySetsDataAccessEnabled) {
             String fpsAdditionalDescription = resources.getString(
                     R.string.website_settings_category_cookie_block_third_party_fps_addition);
             String description = resources.getString(R.string.concat_two_strings_with_periods,
diff --git a/components/content_settings/core/common/content_settings_pattern.cc b/components/content_settings/core/common/content_settings_pattern.cc
index 10f1ee7..84e5ec93 100644
--- a/components/content_settings/core/common/content_settings_pattern.cc
+++ b/components/content_settings/core/common/content_settings_pattern.cc
@@ -582,6 +582,11 @@
   return parts_.has_domain_wildcard && parts_.host.empty();
 }
 
+bool ContentSettingsPattern::MatchesSingleOrigin() const {
+  return !parts_.is_scheme_wildcard && !parts_.has_domain_wildcard &&
+         !parts_.is_port_wildcard && !parts_.is_path_wildcard;
+}
+
 bool ContentSettingsPattern::HasDomainWildcard() const {
   return parts_.has_domain_wildcard && !parts_.host.empty();
 }
diff --git a/components/content_settings/core/common/content_settings_pattern.h b/components/content_settings/core/common/content_settings_pattern.h
index e57470c..9fb7d2bd 100644
--- a/components/content_settings/core/common/content_settings_pattern.h
+++ b/components/content_settings/core/common/content_settings_pattern.h
@@ -211,6 +211,10 @@
   // True if this pattern matches all hosts (i.e. it has a host wildcard).
   bool MatchesAllHosts() const;
 
+  // True if this pattern matches a single origin (i.e. it's the narrowest kind
+  // of a pattern, with no wildcards).
+  bool MatchesSingleOrigin() const;
+
   // True if this pattern has domain wildcard.
   bool HasDomainWildcard() const;
 
diff --git a/components/content_settings/core/common/content_settings_pattern_unittest.cc b/components/content_settings/core/common/content_settings_pattern_unittest.cc
index 6bf1d9e..5a022db8 100644
--- a/components/content_settings/core/common/content_settings_pattern_unittest.cc
+++ b/components/content_settings/core/common/content_settings_pattern_unittest.cc
@@ -915,3 +915,26 @@
   EXPECT_TRUE(Pattern("file:///foo/bar/").HasPath());
   EXPECT_TRUE(Pattern("file:///foo/bar/test.html").HasPath());
 }
+
+TEST(ContentSettingsPatternTest, MatchesSingleOrigin) {
+  EXPECT_FALSE(Pattern("*").MatchesSingleOrigin());
+  EXPECT_FALSE(Pattern("*://example.com:443").MatchesSingleOrigin());
+  EXPECT_FALSE(Pattern("https://[*.]example.com:443").MatchesSingleOrigin());
+  EXPECT_FALSE(Pattern("https://example.com:*").MatchesSingleOrigin());
+  EXPECT_FALSE(Pattern("*://[*.]example.com:*").MatchesSingleOrigin());
+  EXPECT_FALSE(Pattern("https://*").MatchesSingleOrigin());
+  EXPECT_FALSE(Pattern("file:///*").MatchesSingleOrigin());
+
+  EXPECT_TRUE(Pattern("https://example.com:443").MatchesSingleOrigin());
+  EXPECT_TRUE(Pattern("file:///foo/bar/example.txt").MatchesSingleOrigin());
+
+  // URL conversion.
+  EXPECT_FALSE(ContentSettingsPattern::FromURL(GURL("https://example.com"))
+                   .MatchesSingleOrigin());
+  EXPECT_TRUE(
+      ContentSettingsPattern::FromURLNoWildcard(GURL("https://example.com"))
+          .MatchesSingleOrigin());
+  EXPECT_TRUE(
+      ContentSettingsPattern::FromURL(GURL("file:///foo/bar/example.txt"))
+          .MatchesSingleOrigin());
+}
diff --git a/components/content_settings/core/common/content_settings_utils.cc b/components/content_settings/core/common/content_settings_utils.cc
index 22c25ff..276eaf5 100644
--- a/components/content_settings/core/common/content_settings_utils.cc
+++ b/components/content_settings/core/common/content_settings_utils.cc
@@ -58,13 +58,11 @@
   return base::Value::FromUniquePtrValue(std::move(value));
 }
 
-// Whether |pattern| applies to a single origin.
 bool PatternAppliesToSingleOrigin(
     const ContentSettingsPattern& primary_pattern,
     const ContentSettingsPattern& secondary_pattern) {
-  const GURL url(primary_pattern.ToString());
   // Default settings and other patterns apply to multiple origins.
-  if (url::Origin::Create(url).opaque())
+  if (!primary_pattern.MatchesSingleOrigin())
     return false;
   // Embedded content settings only match when |url| is embedded in another
   // origin, so ignore non-wildcard secondary patterns.
diff --git a/components/domain_reliability/features.cc b/components/domain_reliability/features.cc
index ffebba8..0adbd52d 100644
--- a/components/domain_reliability/features.cc
+++ b/components/domain_reliability/features.cc
@@ -7,10 +7,9 @@
 namespace domain_reliability {
 namespace features {
 
-DOMAIN_RELIABILITY_EXPORT extern const base::Feature
-    kPartitionDomainReliabilityByNetworkIsolationKey{
-        "PartitionDomainReliabilityByNetworkIsolationKey",
-        base::FEATURE_ENABLED_BY_DEFAULT};
+DOMAIN_RELIABILITY_EXPORT BASE_FEATURE(kPartitionDomainReliabilityByNetworkIsolationKey,
+                                       "PartitionDomainReliabilityByNetworkIsolationKey",
+                                       base::FEATURE_ENABLED_BY_DEFAULT);
 
 }  // namespace features
 }  // namespace domain_reliability
diff --git a/components/domain_reliability/features.h b/components/domain_reliability/features.h
index c396a3e..64dc5fe 100644
--- a/components/domain_reliability/features.h
+++ b/components/domain_reliability/features.h
@@ -12,8 +12,7 @@
 namespace features {
 
 // Partitions Domain Reliability beacons and upload by NetworkIsolationKey.
-DOMAIN_RELIABILITY_EXPORT extern const base::Feature
-    kPartitionDomainReliabilityByNetworkIsolationKey;
+DOMAIN_RELIABILITY_EXPORT BASE_DECLARE_FEATURE(kPartitionDomainReliabilityByNetworkIsolationKey);
 
 }  // namespace features
 }  // namespace domain_reliability
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index bb8726f..aa7f3c2 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -27096,7 +27096,7 @@
         'type': 'array',
         'items': { 'type': 'string' },
       },
-      'example_value': ['https://example1.com', 'https://[*.]example2.com', 'https://foo.example3.com/path'],
+      'example_value': ['https://example1.com', 'example2.com', 'https://foo.example3.com/path'],
       'features': {
         'per_profile': True,
         'dynamic_refresh': True,
@@ -27105,19 +27105,18 @@
       'id': 826,
       'caption': '''Enable attestation flow for a list of URLs''',
       'tags': [],
+      # TODO(b:252749979): Change URL blocklist filter format URL to help center article.
       'desc': '''Enable <ph name="CHROME_ENTERPRISE_PLATFORM_IDENTITY_CONNECTOR">Chrome Enterprise Platform Identity Connector</ph> for a list of URLs.
 
       Setting this policy specifies which URLs should be allowed to be part of the attestation flow to get the set of signals from the machine.
 
       Leaving this policy unset or empty means that no endpoint will be able to start the attestation flow nor get signals from the machine.
 
-      URLs must have HTTPS scheme, e.g. "https://example.com".
-
       Note: Wildcards, <ph name="WILDCARD_VALUE">*</ph>, are allowed.
 
       For ChromeOS, this policy is related to remote attestation where a certificate is automatically generated and uploaded to the Device Management Server.
 
-      For detailed information on valid <ph name="URL_LABEL">URL</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.''',
+      For detailed information on valid <ph name="URL_LABEL">URL</ph> patterns, please see https://www.chromium.org/administrators/url-blocklist-filter-format.''',
     },
     {
       'name': 'DeviceLoginScreenContextAwareAccessSignalsAllowlist',
@@ -27129,7 +27128,7 @@
         'type': 'array',
         'items': { 'type': 'string' },
       },
-      'example_value': ['https://example1.com', 'https://[*.]example2.com', 'https://foo.example3.com/path'],
+      'example_value': ['https://example1.com', 'example2.com', 'https://foo.example3.com/path'],
       'features': {
         'dynamic_refresh': True,
         'cloud_only': True,
@@ -27143,13 +27142,11 @@
 
       Leaving this policy unset or empty means that no endpoint will be able to start the attestation flow nor get signals from the machine.
 
-      URLs must have HTTPS scheme, e.g. "https://example.com".
-
       Note: Wildcards, <ph name="WILDCARD_VALUE">*</ph>, are allowed.
 
       This policy will only impact the attestation flow on the login and lock screen. To change the in-session attestation flow, please use the <ph name="CONTEXT_AWARE_ACCESS_SIGNALS_ALLOWLIST_POLICY_NAME">ContextAwareAccessSignalsAllowlist</ph> policy.
 
-      For detailed information on valid <ph name="URL_LABEL">URL</ph> patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.''',
+      For detailed information on valid <ph name="URL_LABEL">URL</ph> patterns, please see https://www.chromium.org/administrators/url-blocklist-filter-format.''',
     },
     {
       'name': 'DeviceQuickFixBuildToken',
diff --git a/components/safe_browsing/core/common/features.cc b/components/safe_browsing/core/common/features.cc
index 52eba8b..fd80aba 100644
--- a/components/safe_browsing/core/common/features.cc
+++ b/components/safe_browsing/core/common/features.cc
@@ -92,7 +92,7 @@
 
 BASE_FEATURE(kEnhancedProtectionPhase2IOS,
              "SafeBrowsingEnhancedProtectionPhase2IOS",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 BASE_FEATURE(kExtensionTelemetry,
              "SafeBrowsingExtensionTelemetry",
diff --git a/components/signin/public/base/signin_metrics.cc b/components/signin/public/base/signin_metrics.cc
index 48decc87..201075a8 100644
--- a/components/signin/public/base/signin_metrics.cc
+++ b/components/signin/public/base/signin_metrics.cc
@@ -400,6 +400,7 @@
     case AccessPoint::ACCESS_POINT_ACCOUNT_RENAMED:
     case AccessPoint::ACCESS_POINT_WEB_SIGNIN:
     case AccessPoint::ACCESS_POINT_SETTINGS_SYNC_OFF_ROW:
+    case AccessPoint::ACCESS_POINT_POST_DEVICE_RESTORE_BACKGROUND_SIGNIN:
       NOTREACHED() << "Access point " << static_cast<int>(access_point)
                    << " is not supposed to log signin user actions.";
       break;
@@ -526,6 +527,7 @@
     case AccessPoint::ACCESS_POINT_SAFETY_CHECK:
     case AccessPoint::ACCESS_POINT_SIGNIN_INTERCEPT_FIRST_RUN_EXPERIENCE:
     case AccessPoint::ACCESS_POINT_SETTINGS_SYNC_OFF_ROW:
+    case AccessPoint::ACCESS_POINT_POST_DEVICE_RESTORE_BACKGROUND_SIGNIN:
       NOTREACHED() << "Signin_Impression_From* user actions"
                    << " are not recorded for access point "
                    << static_cast<int>(access_point);
diff --git a/components/signin/public/base/signin_metrics.h b/components/signin/public/base/signin_metrics.h
index ad2559d..76d3b2ba 100644
--- a/components/signin/public/base/signin_metrics.h
+++ b/components/signin/public/base/signin_metrics.h
@@ -190,6 +190,7 @@
   ACCESS_POINT_NTP_FEED_TOP_PROMO = 37,
   ACCESS_POINT_SETTINGS_SYNC_OFF_ROW = 38,
   ACCESS_POINT_POST_DEVICE_RESTORE_SIGNIN_PROMO = 39,
+  ACCESS_POINT_POST_DEVICE_RESTORE_BACKGROUND_SIGNIN = 40,
   // Add values above this line with a corresponding label to the
   // "SigninAccessPoint" enum in tools/metrics/histograms/enums.xml
   ACCESS_POINT_MAX,  // This must be last.
diff --git a/components/signin/public/base/signin_metrics_unittest.cc b/components/signin/public/base/signin_metrics_unittest.cc
index 41da8bfb..9c4ac06 100644
--- a/components/signin/public/base/signin_metrics_unittest.cc
+++ b/components/signin/public/base/signin_metrics_unittest.cc
@@ -63,19 +63,6 @@
     AccessPoint::ACCESS_POINT_NTP_FEED_TOP_PROMO,
     AccessPoint::ACCESS_POINT_POST_DEVICE_RESTORE_SIGNIN_PROMO};
 
-const AccessPoint kAccessPointsThatSupportPersonalizedPromos[] = {
-    AccessPoint::ACCESS_POINT_BOOKMARK_MANAGER,
-    AccessPoint::ACCESS_POINT_RECENT_TABS,
-    AccessPoint::ACCESS_POINT_SETTINGS,
-    AccessPoint::ACCESS_POINT_TAB_SWITCHER,
-    AccessPoint::ACCESS_POINT_EXTENSION_INSTALL_BUBBLE,
-    AccessPoint::ACCESS_POINT_AVATAR_BUBBLE_SIGN_IN,
-    AccessPoint::ACCESS_POINT_PASSWORD_BUBBLE,
-    AccessPoint::ACCESS_POINT_BOOKMARK_BUBBLE,
-    AccessPoint::ACCESS_POINT_NTP_CONTENT_SUGGESTIONS,
-    AccessPoint::ACCESS_POINT_NTP_FEED_TOP_PROMO,
-    AccessPoint::ACCESS_POINT_POST_DEVICE_RESTORE_SIGNIN_PROMO};
-
 class SigninMetricsTest : public ::testing::Test {
  public:
   static std::string GetAccessPointDescription(AccessPoint access_point) {
@@ -152,6 +139,8 @@
         return "SettingsSyncOffRow";
       case AccessPoint::ACCESS_POINT_POST_DEVICE_RESTORE_SIGNIN_PROMO:
         return "PostDeviceRestoreSigninPromo";
+      case AccessPoint::ACCESS_POINT_POST_DEVICE_RESTORE_BACKGROUND_SIGNIN:
+        return "PostDeviceRestoreBackgroundSignin";
       case AccessPoint::ACCESS_POINT_MAX:
         NOTREACHED();
         return "";
@@ -159,11 +148,6 @@
     NOTREACHED();
     return "";
   }
-
-  static bool AccessPointSupportsPersonalizedPromo(AccessPoint access_point) {
-    return base::Contains(kAccessPointsThatSupportPersonalizedPromos,
-                          access_point);
-  }
 };
 
 TEST_F(SigninMetricsTest, RecordSigninUserActionForAccessPoint) {
diff --git a/components/sync/driver/sync_user_settings.h b/components/sync/driver/sync_user_settings.h
index 8f1e9d8..a5e3285 100644
--- a/components/sync/driver/sync_user_settings.h
+++ b/components/sync/driver/sync_user_settings.h
@@ -27,7 +27,8 @@
   ADVANCED_FLOW_INTERRUPTED_TURN_SYNC_ON = 2,
   ADVANCED_FLOW_INTERRUPTED_LEAVE_SYNC_OFF = 3,
   ENGINE_INITIALIZED_WITH_AUTO_START = 4,
-  kMaxValue = ENGINE_INITIALIZED_WITH_AUTO_START,
+  ANDROID_BACKUP_RESTORE = 5,
+  kMaxValue = ANDROID_BACKUP_RESTORE,
 };
 
 // This class encapsulates all the user-configurable bits of Sync.
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 2f8c0be..28a7e2b1 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -1117,6 +1117,15 @@
   BrowserCompositorMac::DisableRecyclingForShutdown();
 #endif
 
+#if defined(USE_AURA)
+  if (env_) {
+    // ContextFactory is owned by ImageTransportFactory, which will delete the
+    // object in the `Terminate` call below. We need to make sure aura::Env
+    // doesn't reference it anymore when that happens.
+    env_->set_context_factory(nullptr);
+  }
+#endif
+
 #if defined(USE_AURA) || BUILDFLAG(IS_MAC)
   {
     TRACE_EVENT0("shutdown",
diff --git a/content/browser/network/network_quality_observer_impl.cc b/content/browser/network/network_quality_observer_impl.cc
index c390032..3431bf42 100644
--- a/content/browser/network/network_quality_observer_impl.cc
+++ b/content/browser/network/network_quality_observer_impl.cc
@@ -63,14 +63,14 @@
 }
 
 NetworkQualityObserverImpl::~NetworkQualityObserverImpl() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   network_quality_tracker_->RemoveRTTAndThroughputEstimatesObserver(this);
   network_quality_tracker_->RemoveEffectiveConnectionTypeObserver(this);
 }
 
 void NetworkQualityObserverImpl::OnEffectiveConnectionTypeChanged(
     net::EffectiveConnectionType type) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   if (last_notified_type_ == type)
     return;
@@ -91,7 +91,7 @@
 
 void NetworkQualityObserverImpl::OnRenderProcessHostCreated(
     content::RenderProcessHost* rph) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   // Notify the newly created renderer of the current network quality.
   rph->GetRendererInterface()->OnNetworkQualityChanged(
@@ -104,7 +104,7 @@
     base::TimeDelta http_rtt,
     base::TimeDelta transport_rtt,
     int32_t downstream_throughput_kbps) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   // Check if any of the network quality metrics changed meaningfully.
   bool http_rtt_changed = MetricChangedMeaningfully(
diff --git a/content/browser/network/network_quality_observer_impl.h b/content/browser/network/network_quality_observer_impl.h
index 5d2bb8c..8a1fc83d 100644
--- a/content/browser/network/network_quality_observer_impl.h
+++ b/content/browser/network/network_quality_observer_impl.h
@@ -56,7 +56,7 @@
   net::EffectiveConnectionType last_notified_type_;
   net::nqe::internal::NetworkQuality last_notified_network_quality_;
 
-  base::ThreadChecker thread_checker_;
+  THREAD_CHECKER(thread_checker_);
 };
 
 }  // namespace content
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc
index a75904b9..d688d25f 100644
--- a/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -389,16 +389,20 @@
 
 // Returns MediaStreamDevices for getDisplayMedia() calls.
 // Returns a video device built with DesktopMediaID with fake initializers if
-// |kUseFakeDeviceForMediaStream| is set. Returns a video device with
-// default DesktopMediaID otherwise.
+// |kUseFakeDeviceForMediaStream| is set and |preferred_display_surface| is no
+// preference. Otherwise, if |preferred_display_surface| specifies a screen,
+// window, or tab, returns a video device with matching DesktopMediaID. Returns
+// a video device with default DesktopMediaID otherwise.
 // Returns an audio device with default device parameters.
-// If |kUseFakeDeviceForMediaStream| specifies a browser window, use
-// |render_process_id| and |render_frame_id| as the browser window identifier.
+// If |kUseFakeDeviceForMediaStream| specifies a
+// browser window, use |render_process_id| and |render_frame_id| as the browser
+// window identifier.
 MediaStreamDevices DisplayMediaDevicesFromFakeDeviceConfig(
     blink::mojom::MediaStreamType media_type,
     bool request_audio,
     int render_process_id,
-    int render_frame_id) {
+    int render_frame_id,
+    blink::mojom::PreferredDisplaySurface preferred_display_surface) {
   MediaStreamDevices devices;
   DesktopMediaID::Type desktop_media_type = DesktopMediaID::TYPE_SCREEN;
   DesktopMediaID::Id desktop_media_id_id = DesktopMediaID::kNullId;
@@ -436,6 +440,23 @@
       }
     }
   }
+  switch (preferred_display_surface) {
+    case blink::mojom::PreferredDisplaySurface::NO_PREFERENCE:
+      break;
+    case blink::mojom::PreferredDisplaySurface::MONITOR:
+      desktop_media_type = DesktopMediaID::TYPE_SCREEN;
+      display_surface = media::mojom::DisplayCaptureSurfaceType::MONITOR;
+      break;
+    case blink::mojom::PreferredDisplaySurface::WINDOW:
+      desktop_media_type = DesktopMediaID::TYPE_WINDOW;
+      display_surface = media::mojom::DisplayCaptureSurfaceType::WINDOW;
+      break;
+    case blink::mojom::PreferredDisplaySurface::BROWSER:
+      desktop_media_type = DesktopMediaID::TYPE_WEB_CONTENTS;
+      display_surface = media::mojom::DisplayCaptureSurfaceType::BROWSER;
+      web_contents_id = {render_process_id, render_frame_id};
+      break;
+  }
   DesktopMediaID media_id(desktop_media_type, desktop_media_id_id,
                           web_contents_id);
   MediaStreamDevice device(media_type, media_id.ToString(),
@@ -4049,7 +4070,8 @@
     devices = DisplayMediaDevicesFromFakeDeviceConfig(
         request->video_type(),
         request->audio_type() == MediaStreamType::DISPLAY_AUDIO_CAPTURE,
-        request->requesting_process_id, request->requesting_frame_id);
+        request->requesting_process_id, request->requesting_frame_id,
+        request->controls.preferred_display_surface);
   } else if (request->video_type() ==
              MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE) {
     // Cache the |label| in the device name field, for unit test purpose only.
diff --git a/content/browser/tracing/startup_tracing_browsertest.cc b/content/browser/tracing/startup_tracing_browsertest.cc
index 7525dfaa..3df52ef 100644
--- a/content/browser/tracing/startup_tracing_browsertest.cc
+++ b/content/browser/tracing/startup_tracing_browsertest.cc
@@ -363,7 +363,8 @@
   CheckOutput(GetExpectedPath(), GetOutputType());
 }
 
-IN_PROC_BROWSER_TEST_P(EmergencyStopTracingTest, StopOnThreadPool) {
+// Flaky: crbug.com/1372387
+IN_PROC_BROWSER_TEST_P(EmergencyStopTracingTest, DISABLED_StopOnThreadPool) {
   EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl("", "title1.html")));
 
   auto expected_path = GetExpectedPath();
@@ -380,7 +381,8 @@
   run_loop.Run();
 }
 
-IN_PROC_BROWSER_TEST_P(EmergencyStopTracingTest, StopOnThreadPoolTwice) {
+// Flaky: crbug.com/1372387
+IN_PROC_BROWSER_TEST_P(EmergencyStopTracingTest, DISABLED_StopOnThreadPoolTwice) {
   EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl("", "title1.html")));
 
   auto expected_path = GetExpectedPath();
diff --git a/content/renderer/pepper/pepper_media_stream_video_track_host.cc b/content/renderer/pepper/pepper_media_stream_video_track_host.cc
index 9e587e90..c2bec6c 100644
--- a/content/renderer/pepper/pepper_media_stream_video_track_host.cc
+++ b/content/renderer/pepper/pepper_media_stream_video_track_host.cc
@@ -444,7 +444,7 @@
       host_->frame_deliverer_ = nullptr;
   }
 
-  base::WeakPtr<MediaStreamVideoSource> GetWeakPtr() const final {
+  base::WeakPtr<MediaStreamVideoSource> GetWeakPtr() final {
     return weak_factory_.GetWeakPtr();
   }
 
diff --git a/device/bluetooth/bluetooth_device.cc b/device/bluetooth/bluetooth_device.cc
index 7b95372..c13b7de 100644
--- a/device/bluetooth/bluetooth_device.cc
+++ b/device/bluetooth/bluetooth_device.cc
@@ -595,18 +595,22 @@
 
     target_service_.reset();
 
-    for (auto& callback : create_gatt_connection_callbacks_)
+    // Callbacks may call back into this code. Move the callback list onto the
+    // stack to avoid potential re-entrancy bugs.
+    auto callbacks = std::move(create_gatt_connection_callbacks_);
+    for (auto& callback : callbacks)
       std::move(callback).Run(/*connection=*/nullptr, error.value());
-    create_gatt_connection_callbacks_.clear();
     return;
   }
 
-  for (auto& callback : create_gatt_connection_callbacks_) {
+  // Callbacks may call back into this code. Move the callback list onto the
+  // stack to avoid potential re-entrancy bugs.
+  auto callbacks = std::move(create_gatt_connection_callbacks_);
+  for (auto& callback : callbacks) {
     std::move(callback).Run(CreateBluetoothGattConnectionObject(),
                             /*error_code=*/absl::nullopt);
   }
 
-  create_gatt_connection_callbacks_.clear();
   GetAdapter()->NotifyDeviceChanged(this);
 }
 
diff --git a/device/bluetooth/bluetooth_device.h b/device/bluetooth/bluetooth_device.h
index 6372c3f..c2869b01 100644
--- a/device/bluetooth/bluetooth_device.h
+++ b/device/bluetooth/bluetooth_device.h
@@ -695,6 +695,7 @@
  protected:
   // BluetoothGattConnection is a friend to call Add/RemoveGattConnection.
   friend BluetoothGattConnection;
+  FRIEND_TEST_ALL_PREFIXES(BluetoothDeviceTest, GattConnectionErrorReentrancy);
   FRIEND_TEST_ALL_PREFIXES(
       BluetoothTest,
       BluetoothGattConnection_DisconnectGatt_SimulateConnect);
diff --git a/device/bluetooth/bluetooth_device_unittest.cc b/device/bluetooth/bluetooth_device_unittest.cc
index 8286286..c3fc1eb6 100644
--- a/device/bluetooth/bluetooth_device_unittest.cc
+++ b/device/bluetooth/bluetooth_device_unittest.cc
@@ -17,6 +17,8 @@
 #include "build/build_config.h"
 #include "device/bluetooth/bluetooth_remote_gatt_service.h"
 #include "device/bluetooth/public/cpp/bluetooth_address.h"
+#include "device/bluetooth/test/mock_bluetooth_adapter.h"
+#include "device/bluetooth/test/mock_bluetooth_device.h"
 #include "device/bluetooth/test/mock_pairing_delegate.h"
 #include "device/bluetooth/test/test_bluetooth_adapter_observer.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -41,6 +43,7 @@
 namespace {
 
 using ::testing::_;
+using ::testing::Return;
 using ::testing::StrictMock;
 
 int8_t ToInt8(BluetoothTest::TestRSSI rssi) {
@@ -135,6 +138,56 @@
   }
 }
 
+TEST(BluetoothDeviceTest, GattConnectionErrorReentrancy) {
+  constexpr char kTestDeviceAddress[] = "00:11:22:33:44:55";
+
+  auto adapter = base::MakeRefCounted<MockBluetoothAdapter>();
+  MockBluetoothDevice device(adapter.get(),
+                             /*bluetooth_class=*/0, "Test Device",
+                             kTestDeviceAddress,
+                             /*initially_paired=*/false,
+                             /*connected=*/false);
+
+  EXPECT_CALL(*adapter, GetDevice(kTestDeviceAddress))
+      .WillRepeatedly(Return(&device));
+
+  EXPECT_CALL(device, CreateGattConnection(_, _))
+      .Times(2)
+      .WillRepeatedly([&](BluetoothDevice::GattConnectionCallback callback,
+                          absl::optional<BluetoothUUID> service_uuid) {
+        device.BluetoothDevice::CreateGattConnection(std::move(callback),
+                                                     service_uuid);
+      });
+  EXPECT_CALL(device, CreateGattConnectionImpl(_))
+      .WillOnce([&](absl::optional<BluetoothUUID> service_uuid) {
+        device.DidConnectGatt(BluetoothDevice::ConnectErrorCode::ERROR_FAILED);
+      });
+  EXPECT_CALL(device, IsGattConnected())
+      .WillOnce(Return(false))
+      .WillOnce(Return(true));
+
+  // Trigger potential re-entrancy problems by calling CreateGattConnection()
+  // from within the callback passed to CreateGattConnection().
+  device.CreateGattConnection(
+      base::BindLambdaForTesting(
+          [&](std::unique_ptr<BluetoothGattConnection> connection,
+              absl::optional<BluetoothDevice::ConnectErrorCode> error_code) {
+            EXPECT_FALSE(connection);
+            EXPECT_EQ(error_code,
+                      BluetoothDevice::ConnectErrorCode::ERROR_FAILED);
+            device.CreateGattConnection(
+                base::BindLambdaForTesting(
+                    [&](std::unique_ptr<BluetoothGattConnection> connection,
+                        absl::optional<BluetoothDevice::ConnectErrorCode>
+                            error_code) {
+                      EXPECT_TRUE(connection);
+                      EXPECT_FALSE(error_code);
+                    }),
+                /*service_uuid=*/absl::nullopt);
+          }),
+      /*service_uuid=*/absl::nullopt);
+}
+
 #if BUILDFLAG(IS_WIN)
 TEST_P(BluetoothTestWinrtOnly, DeviceIsPaired) {
   if (!PlatformSupportsLowEnergy()) {
diff --git a/gpu/command_buffer/service/context_state.h b/gpu/command_buffer/service/context_state.h
index 276eeb4..44d2494 100644
--- a/gpu/command_buffer/service/context_state.h
+++ b/gpu/command_buffer/service/context_state.h
@@ -422,8 +422,8 @@
   // vector<[x,y,w,h]>. Always has space for MAX_WINDOW_RECTANGLES rectangles.
   std::vector<GLint> window_rectangles_;
 
-  raw_ptr<gl::GLApi> api_ = nullptr;
-  raw_ptr<FeatureInfo> feature_info_;
+  raw_ptr<gl::GLApi, DanglingUntriaged> api_ = nullptr;
+  raw_ptr<FeatureInfo, DanglingUntriaged> feature_info_;
 
   bool context_lost_ = false;
 };
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 0599d98a..0f2fba1 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -2668,7 +2668,7 @@
   scoped_refptr<ShaderTranslatorInterface> fragment_translator_;
 
   // Cached from ContextGroup
-  raw_ptr<const Validators> validators_;
+  raw_ptr<const Validators, DanglingUntriaged> validators_;
   scoped_refptr<FeatureInfo> feature_info_;
 
   int frame_number_;
diff --git a/gpu/command_buffer/service/raster_decoder.cc b/gpu/command_buffer/service/raster_decoder.cc
index 7980f0e..d2ac0ac7 100644
--- a/gpu/command_buffer/service/raster_decoder.cc
+++ b/gpu/command_buffer/service/raster_decoder.cc
@@ -901,7 +901,7 @@
 
   const bool is_drdc_enabled_;
 
-  raw_ptr<gl::GLApi> api_ = nullptr;
+  raw_ptr<gl::GLApi, DanglingUntriaged> api_ = nullptr;
 
   base::WeakPtrFactory<DecoderContext> weak_ptr_factory_{this};
 };
diff --git a/gpu/command_buffer/service/shared_image/egl_image_backing.cc b/gpu/command_buffer/service/shared_image/egl_image_backing.cc
index 868a27d..5366b82 100644
--- a/gpu/command_buffer/service/shared_image/egl_image_backing.cc
+++ b/gpu/command_buffer/service/shared_image/egl_image_backing.cc
@@ -44,7 +44,7 @@
       texture_->RemoveLightweightRef(!context_lost_);
   }
 
-  const raw_ptr<gles2::Texture> texture_ = nullptr;
+  const raw_ptr<gles2::Texture, DanglingUntriaged> texture_ = nullptr;
   const scoped_refptr<gles2::TexturePassthrough> texture_passthrough_;
   bool context_lost_ = false;
 };
diff --git a/gpu/command_buffer/service/shared_image/video_surface_texture_image_backing.cc b/gpu/command_buffer/service/shared_image/video_surface_texture_image_backing.cc
index a2b7783..4388607 100644
--- a/gpu/command_buffer/service/shared_image/video_surface_texture_image_backing.cc
+++ b/gpu/command_buffer/service/shared_image/video_surface_texture_image_backing.cc
@@ -131,14 +131,21 @@
     auto* video_backing =
         static_cast<VideoSurfaceTextureImageBacking*>(backing());
     video_backing->BeginGLReadAccess(texture_->service_id());
-    GetTexture()->SetLevelImageState(GetTexture()->target(), 0,
-                                     gles2::Texture::BOUND);
+
+    // If we passed a GLImage to BindStreamTextureImage(), mark it as bound.
+    if (!base::FeatureList::IsEnabled(kPassNullForGLImageWhenBindingTexture)) {
+      GetTexture()->SetLevelImageState(GetTexture()->target(), 0,
+                                       gles2::Texture::BOUND);
+    }
+
     return true;
   }
 
   void EndAccess() override {
-    GetTexture()->SetLevelImageState(GetTexture()->target(), 0,
-                                     gles2::Texture::UNBOUND);
+    if (!base::FeatureList::IsEnabled(kPassNullForGLImageWhenBindingTexture)) {
+      GetTexture()->SetLevelImageState(GetTexture()->target(), 0,
+                                       gles2::Texture::UNBOUND);
+    }
   }
 
  private:
@@ -181,7 +188,12 @@
     auto* video_backing =
         static_cast<VideoSurfaceTextureImageBacking*>(backing());
     video_backing->BeginGLReadAccess(passthrough_texture_->service_id());
-    passthrough_texture_->set_is_bind_pending(false);
+
+    // If we passed a GLImage to BindStreamTextureImage(), mark it as bound.
+    if (!base::FeatureList::IsEnabled(kPassNullForGLImageWhenBindingTexture)) {
+      passthrough_texture_->set_is_bind_pending(false);
+    }
+
     return true;
   }
 
diff --git a/gpu/command_buffer/service/texture_manager.h b/gpu/command_buffer/service/texture_manager.h
index 91b56e6..1524f6d5 100644
--- a/gpu/command_buffer/service/texture_manager.h
+++ b/gpu/command_buffer/service/texture_manager.h
@@ -791,7 +791,7 @@
   void reset_client_id() { client_id_ = 0; }
 
   raw_ptr<TextureManager> manager_;
-  raw_ptr<Texture> texture_;
+  raw_ptr<Texture, DanglingUntriaged> texture_;
   GLuint client_id_;
   GLint num_observers_;
   bool force_context_lost_;
diff --git a/ios/chrome/app/application_delegate/BUILD.gn b/ios/chrome/app/application_delegate/BUILD.gn
index 4816957b3..0e97b38 100644
--- a/ios/chrome/app/application_delegate/BUILD.gn
+++ b/ios/chrome/app/application_delegate/BUILD.gn
@@ -231,7 +231,6 @@
     "//ios/chrome/browser/ui/main",
     "//ios/chrome/browser/ui/main:scene",
     "//ios/chrome/browser/ui/ntp:util",
-    "//ios/chrome/browser/ui/util",
     "//ios/chrome/browser/url",
     "//ios/chrome/browser/url:constants",
     "//ios/chrome/browser/url_loading",
diff --git a/ios/chrome/app/application_delegate/app_state.mm b/ios/chrome/app/application_delegate/app_state.mm
index 93638f2c7..8f53754 100644
--- a/ios/chrome/app/application_delegate/app_state.mm
+++ b/ios/chrome/app/application_delegate/app_state.mm
@@ -47,7 +47,6 @@
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h"
 #import "ios/chrome/browser/ui/main/browser_interface_provider.h"
 #import "ios/chrome/browser/ui/main/scene_delegate.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/web_state_list/session_metrics.h"
 #import "ios/chrome/browser/web_state_list/web_state_list_metrics_browser_agent.h"
 #import "ios/net/cookies/cookie_store_ios.h"
diff --git a/ios/chrome/browser/signin/chrome_account_manager_service.mm b/ios/chrome/browser/signin/chrome_account_manager_service.mm
index 51042e5..f0fa7bb 100644
--- a/ios/chrome/browser/signin/chrome_account_manager_service.mm
+++ b/ios/chrome/browser/signin/chrome_account_manager_service.mm
@@ -11,7 +11,6 @@
 #import "components/signin/public/base/signin_pref_names.h"
 #import "ios/chrome/browser/application_context/application_context.h"
 #import "ios/chrome/browser/signin/resized_avatar_cache.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #import "ios/public/provider/chrome/browser/signin/chrome_identity_service.h"
diff --git a/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.mm b/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.mm
index afb06b6..32b4bcb 100644
--- a/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.mm
+++ b/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.mm
@@ -89,6 +89,8 @@
         ACCESS_POINT_SIGNIN_INTERCEPT_FIRST_RUN_EXPERIENCE:
     case signin_metrics::AccessPoint::ACCESS_POINT_SEND_TAB_TO_SELF_PROMO:
     case signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS_SYNC_OFF_ROW:
+    case signin_metrics::AccessPoint::
+        ACCESS_POINT_POST_DEVICE_RESTORE_BACKGROUND_SIGNIN:
     case signin_metrics::AccessPoint::ACCESS_POINT_MAX:
       return false;
   }
@@ -151,6 +153,8 @@
     case signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS_SYNC_OFF_ROW:
     case signin_metrics::AccessPoint::
         ACCESS_POINT_POST_DEVICE_RESTORE_SIGNIN_PROMO:
+    case signin_metrics::AccessPoint::
+        ACCESS_POINT_POST_DEVICE_RESTORE_BACKGROUND_SIGNIN:
     case signin_metrics::AccessPoint::ACCESS_POINT_MAX:
       NOTREACHED() << "Unexpected value for access point "
                    << static_cast<int>(access_point);
@@ -215,6 +219,8 @@
     case signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS_SYNC_OFF_ROW:
     case signin_metrics::AccessPoint::
         ACCESS_POINT_POST_DEVICE_RESTORE_SIGNIN_PROMO:
+    case signin_metrics::AccessPoint::
+        ACCESS_POINT_POST_DEVICE_RESTORE_BACKGROUND_SIGNIN:
     case signin_metrics::AccessPoint::ACCESS_POINT_MAX:
       NOTREACHED() << "Unexpected value for access point "
                    << static_cast<int>(access_point);
@@ -279,6 +285,8 @@
     case signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS_SYNC_OFF_ROW:
     case signin_metrics::AccessPoint::
         ACCESS_POINT_POST_DEVICE_RESTORE_SIGNIN_PROMO:
+    case signin_metrics::AccessPoint::
+        ACCESS_POINT_POST_DEVICE_RESTORE_BACKGROUND_SIGNIN:
     case signin_metrics::AccessPoint::ACCESS_POINT_MAX:
       NOTREACHED() << "Unexpected value for access point "
                    << static_cast<int>(access_point);
@@ -332,6 +340,8 @@
     case signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS_SYNC_OFF_ROW:
     case signin_metrics::AccessPoint::
         ACCESS_POINT_POST_DEVICE_RESTORE_SIGNIN_PROMO:
+    case signin_metrics::AccessPoint::
+        ACCESS_POINT_POST_DEVICE_RESTORE_BACKGROUND_SIGNIN:
     case signin_metrics::AccessPoint::ACCESS_POINT_MAX:
       return nullptr;
   }
@@ -383,6 +393,8 @@
     case signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS_SYNC_OFF_ROW:
     case signin_metrics::AccessPoint::
         ACCESS_POINT_POST_DEVICE_RESTORE_SIGNIN_PROMO:
+    case signin_metrics::AccessPoint::
+        ACCESS_POINT_POST_DEVICE_RESTORE_BACKGROUND_SIGNIN:
     case signin_metrics::AccessPoint::ACCESS_POINT_MAX:
       return nullptr;
   }
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn b/ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn
index 57fdea9f..2bc58f03 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn
+++ b/ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn
@@ -235,7 +235,6 @@
     "//ios/chrome/app/strings",
     "//ios/chrome/browser/ui/authentication:eg_test_support+eg2",
     "//ios/chrome/browser/ui/autofill:eg_test_support+eg2",
-    "//ios/chrome/browser/ui/util",
     "//ios/chrome/browser/ui/util:eg_test_support+eg2",
     "//ios/chrome/test:eg_test_support+eg2",
     "//ios/chrome/test/earl_grey:eg_test_support+eg2",
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/address_view_controller.mm b/ios/chrome/browser/ui/autofill/manual_fill/address_view_controller.mm
index 563301e..cb0b9db2 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/address_view_controller.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/address_view_controller.mm
@@ -8,7 +8,6 @@
 #import "base/metrics/histogram_macros.h"
 #import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_action_cell.h"
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #import "ios/chrome/grit/ios_strings.h"
 #import "ui/base/l10n/l10n_util_mac.h"
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/card_view_controller.mm b/ios/chrome/browser/ui/autofill/manual_fill/card_view_controller.mm
index 833656c3..cdf786d 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/card_view_controller.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/card_view_controller.mm
@@ -8,7 +8,6 @@
 #import "base/metrics/histogram_macros.h"
 #import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_action_cell.h"
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #import "ios/chrome/grit/ios_strings.h"
 #import "ui/base/l10n/l10n_util_mac.h"
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/fallback_view_controller.mm b/ios/chrome/browser/ui/autofill/manual_fill/fallback_view_controller.mm
index 0f5b35118..879e3ae 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/fallback_view_controller.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/fallback_view_controller.mm
@@ -9,6 +9,7 @@
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
+#import "ios/chrome/common/ui/util/ui_util.h"
 #import "ios/chrome/grit/ios_strings.h"
 #import "ui/base/device_form_factor.h"
 #import "ui/base/l10n/l10n_util_mac.h"
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_all_password_coordinator.mm b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_all_password_coordinator.mm
index 2acd548..69f32404 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_all_password_coordinator.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_all_password_coordinator.mm
@@ -17,7 +17,6 @@
 #import "ios/chrome/browser/ui/autofill/manual_fill/password_view_controller.h"
 #import "ios/chrome/browser/ui/table_view/table_view_animator.h"
 #import "ios/chrome/browser/ui/table_view/table_view_navigation_controller.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller.mm b/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller.mm
index 5ebbad5af..69cd8d18 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller.mm
@@ -17,7 +17,6 @@
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
 #import "ios/chrome/browser/ui/table_view/table_view_favicon_data_source.h"
 #import "ios/chrome/browser/ui/table_view/table_view_navigation_controller_constants.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
 #import "ios/chrome/common/ui/favicon/favicon_attributes.h"
diff --git a/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm b/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
index de583f61..31b8ed3 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
@@ -219,51 +219,6 @@
                  @"No keyboard commands are registered.");
 }
 
-// Test that swiping left to right navigate back.
-// TODO(crbug.com/768339): This test is faling on devices because
-// grey_swipeFastInDirectionWithStartPoint does not work.
-// TODO(crbug.com/978877): Fix the bug in EG and enable the test.
-// Navigate back side swipe gesture does not work on iOS13 simulator. This
-// is not specific to Bookmarks. The issue is that the gesture needs to
-// start offscreen, and EG cannot replicate that.
-- (void)DISABLED_testNavigateBackWithGesture {
-  // Disabled on iPad as there is not "navigate back" gesture.
-  if ([ChromeEarlGrey isIPadIdiom]) {
-    EARL_GREY_TEST_SKIPPED(@"Test not applicable for iPad");
-  }
-
-  [BookmarkEarlGrey setupStandardBookmarks];
-  [BookmarkEarlGreyUI openBookmarks];
-  [BookmarkEarlGreyUI openMobileBookmarks];
-
-  // Make sure Mobile Bookmarks is not present. Also check the button Class to
-  // avoid matching the "back" NavigationBar button.
-  [[EarlGrey
-      selectElementWithMatcher:grey_allOf(
-                                   grey_accessibilityID(@"Mobile Bookmarks"),
-                                   grey_kindOfClassName(@"UITableViewCell"),
-                                   nil)] assertWithMatcher:grey_nil()];
-
-  // Open the first folder, to be able to go back twice on the bookmarks.
-  [[EarlGrey
-      selectElementWithMatcher:TappableBookmarkNodeWithLabel(@"Folder 1")]
-      performAction:grey_tap()];
-
-  // Back twice using swipe left gesture.
-  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
-                                          kBookmarkHomeTableViewIdentifier)]
-      performAction:grey_swipeFastInDirectionWithStartPoint(kGREYDirectionRight,
-                                                            0.01, 0.5)];
-  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
-                                          kBookmarkHomeTableViewIdentifier)]
-      performAction:grey_swipeFastInDirectionWithStartPoint(kGREYDirectionRight,
-                                                            0.01, 0.5)];
-
-  // Check we navigated back to the Mobile Bookmarks.
-  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Mobile Bookmarks")]
-      assertWithMatcher:grey_sufficientlyVisible()];
-}
-
 // Tests that the bookmark context bar is shown in MobileBookmarks.
 - (void)testBookmarkContextBarShown {
   [BookmarkEarlGrey setupStandardBookmarks];
diff --git a/ios/chrome/browser/ui/bubble/BUILD.gn b/ios/chrome/browser/ui/bubble/BUILD.gn
index cc1678c..8080a96b 100644
--- a/ios/chrome/browser/ui/bubble/BUILD.gn
+++ b/ios/chrome/browser/ui/bubble/BUILD.gn
@@ -56,7 +56,6 @@
     ":bubble",
     "//base",
     "//base:i18n",
-    "//ios/chrome/browser/ui/util",
     "//testing/gtest",
   ]
   frameworks = [ "CoreGraphics.framework" ]
diff --git a/ios/chrome/browser/ui/bubble/bubble_presenter.mm b/ios/chrome/browser/ui/bubble/bubble_presenter.mm
index 1de8cc7..ed12afaa 100644
--- a/ios/chrome/browser/ui/bubble/bubble_presenter.mm
+++ b/ios/chrome/browser/ui/bubble/bubble_presenter.mm
@@ -20,7 +20,6 @@
 #import "ios/chrome/browser/ui/commands/toolbar_commands.h"
 #import "ios/chrome/browser/ui/util/named_guide.h"
 #import "ios/chrome/browser/ui/util/named_guide_util.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #import "ios/chrome/browser/url/chrome_url_constants.h"
 #import "ios/chrome/browser/url/url_util.h"
diff --git a/ios/chrome/browser/ui/bubble/bubble_util.mm b/ios/chrome/browser/ui/bubble/bubble_util.mm
index 069803b..b96b6fc 100644
--- a/ios/chrome/browser/ui/bubble/bubble_util.mm
+++ b/ios/chrome/browser/ui/bubble/bubble_util.mm
@@ -10,7 +10,6 @@
 #import "base/i18n/rtl.h"
 #import "base/notreached.h"
 #import "ios/chrome/browser/ui/util/rtl_geometry.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/bubble/bubble_util_unittest.mm b/ios/chrome/browser/ui/bubble/bubble_util_unittest.mm
index db5041d..6a4cd09 100644
--- a/ios/chrome/browser/ui/bubble/bubble_util_unittest.mm
+++ b/ios/chrome/browser/ui/bubble/bubble_util_unittest.mm
@@ -6,7 +6,6 @@
 
 #import <CoreGraphics/CoreGraphics.h>
 
-#import "ios/chrome/browser/ui/util/ui_util.h"
 #import "testing/gtest/include/gtest/gtest.h"
 #import "testing/platform_test.h"
 
diff --git a/ios/chrome/browser/ui/bubble/bubble_view.mm b/ios/chrome/browser/ui/bubble/bubble_view.mm
index 1dc4ea5..78186f0 100644
--- a/ios/chrome/browser/ui/bubble/bubble_view.mm
+++ b/ios/chrome/browser/ui/bubble/bubble_view.mm
@@ -11,7 +11,6 @@
 #import "ios/chrome/browser/ui/bubble/bubble_util.h"
 #import "ios/chrome/browser/ui/icons/chrome_symbol.h"
 #import "ios/chrome/browser/ui/util/rtl_geometry.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
 #import "ios/chrome/grit/ios_strings.h"
diff --git a/ios/chrome/browser/ui/bubble/bubble_view_controller_presenter.mm b/ios/chrome/browser/ui/bubble/bubble_view_controller_presenter.mm
index 6b8377c7..bde816e 100644
--- a/ios/chrome/browser/ui/bubble/bubble_view_controller_presenter.mm
+++ b/ios/chrome/browser/ui/bubble/bubble_view_controller_presenter.mm
@@ -9,7 +9,6 @@
 #import "base/metrics/histogram_macros.h"
 #import "ios/chrome/browser/ui/bubble/bubble_util.h"
 #import "ios/chrome/browser/ui/bubble/bubble_view_controller.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/bubble/bubble_view_unittest.mm b/ios/chrome/browser/ui/bubble/bubble_view_unittest.mm
index 665aa9d4..78d19ac1 100644
--- a/ios/chrome/browser/ui/bubble/bubble_view_unittest.mm
+++ b/ios/chrome/browser/ui/bubble/bubble_view_unittest.mm
@@ -7,7 +7,6 @@
 #import "base/ios/ios_util.h"
 #import "base/mac/foundation_util.h"
 #import "ios/chrome/browser/ui/bubble/bubble_unittest_util.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
 #import "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
 #import "testing/platform_test.h"
diff --git a/ios/chrome/browser/ui/download/BUILD.gn b/ios/chrome/browser/ui/download/BUILD.gn
index 590ad48..2cba67b 100644
--- a/ios/chrome/browser/ui/download/BUILD.gn
+++ b/ios/chrome/browser/ui/download/BUILD.gn
@@ -55,7 +55,6 @@
     "//ios/chrome/browser/ui/icons:download_icons",
     "//ios/chrome/browser/ui/icons:symbols",
     "//ios/chrome/browser/ui/presenters",
-    "//ios/chrome/browser/ui/util",
     "//ios/chrome/browser/web:web_internal",
     "//ios/chrome/browser/web_state_list:web_state_list",
     "//ios/chrome/common/ui/colors",
@@ -106,7 +105,6 @@
     "//ios/chrome/browser/overlays",
     "//ios/chrome/browser/overlays/public/web_content_area",
     "//ios/chrome/browser/ui/commands",
-    "//ios/chrome/browser/ui/util",
     "//ios/chrome/browser/web_state_list:test_support",
     "//ios/chrome/browser/web_state_list:web_state_list",
     "//ios/chrome/test:test_support",
diff --git a/ios/chrome/browser/ui/download/ar_quick_look_coordinator_unittest.mm b/ios/chrome/browser/ui/download/ar_quick_look_coordinator_unittest.mm
index e33fda7..7b7c9c6 100644
--- a/ios/chrome/browser/ui/download/ar_quick_look_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/download/ar_quick_look_coordinator_unittest.mm
@@ -20,7 +20,6 @@
 #import "ios/chrome/browser/download/ar_quick_look_tab_helper_delegate.h"
 #import "ios/chrome/browser/download/download_test_util.h"
 #import "ios/chrome/browser/main/test_browser.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/web_state_list/fake_web_state_list_delegate.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_opener.h"
diff --git a/ios/chrome/browser/ui/download/download_manager_coordinator.mm b/ios/chrome/browser/ui/download/download_manager_coordinator.mm
index dd8b5e6..6232677 100644
--- a/ios/chrome/browser/ui/download/download_manager_coordinator.mm
+++ b/ios/chrome/browser/ui/download/download_manager_coordinator.mm
@@ -39,7 +39,6 @@
 #import "ios/chrome/browser/ui/download/download_manager_view_controller.h"
 #import "ios/chrome/browser/ui/presenters/contained_presenter.h"
 #import "ios/chrome/browser/ui/presenters/contained_presenter_delegate.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_list_observer.h"
 #import "ios/chrome/grit/ios_strings.h"
diff --git a/ios/chrome/browser/ui/download/safari_download_coordinator_unittest.mm b/ios/chrome/browser/ui/download/safari_download_coordinator_unittest.mm
index 90dae50..1f78cfa 100644
--- a/ios/chrome/browser/ui/download/safari_download_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/download/safari_download_coordinator_unittest.mm
@@ -17,7 +17,6 @@
 #import "ios/chrome/browser/download/safari_download_tab_helper.h"
 #import "ios/chrome/browser/download/safari_download_tab_helper_delegate.h"
 #import "ios/chrome/browser/main/test_browser.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/web_state_list/fake_web_state_list_delegate.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_opener.h"
diff --git a/ios/chrome/browser/ui/image_util/image_copier.mm b/ios/chrome/browser/ui/image_util/image_copier.mm
index 722cdb5..5cf60bf 100644
--- a/ios/chrome/browser/ui/image_util/image_copier.mm
+++ b/ios/chrome/browser/ui/image_util/image_copier.mm
@@ -24,11 +24,9 @@
 #endif
 
 namespace {
-// Name of the UMA ContextMenu.iOS.CopyImage histogram.
-const char kUmaContextMenuCopyImage[] = "ContextMenu.iOS.CopyImage";
 // These values are persisted to logs. Entries should not be renumbered and
 // numeric values should never be reused.
-// Enum for the ContextMenu.iOS.CopyImage UMA histogram to report
+// Enum for the Mobile.ContextMenu.CopyImage UMA histogram to report
 // the results of Copy Image.
 enum class ContextMenuCopyImage {
   // Copy Image is called.
@@ -53,7 +51,7 @@
 // A speical id indicates that last copy is finished or canceled and next
 // copy has not started.
 const int kNoActiveCopy = 0;
-}
+}  // namespace
 
 @interface ImageCopier ()
 // The browser.
@@ -161,7 +159,7 @@
 }
 
 - (void)recordCopyImageUMA:(ContextMenuCopyImage)UMAEnum {
-  UMA_HISTOGRAM_ENUMERATION(kUmaContextMenuCopyImage, UMAEnum);
+  UMA_HISTOGRAM_ENUMERATION("Mobile.ContextMenu.CopyImage", UMAEnum);
 }
 
 @end
diff --git a/ios/chrome/browser/ui/lens/lens_availability.mm b/ios/chrome/browser/ui/lens/lens_availability.mm
index aa4d458..30f3c78 100644
--- a/ios/chrome/browser/ui/lens/lens_availability.mm
+++ b/ios/chrome/browser/ui/lens/lens_availability.mm
@@ -9,4 +9,4 @@
 #endif
 
 const char kIOSLensSupportStatusHistogram[] =
-    "ContextMenu.iOS.LensSupportStatus";
+    "Mobile.ContextMenu.LensSupportStatus";
diff --git a/ios/chrome/browser/ui/main_content/BUILD.gn b/ios/chrome/browser/ui/main_content/BUILD.gn
index f28a452a..2f325e8 100644
--- a/ios/chrome/browser/ui/main_content/BUILD.gn
+++ b/ios/chrome/browser/ui/main_content/BUILD.gn
@@ -60,8 +60,8 @@
     "//base/test:test_support",
     "//ios/chrome/browser/ui/broadcaster",
     "//ios/chrome/browser/ui/main_content/test",
-    "//ios/chrome/browser/ui/util",
     "//ios/chrome/browser/web_state_list",
+    "//ios/chrome/common/ui/util",
     "//ios/web/public/test",
     "//ios/web/public/test/fakes",
     "//testing/gtest",
diff --git a/ios/chrome/browser/ui/main_content/main_content_ui_state.mm b/ios/chrome/browser/ui/main_content/main_content_ui_state.mm
index 6555b0213..786fbeb 100644
--- a/ios/chrome/browser/ui/main_content/main_content_ui_state.mm
+++ b/ios/chrome/browser/ui/main_content/main_content_ui_state.mm
@@ -7,7 +7,6 @@
 #import <ostream>
 
 #import "base/check_op.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/main_content/main_content_ui_state_unittest.mm b/ios/chrome/browser/ui/main_content/main_content_ui_state_unittest.mm
index 7ec29257..77195211 100644
--- a/ios/chrome/browser/ui/main_content/main_content_ui_state_unittest.mm
+++ b/ios/chrome/browser/ui/main_content/main_content_ui_state_unittest.mm
@@ -5,7 +5,7 @@
 #import "ios/chrome/browser/ui/main_content/main_content_ui_state.h"
 
 #import "ios/chrome/browser/ui/broadcaster/chrome_broadcaster.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
+#import "ios/chrome/common/ui/util/ui_util.h"
 #import "testing/platform_test.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/main_content/test/BUILD.gn b/ios/chrome/browser/ui/main_content/test/BUILD.gn
index 7eef7c5..a2ea979 100644
--- a/ios/chrome/browser/ui/main_content/test/BUILD.gn
+++ b/ios/chrome/browser/ui/main_content/test/BUILD.gn
@@ -19,7 +19,7 @@
   deps = [
     "//ios/chrome/browser/ui/broadcaster",
     "//ios/chrome/browser/ui/main_content:main_content_ui",
-    "//ios/chrome/browser/ui/util",
+    "//ios/chrome/common/ui/util",
     "//testing/gtest",
   ]
 }
diff --git a/ios/chrome/browser/ui/main_content/test/main_content_broadcast_test_util.mm b/ios/chrome/browser/ui/main_content/test/main_content_broadcast_test_util.mm
index 6ed437bd..986a404 100644
--- a/ios/chrome/browser/ui/main_content/test/main_content_broadcast_test_util.mm
+++ b/ios/chrome/browser/ui/main_content/test/main_content_broadcast_test_util.mm
@@ -6,7 +6,7 @@
 
 #import "ios/chrome/browser/ui/main_content/test/test_main_content_ui_observer.h"
 #import "ios/chrome/browser/ui/main_content/test/test_main_content_ui_state.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
+#import "ios/chrome/common/ui/util/ui_util.h"
 #import "testing/gtest/include/gtest/gtest.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/recent_tabs/BUILD.gn b/ios/chrome/browser/ui/recent_tabs/BUILD.gn
index 2b414797..9ca7c23 100644
--- a/ios/chrome/browser/ui/recent_tabs/BUILD.gn
+++ b/ios/chrome/browser/ui/recent_tabs/BUILD.gn
@@ -39,7 +39,6 @@
     "//ios/chrome/browser/ui/ntp",
     "//ios/chrome/browser/ui/sharing",
     "//ios/chrome/browser/ui/table_view",
-    "//ios/chrome/browser/ui/util",
     "//ios/chrome/browser/url_loading",
     "//ios/chrome/browser/web_state_list",
     "//ios/chrome/common/ui/favicon:favicon_constants",
@@ -109,7 +108,6 @@
     "//ios/chrome/browser/ui/table_view:presentation",
     "//ios/chrome/browser/ui/table_view:styler",
     "//ios/chrome/browser/ui/table_view:utils",
-    "//ios/chrome/browser/ui/util",
     "//ios/chrome/browser/url_loading",
     "//ios/chrome/browser/web_state_list",
     "//ios/chrome/browser/web_state_list",
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm
index 5893f4c..059ad46 100644
--- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm
@@ -70,7 +70,6 @@
 #import "ios/chrome/browser/ui/table_view/table_view_favicon_data_source.h"
 #import "ios/chrome/browser/ui/table_view/table_view_utils.h"
 #import "ios/chrome/browser/ui/ui_feature_flags.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #import "ios/chrome/browser/url_loading/url_loading_browser_agent.h"
 #import "ios/chrome/browser/url_loading/url_loading_params.h"
diff --git a/ios/chrome/browser/ui/sad_tab/sad_tab_view.mm b/ios/chrome/browser/ui/sad_tab/sad_tab_view.mm
index 9c3426e..b606b50 100644
--- a/ios/chrome/browser/ui/sad_tab/sad_tab_view.mm
+++ b/ios/chrome/browser/ui/sad_tab/sad_tab_view.mm
@@ -18,6 +18,7 @@
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
 #import "ios/chrome/common/ui/util/pointer_interaction_util.h"
 #import "ios/chrome/common/ui/util/text_view_util.h"
+#import "ios/chrome/common/ui/util/ui_util.h"
 #import "ios/web/public/browser_state.h"
 #import "ios/web/public/navigation/navigation_manager.h"
 #import "net/base/mac/url_conversions.h"
diff --git a/ios/chrome/browser/ui/scanner/preview_overlay_view.mm b/ios/chrome/browser/ui/scanner/preview_overlay_view.mm
index e4287005..c331bae 100644
--- a/ios/chrome/browser/ui/scanner/preview_overlay_view.mm
+++ b/ios/chrome/browser/ui/scanner/preview_overlay_view.mm
@@ -6,7 +6,7 @@
 
 #import <AVFoundation/AVFoundation.h>
 
-#import "ios/chrome/browser/ui/util/ui_util.h"
+#import "ios/chrome/common/ui/util/ui_util.h"
 #import "ui/base/device_form_factor.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/scanner/scanner_view.mm b/ios/chrome/browser/ui/scanner/scanner_view.mm
index 0e7ff2d..58e35197 100644
--- a/ios/chrome/browser/ui/scanner/scanner_view.mm
+++ b/ios/chrome/browser/ui/scanner/scanner_view.mm
@@ -10,7 +10,6 @@
 #import "ios/chrome/browser/ui/icons/chrome_icon.h"
 #import "ios/chrome/browser/ui/scanner/preview_overlay_view.h"
 #import "ios/chrome/browser/ui/scanner/video_preview_view.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/common/ui/util/constraints_ui_util.h"
 #import "ios/chrome/grit/ios_strings.h"
 #import "ui/base/l10n/l10n_util.h"
diff --git a/ios/chrome/browser/ui/scanner/scanner_view_controller.mm b/ios/chrome/browser/ui/scanner/scanner_view_controller.mm
index 09583430a..bb976e8 100644
--- a/ios/chrome/browser/ui/scanner/scanner_view_controller.mm
+++ b/ios/chrome/browser/ui/scanner/scanner_view_controller.mm
@@ -14,7 +14,6 @@
 #import "ios/chrome/browser/ui/scanner/scanner_presenting.h"
 #import "ios/chrome/browser/ui/scanner/scanner_transitioning_delegate.h"
 #import "ios/chrome/browser/ui/scanner/scanner_view.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/grit/ios_strings.h"
 #import "ui/base/l10n/l10n_util.h"
 
diff --git a/ios/chrome/browser/ui/scanner/video_preview_view.mm b/ios/chrome/browser/ui/scanner/video_preview_view.mm
index 7730a091..514eccfc 100644
--- a/ios/chrome/browser/ui/scanner/video_preview_view.mm
+++ b/ios/chrome/browser/ui/scanner/video_preview_view.mm
@@ -6,7 +6,7 @@
 
 #import "base/check.h"
 #import "base/mac/foundation_util.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
+#import "ios/chrome/common/ui/util/ui_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/settings/bar_button_activity_indicator.mm b/ios/chrome/browser/ui/settings/bar_button_activity_indicator.mm
index 43416929..8c6d424b 100644
--- a/ios/chrome/browser/ui/settings/bar_button_activity_indicator.mm
+++ b/ios/chrome/browser/ui/settings/bar_button_activity_indicator.mm
@@ -4,8 +4,8 @@
 
 #import "ios/chrome/browser/ui/settings/bar_button_activity_indicator.h"
 
-#import "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
+#import "ios/chrome/common/ui/util/ui_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/settings/safety_check/safety_check_mediator_unittest.mm b/ios/chrome/browser/ui/settings/safety_check/safety_check_mediator_unittest.mm
index cae7a91..f6f40d0 100644
--- a/ios/chrome/browser/ui/settings/safety_check/safety_check_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/settings/safety_check/safety_check_mediator_unittest.mm
@@ -330,7 +330,7 @@
     EXPECT_NSEQ(
         mediator_.safeBrowsingCheckItem.detailText,
         GetNSString(
-            IDS_IOS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_STANDARD_PROTECTION_ENABLED_DESC));
+            IDS_IOS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_STANDARD_PROTECTION_ENABLED_DESC_WITH_ENHANCED_PROTECTION));
   } else {
     EXPECT_NSEQ(
         mediator_.safeBrowsingCheckItem.detailText,
@@ -362,7 +362,7 @@
   EXPECT_NSEQ(
       mediator_.safeBrowsingCheckItem.detailText,
       GetNSString(
-          IDS_IOS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_STANDARD_PROTECTION_ENABLED_DESC));
+          IDS_IOS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_STANDARD_PROTECTION_ENABLED_DESC_WITH_ENHANCED_PROTECTION));
   EXPECT_EQ(mediator_.safeBrowsingCheckItem.trailingImage,
             [[UIImage imageNamed:@"settings_safe_state"]
                 imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]);
@@ -431,7 +431,7 @@
   EXPECT_NSEQ(
       mediator_.safeBrowsingCheckItem.detailText,
       GetNSString(IDS_IOS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_DISABLED_DESC));
-  EXPECT_FALSE(mediator_.safeBrowsingCheckItem.infoButtonHidden);
+  EXPECT_TRUE(mediator_.safeBrowsingCheckItem.infoButtonHidden);
 }
 
 TEST_F(SafetyCheckMediatorTest, SafeBrowsingManagedUI) {
diff --git a/ios/chrome/browser/ui/settings/settings_navigation_controller.mm b/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
index f7c2bc1..6cdabc8 100644
--- a/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
+++ b/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
@@ -31,7 +31,6 @@
 #import "ios/chrome/browser/ui/settings/settings_table_view_controller.h"
 #import "ios/chrome/browser/ui/settings/sync/sync_encryption_passphrase_table_view_controller.h"
 #import "ios/chrome/browser/ui/table_view/table_view_utils.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
 #import "ios/chrome/common/ui/util/constraints_ui_util.h"
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/BUILD.gn b/ios/chrome/browser/ui/tab_switcher/tab_grid/BUILD.gn
index 0e1af0f..b0267fa 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/BUILD.gn
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/BUILD.gn
@@ -156,7 +156,6 @@
     "//ios/chrome/browser/ui/thumb_strip",
     "//ios/chrome/browser/ui/thumb_strip:feature_flags",
     "//ios/chrome/browser/ui/thumb_strip:public",
-    "//ios/chrome/browser/ui/util",
     "//ios/chrome/browser/url:constants",
     "//ios/chrome/common:string_util",
     "//ios/chrome/common/ui/util",
@@ -250,7 +249,6 @@
     "//ios/chrome/browser/ui/start_surface:feature_flags",
     "//ios/chrome/browser/ui/tab_switcher/tab_grid/grid:grid_ui_constants",
     "//ios/chrome/browser/ui/thumb_strip:feature_flags",
-    "//ios/chrome/browser/ui/util",
     "//ios/chrome/common/ui/table_view:cells_constants",
     "//ios/chrome/test/earl_grey:eg_test_support+eg2",
     "//ios/testing/earl_grey:eg_test_support+eg2",
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/transitions/BUILD.gn b/ios/chrome/browser/ui/tab_switcher/tab_grid/transitions/BUILD.gn
index 4eb81ffd..0191069 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/transitions/BUILD.gn
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/transitions/BUILD.gn
@@ -23,5 +23,6 @@
     "//ios/chrome/browser/crash_report",
     "//ios/chrome/browser/ui/tab_switcher/tab_grid:tab_grid_paging",
     "//ios/chrome/browser/ui/util",
+    "//ios/chrome/common/ui/util",
   ]
 }
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/transitions/grid_transition_animation.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/transitions/grid_transition_animation.mm
index 83bed28..662f971 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/transitions/grid_transition_animation.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/transitions/grid_transition_animation.mm
@@ -7,7 +7,7 @@
 #import "ios/chrome/browser/ui/tab_switcher/tab_grid/transitions/grid_to_tab_transition_view.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_grid/transitions/grid_transition_layout.h"
 #import "ios/chrome/browser/ui/util/property_animator_group.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
+#import "ios/chrome/common/ui/util/ui_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/transitions/tab_grid_transition_handler.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/transitions/tab_grid_transition_handler.mm
index eea032c0..77c2510 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/transitions/tab_grid_transition_handler.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/transitions/tab_grid_transition_handler.mm
@@ -8,7 +8,7 @@
 #import "ios/chrome/browser/ui/tab_switcher/tab_grid/transitions/grid_transition_animation_layout_providing.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_grid/transitions/grid_transition_layout.h"
 #import "ios/chrome/browser/ui/util/named_guide.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
+#import "ios/chrome/common/ui/util/ui_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_strip/tab_strip_view_layout.mm b/ios/chrome/browser/ui/tab_switcher/tab_strip/tab_strip_view_layout.mm
index 6f840376..5fda2d5 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_strip/tab_strip_view_layout.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_strip/tab_strip_view_layout.mm
@@ -5,7 +5,6 @@
 #import "ios/chrome/browser/ui/tab_switcher/tab_strip/tab_strip_view_layout.h"
 
 #import "base/cxx17_backports.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/toolbar/BUILD.gn b/ios/chrome/browser/ui/toolbar/BUILD.gn
index 32d6f8e..a1bf1f5 100644
--- a/ios/chrome/browser/ui/toolbar/BUILD.gn
+++ b/ios/chrome/browser/ui/toolbar/BUILD.gn
@@ -168,7 +168,6 @@
     "//ios/chrome/browser/ui/toolbar/buttons",
     "//ios/chrome/browser/ui/toolbar/public",
     "//ios/chrome/browser/ui/toolbar/test",
-    "//ios/chrome/browser/ui/util",
     "//ios/chrome/browser/url:constants",
     "//ios/chrome/browser/web_state_list",
     "//ios/chrome/browser/web_state_list:test_support",
@@ -236,7 +235,7 @@
     "//ios/chrome/browser/ui/popup_menu:constants",
     "//ios/chrome/browser/ui/start_surface:feature_flags",
     "//ios/chrome/browser/ui/toolbar/public:constants",
-    "//ios/chrome/browser/ui/util:util",
+    "//ios/chrome/browser/ui/util",
     "//ios/chrome/test/earl_grey:eg_test_support+eg2",
     "//ios/testing/earl_grey:eg_test_support+eg2",
     "//ios/third_party/earl_grey2:test_lib",
diff --git a/ios/chrome/browser/ui/toolbar/buttons/toolbar_tab_grid_button.mm b/ios/chrome/browser/ui/toolbar/buttons/toolbar_tab_grid_button.mm
index a37af52e9..e1917ff6 100644
--- a/ios/chrome/browser/ui/toolbar/buttons/toolbar_tab_grid_button.mm
+++ b/ios/chrome/browser/ui/toolbar/buttons/toolbar_tab_grid_button.mm
@@ -6,7 +6,6 @@
 
 #import "ios/chrome/browser/ui/toolbar/buttons/toolbar_configuration.h"
 #import "ios/chrome/browser/ui/toolbar/public/toolbar_constants.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #import "ios/chrome/common/ui/util/constraints_ui_util.h"
 
diff --git a/ios/chrome/browser/ui/toolbar/buttons/toolbar_tools_menu_button.mm b/ios/chrome/browser/ui/toolbar/buttons/toolbar_tools_menu_button.mm
index 8870970c3..9545dcf 100644
--- a/ios/chrome/browser/ui/toolbar/buttons/toolbar_tools_menu_button.mm
+++ b/ios/chrome/browser/ui/toolbar/buttons/toolbar_tools_menu_button.mm
@@ -10,7 +10,6 @@
 #import "base/check_op.h"
 #import "ios/chrome/browser/ui/toolbar/buttons/toolbar_configuration.h"
 #import "ios/chrome/browser/ui/util/rtl_geometry.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/toolbar/primary_toolbar_coordinator.mm b/ios/chrome/browser/ui/toolbar/primary_toolbar_coordinator.mm
index 1f1a9be..b0d5d78 100644
--- a/ios/chrome/browser/ui/toolbar/primary_toolbar_coordinator.mm
+++ b/ios/chrome/browser/ui/toolbar/primary_toolbar_coordinator.mm
@@ -32,7 +32,6 @@
 #import "ios/chrome/browser/ui/toolbar/primary_toolbar_view_controller.h"
 #import "ios/chrome/browser/ui/toolbar/primary_toolbar_view_controller_delegate.h"
 #import "ios/chrome/browser/ui/toolbar/toolbar_coordinator_delegate.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/components/webui/web_ui_url_constants.h"
diff --git a/ios/chrome/browser/ui/toolbar/primary_toolbar_view_controller.mm b/ios/chrome/browser/ui/toolbar/primary_toolbar_view_controller.mm
index a510074..cafe487e 100644
--- a/ios/chrome/browser/ui/toolbar/primary_toolbar_view_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/primary_toolbar_view_controller.mm
@@ -27,8 +27,8 @@
 #import "ios/chrome/browser/ui/ui_feature_flags.h"
 #import "ios/chrome/browser/ui/util/dynamic_type_util.h"
 #import "ios/chrome/browser/ui/util/named_guide.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
+#import "ios/chrome/common/ui/util/ui_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/toolbar/public/BUILD.gn b/ios/chrome/browser/ui/toolbar/public/BUILD.gn
index 476d29d..b20a86f 100644
--- a/ios/chrome/browser/ui/toolbar/public/BUILD.gn
+++ b/ios/chrome/browser/ui/toolbar/public/BUILD.gn
@@ -19,6 +19,7 @@
     "//ios/chrome/browser/ui/fullscreen:ui",
     "//ios/chrome/browser/ui/ntp",
     "//ios/chrome/browser/ui/util",
+    "//ios/chrome/common/ui/util",
     "//ios/components/ui_util",
   ]
   public_deps = [ ":constants" ]
diff --git a/ios/chrome/browser/ui/toolbar/public/toolbar_utils.mm b/ios/chrome/browser/ui/toolbar/public/toolbar_utils.mm
index adbee796..414e1dc 100644
--- a/ios/chrome/browser/ui/toolbar/public/toolbar_utils.mm
+++ b/ios/chrome/browser/ui/toolbar/public/toolbar_utils.mm
@@ -6,6 +6,7 @@
 
 #import "ios/chrome/browser/ui/toolbar/public/toolbar_constants.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
+#import "ios/chrome/common/ui/util/ui_util.h"
 #import "ios/components/ui_util/dynamic_type_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/toolbar/test/BUILD.gn b/ios/chrome/browser/ui/toolbar/test/BUILD.gn
index 664af40..ed8d9f8 100644
--- a/ios/chrome/browser/ui/toolbar/test/BUILD.gn
+++ b/ios/chrome/browser/ui/toolbar/test/BUILD.gn
@@ -18,7 +18,7 @@
   deps = [
     "//ios/chrome/browser/ui/broadcaster",
     "//ios/chrome/browser/ui/toolbar/fullscreen",
-    "//ios/chrome/browser/ui/util",
+    "//ios/chrome/common/ui/util",
     "//ios/web/public/test/fakes",
     "//testing/gtest",
   ]
diff --git a/ios/chrome/browser/ui/toolbar/test/toolbar_broadcast_test_util.mm b/ios/chrome/browser/ui/toolbar/test/toolbar_broadcast_test_util.mm
index 387625a..cdf2c5bf 100644
--- a/ios/chrome/browser/ui/toolbar/test/toolbar_broadcast_test_util.mm
+++ b/ios/chrome/browser/ui/toolbar/test/toolbar_broadcast_test_util.mm
@@ -6,7 +6,7 @@
 
 #import "ios/chrome/browser/ui/toolbar/fullscreen/toolbar_ui.h"
 #import "ios/chrome/browser/ui/toolbar/test/test_toolbar_ui_observer.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
+#import "ios/chrome/common/ui/util/ui_util.h"
 #import "testing/gtest/include/gtest/gtest.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/toolbar_container/BUILD.gn b/ios/chrome/browser/ui/toolbar_container/BUILD.gn
index 801804c..daa56c5 100644
--- a/ios/chrome/browser/ui/toolbar_container/BUILD.gn
+++ b/ios/chrome/browser/ui/toolbar_container/BUILD.gn
@@ -53,7 +53,6 @@
     ":toolbar_collapsing",
     "//base",
     "//ios/chrome/browser/ui/fullscreen:ui",
-    "//ios/chrome/browser/ui/util",
     "//ios/chrome/common/ui/util",
   ]
 }
@@ -72,7 +71,6 @@
     ":toolbar_collapsing",
     ":ui",
     "//base/test:test_support",
-    "//ios/chrome/browser/ui/util",
     "//ios/chrome/common/ui/util",
     "//testing/gtest",
   ]
diff --git a/ios/chrome/browser/ui/toolbar_container/collapsing_toolbar_height_constraint.mm b/ios/chrome/browser/ui/toolbar_container/collapsing_toolbar_height_constraint.mm
index 1cc743c..97eb7ca 100644
--- a/ios/chrome/browser/ui/toolbar_container/collapsing_toolbar_height_constraint.mm
+++ b/ios/chrome/browser/ui/toolbar_container/collapsing_toolbar_height_constraint.mm
@@ -10,7 +10,7 @@
 #import "base/cxx17_backports.h"
 #import "ios/chrome/browser/ui/toolbar_container/collapsing_toolbar_height_constraint_delegate.h"
 #import "ios/chrome/browser/ui/toolbar_container/toolbar_collapsing.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
+#import "ios/chrome/common/ui/util/ui_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/toolbar_container/toolbar_container_view_controller.mm b/ios/chrome/browser/ui/toolbar_container/toolbar_container_view_controller.mm
index ffb6061..62e1bea 100644
--- a/ios/chrome/browser/ui/toolbar_container/toolbar_container_view_controller.mm
+++ b/ios/chrome/browser/ui/toolbar_container/toolbar_container_view_controller.mm
@@ -13,8 +13,8 @@
 #import "ios/chrome/browser/ui/toolbar_container/collapsing_toolbar_height_constraint_delegate.h"
 #import "ios/chrome/browser/ui/toolbar_container/toolbar_container_view.h"
 #import "ios/chrome/browser/ui/toolbar_container/toolbar_height_range.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/common/ui/util/constraints_ui_util.h"
+#import "ios/chrome/common/ui/util/ui_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/toolbar_container/toolbar_height_range.mm b/ios/chrome/browser/ui/toolbar_container/toolbar_height_range.mm
index 9abd8d04..cf0ffc8 100644
--- a/ios/chrome/browser/ui/toolbar_container/toolbar_height_range.mm
+++ b/ios/chrome/browser/ui/toolbar_container/toolbar_height_range.mm
@@ -6,7 +6,7 @@
 
 #import <algorithm>
 
-#import "ios/chrome/browser/ui/util/ui_util.h"
+#import "ios/chrome/common/ui/util/ui_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/util/keyboard_observer_helper.mm b/ios/chrome/browser/ui/util/keyboard_observer_helper.mm
index 4acaa24..854796c 100644
--- a/ios/chrome/browser/ui/util/keyboard_observer_helper.mm
+++ b/ios/chrome/browser/ui/util/keyboard_observer_helper.mm
@@ -6,8 +6,8 @@
 
 #import "base/check.h"
 #import "base/check_op.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/common/ui/util/constraints_ui_util.h"
+#import "ios/chrome/common/ui/util/ui_util.h"
 #import "ui/base/device_form_factor.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/util/rtl_geometry.mm b/ios/chrome/browser/ui/util/rtl_geometry.mm
index c7df9de..ef4df8a2 100644
--- a/ios/chrome/browser/ui/util/rtl_geometry.mm
+++ b/ios/chrome/browser/ui/util/rtl_geometry.mm
@@ -8,7 +8,7 @@
 #import <limits>
 
 #import "base/check_op.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
+#import "ios/chrome/common/ui/util/ui_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/util/uikit_ui_util.mm b/ios/chrome/browser/ui/util/uikit_ui_util.mm
index b5624425..a7fe8754 100644
--- a/ios/chrome/browser/ui/util/uikit_ui_util.mm
+++ b/ios/chrome/browser/ui/util/uikit_ui_util.mm
@@ -21,7 +21,7 @@
 #import "ios/chrome/browser/ui/ui_feature_flags.h"
 #import "ios/chrome/browser/ui/util/dynamic_type_util.h"
 #import "ios/chrome/browser/ui/util/rtl_geometry.h"
-#import "ios/chrome/browser/ui/util/ui_util.h"
+#import "ios/chrome/common/ui/util/ui_util.h"
 #import "ios/web/public/thread/web_thread.h"
 #import "ui/base/l10n/l10n_util.h"
 #import "ui/base/l10n/l10n_util_mac.h"
diff --git a/ios/chrome/browser/web/image_fetch/image_fetch_tab_helper.mm b/ios/chrome/browser/web/image_fetch/image_fetch_tab_helper.mm
index f34af3f..787bbe2 100644
--- a/ios/chrome/browser/web/image_fetch/image_fetch_tab_helper.mm
+++ b/ios/chrome/browser/web/image_fetch/image_fetch_tab_helper.mm
@@ -25,7 +25,7 @@
 #endif
 
 const char kUmaGetImageDataByJsResult[] =
-    "ContextMenu.iOS.GetImageDataByJsResult";
+    "Mobile.ContextMenu.GetImageDataByJsResult";
 
 namespace {
 // Key for image_fetcher
diff --git a/ios/chrome/browser/web/page_placeholder_tab_helper.h b/ios/chrome/browser/web/page_placeholder_tab_helper.h
index b9ef2a47..a84f31b8 100644
--- a/ios/chrome/browser/web/page_placeholder_tab_helper.h
+++ b/ios/chrome/browser/web/page_placeholder_tab_helper.h
@@ -67,6 +67,9 @@
   // that has the Content Area named guide.
   void DisplaySnapshotImage(UIImage* snapshot);
 
+  // Display image in a placeholder after retrieval from SnapshotTabHelper.
+  void OnImageRetrieved(UIImage* image);
+
   // WebState this tab helper is attached to.
   web::WebState* web_state_ = nullptr;
 
diff --git a/ios/chrome/browser/web/page_placeholder_tab_helper.mm b/ios/chrome/browser/web/page_placeholder_tab_helper.mm
index a525131..51c8278 100644
--- a/ios/chrome/browser/web/page_placeholder_tab_helper.mm
+++ b/ios/chrome/browser/web/page_placeholder_tab_helper.mm
@@ -78,6 +78,12 @@
   RemovePlaceholder();
 }
 
+void PagePlaceholderTabHelper::OnImageRetrieved(UIImage* image) {
+  if (displaying_placeholder()) {
+    DisplaySnapshotImage(image);
+  }
+}
+
 void PagePlaceholderTabHelper::AddPlaceholder() {
   // WebState::WasShown() and WebState::IsVisible() are bookkeeping mechanisms
   // that do not guarantee the WebState's view is in the view hierarchy.
@@ -99,13 +105,20 @@
   SnapshotTabHelper* snapshotTabHelper =
       SnapshotTabHelper::FromWebState(web_state_);
   if (snapshotTabHelper) {
-    base::WeakPtr<PagePlaceholderTabHelper> weak_tab_helper =
-        weak_factory_.GetWeakPtr();
-    snapshotTabHelper->RetrieveGreySnapshot(^(UIImage* snapshot) {
-      if (weak_tab_helper && weak_tab_helper->displaying_placeholder()) {
-        DisplaySnapshotImage(snapshot);
-      }
-    });
+    __block base::OnceCallback<void(UIImage*)> callback =
+        base::BindOnce(&PagePlaceholderTabHelper::OnImageRetrieved,
+                       weak_factory_.GetWeakPtr());
+
+    auto block = ^(UIImage* image) {
+      std::move(callback).Run(image);
+    };
+
+    // Show grey snapshots only for the WebStates that haven't been loaded
+    if (web_state_->IsLoading()) {
+      snapshotTabHelper->RetrieveGreySnapshot(block);
+    } else {
+      snapshotTabHelper->RetrieveColorSnapshot(block);
+    }
   }
 
   // Remove placeholder if it takes too long to load the page.
diff --git a/ios/web/web_state/error_page_inttest.mm b/ios/web/web_state/error_page_inttest.mm
index ca63c53b..435ef136 100644
--- a/ios/web/web_state/error_page_inttest.mm
+++ b/ios/web/web_state/error_page_inttest.mm
@@ -161,13 +161,7 @@
 
 // Tests that the error page is correctly displayed after navigating back to it
 // multiple times. See http://crbug.com/944037 .
-// TODO(crbug.com/954231): this test is flaky on device.
-#if TARGET_IPHONE_SIMULATOR
-#define MAYBE_BackForwardErrorPage BackForwardErrorPage
-#else
-#define MAYBE_BackForwardErrorPage FLAKY_BackForwardErrorPage
-#endif
-TEST_F(ErrorPageTest, MAYBE_BackForwardErrorPage) {
+TEST_F(ErrorPageTest, BackForwardErrorPage) {
   // TODO(crbug.com/1153261): this test should be fixed in newer versions of
   // WebKit.
   if (@available(iOS 15, *)) {
diff --git a/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc b/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
index 561f5a6..d84e339 100644
--- a/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
@@ -114,10 +114,6 @@
     return RestrictIoctl();
   }
 
-  if (sysno == __NR_sched_getaffinity) {
-    return Allow();
-  }
-
   // Used when RSS limiting is enabled in sanitizers.
   if (sysno == __NR_getrusage) {
     return RestrictGetrusage();
@@ -230,6 +226,13 @@
   if (sysno == __NR_getpriority || sysno ==__NR_setpriority)
     return RestrictGetSetpriority(current_pid);
 
+  // The scheduling syscalls are used in threading libraries and also heavily in
+  // abseil. See for example https://crbug.com/1370394.
+  if (sysno == __NR_sched_getaffinity || sysno == __NR_sched_getparam ||
+      sysno == __NR_sched_getscheduler || sysno == __NR_sched_setscheduler) {
+    return RestrictSchedTarget(current_pid, sysno);
+  }
+
   if (sysno == __NR_getrandom) {
     return RestrictGetRandom();
   }
diff --git a/sandbox/policy/linux/bpf_audio_policy_linux.cc b/sandbox/policy/linux/bpf_audio_policy_linux.cc
index 8e32e62..bb6424c 100644
--- a/sandbox/policy/linux/bpf_audio_policy_linux.cc
+++ b/sandbox/policy/linux/bpf_audio_policy_linux.cc
@@ -66,9 +66,6 @@
 #if defined(__NR_pwrite64)
     case __NR_pwrite64:
 #endif
-#if defined(__NR_sched_setscheduler)
-    case __NR_sched_setscheduler:
-#endif
 #if defined(__NR_setsockopt)
     case __NR_setsockopt:
 #endif
diff --git a/sandbox/policy/linux/bpf_cdm_policy_linux.cc b/sandbox/policy/linux/bpf_cdm_policy_linux.cc
index fdd7aaa2..433720f 100644
--- a/sandbox/policy/linux/bpf_cdm_policy_linux.cc
+++ b/sandbox/policy/linux/bpf_cdm_policy_linux.cc
@@ -45,8 +45,6 @@
     case __NR_times:
     case __NR_uname:
       return Allow();
-    case __NR_sched_getaffinity:
-      return RestrictSchedTarget(GetPolicyPid(), sysno);
     case __NR_prlimit64:
       return RestrictPrlimitToGetrlimit(GetPolicyPid());
     default:
diff --git a/sandbox/policy/linux/bpf_gpu_policy_linux.cc b/sandbox/policy/linux/bpf_gpu_policy_linux.cc
index a821dbb..35ccbb7 100644
--- a/sandbox/policy/linux/bpf_gpu_policy_linux.cc
+++ b/sandbox/policy/linux/bpf_gpu_policy_linux.cc
@@ -93,7 +93,6 @@
     case __NR_sysinfo:
     case __NR_uname:  // https://crbug.com/1075934
       return Allow();
-    case __NR_sched_getaffinity:
     case __NR_sched_setaffinity:
       return RestrictSchedTarget(GetPolicyPid(), sysno);
     case __NR_prlimit64:
diff --git a/sandbox/policy/linux/bpf_ime_policy_linux.cc b/sandbox/policy/linux/bpf_ime_policy_linux.cc
index 6b41932e..6852c62 100644
--- a/sandbox/policy/linux/bpf_ime_policy_linux.cc
+++ b/sandbox/policy/linux/bpf_ime_policy_linux.cc
@@ -42,10 +42,6 @@
     case __NR_getrusage:
       return RestrictGetrusage();
 #endif
-#if defined(__NR_sched_getaffinity)
-    case __NR_sched_getaffinity:
-      return RestrictSchedTarget(GetPolicyPid(), sysno);
-#endif
     default:
       auto* sandbox_linux = SandboxLinux::GetInstance();
       if (sandbox_linux->ShouldBrokerHandleSyscall(sysno))
diff --git a/sandbox/policy/linux/bpf_libassistant_policy_linux.cc b/sandbox/policy/linux/bpf_libassistant_policy_linux.cc
index ba3e004..fbcd6784 100644
--- a/sandbox/policy/linux/bpf_libassistant_policy_linux.cc
+++ b/sandbox/policy/linux/bpf_libassistant_policy_linux.cc
@@ -30,10 +30,6 @@
 
 ResultExpr LibassistantProcessPolicy::EvaluateSyscall(int sysno) const {
   switch (sysno) {
-    case __NR_sched_getparam:
-    case __NR_sched_getscheduler:
-    case __NR_sched_setscheduler:
-      return RestrictSchedTarget(GetPolicyPid(), sysno);
     case __NR_socket: {
       const Arg<int> domain(0);
       const Arg<int> type(1);
diff --git a/sandbox/policy/linux/bpf_ppapi_policy_linux.cc b/sandbox/policy/linux/bpf_ppapi_policy_linux.cc
index d9e9165d..6d904020 100644
--- a/sandbox/policy/linux/bpf_ppapi_policy_linux.cc
+++ b/sandbox/policy/linux/bpf_ppapi_policy_linux.cc
@@ -33,11 +33,6 @@
     case __NR_sysinfo:
     case __NR_times:
       return Allow();
-    case __NR_sched_getaffinity:
-    case __NR_sched_getparam:
-    case __NR_sched_getscheduler:
-    case __NR_sched_setscheduler:
-      return RestrictSchedTarget(GetPolicyPid(), sysno);
     case __NR_ioctl:
       return Error(ENOTTY);  // Flash Access.
     default:
diff --git a/sandbox/policy/linux/bpf_renderer_policy_linux.cc b/sandbox/policy/linux/bpf_renderer_policy_linux.cc
index e40b4b2..5e4483a1 100644
--- a/sandbox/policy/linux/bpf_renderer_policy_linux.cc
+++ b/sandbox/policy/linux/bpf_renderer_policy_linux.cc
@@ -103,11 +103,6 @@
     case __NR_getcpu:
 #endif
       return Allow();
-    case __NR_sched_getaffinity:
-    case __NR_sched_getparam:
-    case __NR_sched_getscheduler:
-    case __NR_sched_setscheduler:
-      return RestrictSchedTarget(GetPolicyPid(), sysno);
     case __NR_prlimit64:
       // See crbug.com/662450 and setrlimit comment above.
       return RestrictPrlimit(GetPolicyPid());
diff --git a/sandbox/policy/linux/bpf_screen_ai_policy_linux.cc b/sandbox/policy/linux/bpf_screen_ai_policy_linux.cc
index 54f720dd..273bbeee 100644
--- a/sandbox/policy/linux/bpf_screen_ai_policy_linux.cc
+++ b/sandbox/policy/linux/bpf_screen_ai_policy_linux.cc
@@ -53,12 +53,6 @@
     case __NR_prlimit64:
       return RestrictPrlimitToGetrlimit(GetPolicyPid());
 
-    case __NR_sched_getaffinity:
-    case __NR_sched_getparam:
-    case __NR_sched_getscheduler:
-    case __NR_sched_setscheduler:
-      return RestrictSchedTarget(GetPolicyPid(), system_call_number);
-
     default:
       if (SyscallSets::IsGoogle3Threading(system_call_number)) {
         return RestrictGoogle3Threading(system_call_number);
diff --git a/sandbox/policy/linux/bpf_service_policy_linux.cc b/sandbox/policy/linux/bpf_service_policy_linux.cc
index b308874..32754e6 100644
--- a/sandbox/policy/linux/bpf_service_policy_linux.cc
+++ b/sandbox/policy/linux/bpf_service_policy_linux.cc
@@ -24,10 +24,6 @@
   switch (sysno) {
     case __NR_ioctl:
       return RestrictIoctl();
-    // Some third party libraries seem to call sched_getaffinity(). There's not
-    // much reason to block the syscall.
-    case __NR_sched_getaffinity:
-      return RestrictSchedTarget(GetPolicyPid(), sysno);
       // Allow the system calls below.
 #if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || \
     defined(__aarch64__)
diff --git a/sandbox/policy/linux/bpf_speech_recognition_policy_linux.cc b/sandbox/policy/linux/bpf_speech_recognition_policy_linux.cc
index 3fa559c..633d068d 100644
--- a/sandbox/policy/linux/bpf_speech_recognition_policy_linux.cc
+++ b/sandbox/policy/linux/bpf_speech_recognition_policy_linux.cc
@@ -34,15 +34,6 @@
     case __NR_getdents:
       return Allow();
 #endif
-#if defined(__NR_sched_getparam)
-    case __NR_sched_getparam:
-#endif
-#if defined(__NR_sched_getscheduler)
-    case __NR_sched_getscheduler:
-#endif
-    case __NR_sched_setscheduler:
-      // Used for starting an AudioStream when recognizing microphone data.
-      return RestrictSchedTarget(GetPolicyPid(), system_call_number);
     default:
       auto* sandbox_linux = SandboxLinux::GetInstance();
       if (sandbox_linux->ShouldBrokerHandleSyscall(system_call_number))
diff --git a/sandbox/policy/linux/bpf_tts_policy_linux.cc b/sandbox/policy/linux/bpf_tts_policy_linux.cc
index 7e40476..0d8b666 100644
--- a/sandbox/policy/linux/bpf_tts_policy_linux.cc
+++ b/sandbox/policy/linux/bpf_tts_policy_linux.cc
@@ -28,8 +28,6 @@
   switch (sysno) {
     case __NR_sysinfo:
       return Allow();
-    case __NR_sched_setscheduler:
-      return RestrictSchedTarget(GetPolicyPid(), sysno);
     default:
       break;
   }
diff --git a/sandbox/policy/linux/bpf_utility_policy_linux.cc b/sandbox/policy/linux/bpf_utility_policy_linux.cc
index f36007c..e299ce99 100644
--- a/sandbox/policy/linux/bpf_utility_policy_linux.cc
+++ b/sandbox/policy/linux/bpf_utility_policy_linux.cc
@@ -30,10 +30,6 @@
     case __NR_prlimit64:
       // Restrict prlimit() to reference only the calling process.
       return RestrictPrlimitToGetrlimit(GetPolicyPid());
-    // Some third party libraries seem to call sched_getaffinity(). There's not
-    // much reason to block the syscall.
-    case __NR_sched_getaffinity:
-      return RestrictSchedTarget(GetPolicyPid(), sysno);
     // Allow the system calls below.
     case __NR_fdatasync:
     case __NR_fsync:
diff --git a/services/audio/BUILD.gn b/services/audio/BUILD.gn
index a9b05d4..629a4eb 100644
--- a/services/audio/BUILD.gn
+++ b/services/audio/BUILD.gn
@@ -28,6 +28,8 @@
     "in_process_audio_manager_accessor.h",
     "input_controller.cc",
     "input_controller.h",
+    "input_glitch_counter.cc",
+    "input_glitch_counter.h",
     "input_stream.cc",
     "input_stream.h",
     "input_sync_writer.cc",
@@ -160,6 +162,7 @@
     "device_notifier_unittest.cc",
     "group_coordinator_unittest.cc",
     "input_controller_unittest.cc",
+    "input_glitch_counter_unittest.cc",
     "input_stream_unittest.cc",
     "input_sync_writer_unittest.cc",
     "local_muter_unittest.cc",
diff --git a/services/audio/input_glitch_counter.cc b/services/audio/input_glitch_counter.cc
new file mode 100644
index 0000000..8413d9b
--- /dev/null
+++ b/services/audio/input_glitch_counter.cc
@@ -0,0 +1,119 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include "services/audio/input_glitch_counter.h"
+#include <cstddef>
+#include <utility>
+
+#include "base/check_op.h"
+#include "base/format_macros.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/strings/stringprintf.h"
+#include "base/time/time.h"
+
+namespace audio {
+
+namespace {
+
+// Used to log if any audio glitches have been detected during an audio session.
+// Elements in this enum should not be added, deleted or rearranged.
+enum class AudioGlitchResult {
+  kNoGlitches = 0,
+  kGlitches = 1,
+  kMaxValue = kGlitches
+};
+
+}  // namespace
+
+InputGlitchCounter::InputGlitchCounter(
+    base::RepeatingCallback<void(const std::string&)> log_callback)
+    : log_callback_(std::move(log_callback)) {}
+
+InputGlitchCounter::~InputGlitchCounter() {
+  // Subtract 'trailing' error counts that will happen if the renderer process
+  // was killed or e.g. the page refreshed while the input device was open etc.
+  // The counts should then only include data from before the teardown period.
+  DCHECK_GE(write_count_, global_sample_.trailing_missed_read_deadline_count_);
+  DCHECK_GE(global_sample_.missed_read_deadline_count_,
+            global_sample_.trailing_missed_read_deadline_count_);
+  DCHECK_GE(global_sample_.dropped_data_count_,
+            global_sample_.trailing_dropped_data_count_);
+  write_count_ -= global_sample_.trailing_missed_read_deadline_count_;
+  global_sample_.missed_read_deadline_count_ -=
+      global_sample_.trailing_missed_read_deadline_count_;
+  global_sample_.dropped_data_count_ -=
+      global_sample_.trailing_dropped_data_count_;
+
+  // Log whether or not there was any dropped data at all (before the teardown
+  // period).
+  base::UmaHistogramEnumeration("Media.AudioCapturerAudioGlitches",
+                                global_sample_.dropped_data_count_ == 0
+                                    ? AudioGlitchResult::kNoGlitches
+                                    : AudioGlitchResult::kGlitches);
+
+  std::string log_string = base::StringPrintf(
+      "AISW: number of detected audio glitches: %" PRIuS " out of %" PRIuS,
+      global_sample_.dropped_data_count_, write_count_);
+  log_callback_.Run(log_string);
+
+  if (write_count_ < kSampleInterval) {
+    // The stream without trailing glitches is shorter than kSampleInterval
+    // callbacks, which means UploadCompleteSamples() has never uploaded
+    // anything. Adding stats to dedicated histograms.
+    base::UmaHistogramCounts1000("Media.AudioCapturerDroppedDataBelow10s",
+                                 global_sample_.dropped_data_count_);
+    base::UmaHistogramCounts1000(
+        "Media.AudioCapturerMissedReadDeadlineBelow10s",
+        global_sample_.missed_read_deadline_count_);
+  }
+
+  // All remaining not uploaded |complete_samples_| will be dropped, since the
+  // first of them at least partially and the rest fully consist of trailing
+  // glitches.
+}
+
+void InputGlitchCounter::ReportDroppedData(bool dropped_data) {
+  if (dropped_data) {
+    ++current_sample_.dropped_data_count_;
+    ++global_sample_.dropped_data_count_;
+    ++global_sample_.trailing_dropped_data_count_;
+  } else {
+    // Since we have just successfully written data, we can assume that the
+    // receiver is still alive, so there should not be any trailing errors.
+    // Thererfore we can upload any complete samples we have stored.
+    global_sample_.trailing_dropped_data_count_ = 0;
+    global_sample_.trailing_missed_read_deadline_count_ = 0;
+    UploadCompleteSamples();
+  }
+}
+
+void InputGlitchCounter::ReportMissedReadDeadline(bool missed_read_deadline) {
+  ++write_count_;
+  if (missed_read_deadline) {
+    ++current_sample_.missed_read_deadline_count_;
+    ++global_sample_.missed_read_deadline_count_;
+    ++global_sample_.trailing_missed_read_deadline_count_;
+  }
+
+  // If it's the end of the sample window, then it's time queue the current
+  // sample to be uploaded and start adding data to a new sample.
+  if (write_count_ % kSampleInterval == 0) {
+    // The sample will be uploaded once we know that it does not contain
+    // trailing errors.
+    complete_samples_.push_back(current_sample_);
+    current_sample_ = {};
+  }
+}
+
+void InputGlitchCounter::UploadCompleteSamples() {
+  for (Sample& sample : complete_samples_) {
+    base::UmaHistogramCounts1000("Media.AudioCapturerDroppedData10sIntervals",
+                                 sample.dropped_data_count_);
+    base::UmaHistogramCounts1000(
+        "Media.AudioCapturerMissedReadDeadline10sIntervals",
+        sample.missed_read_deadline_count_);
+  }
+  complete_samples_.clear();
+}
+
+}  // namespace audio
diff --git a/services/audio/input_glitch_counter.h b/services/audio/input_glitch_counter.h
new file mode 100644
index 0000000..70be327
--- /dev/null
+++ b/services/audio/input_glitch_counter.h
@@ -0,0 +1,81 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_AUDIO_INPUT_GLITCH_COUNTER_H_
+#define SERVICES_AUDIO_INPUT_GLITCH_COUNTER_H_
+
+#include <cstddef>
+#include <vector>
+#include "base/callback.h"
+#include "base/time/time.h"
+namespace audio {
+
+// Class for logging audio glitch data at 10 second intervals, for use by
+// InputSyncWriter. Upon destruction, logs how much data was dropped to
+// |log_callback|.
+class InputGlitchCounter {
+ public:
+  explicit InputGlitchCounter(
+      base::RepeatingCallback<void(const std::string&)> log_callback);
+  virtual ~InputGlitchCounter();
+
+  InputGlitchCounter(const InputGlitchCounter&) = delete;
+  InputGlitchCounter& operator=(const InputGlitchCounter&) = delete;
+
+  // Report either a successful attempt to write data to shared memory, in which
+  // case |dropped_data| is false, or that data was dropped for any reason
+  // (typically because the fifo or socket buffer is full), in which case
+  // |dropped_data| is true.
+  virtual void ReportDroppedData(bool dropped_data);
+
+  // Reports a call to InputSyncWriter::Write(), and whether or not the reader
+  // met the read deadline.
+  virtual void ReportMissedReadDeadline(bool missed_read_deadline);
+
+ private:
+  // Represents a sample of write statistics during a 10 second interval.
+  struct Sample {
+    // Counts the number of times InputSyncWriter::Write() was called and the
+    // shared memory was full.
+    size_t missed_read_deadline_count_ = 0;
+
+    // Counts the number times data was dropped, due to either the fifo or the
+    // socket buffer being full.
+    size_t dropped_data_count_ = 0;
+  };
+
+  void UploadCompleteSamples();
+
+  // The number of calls to ReportMissedReadDeadline(), which corresponds to the
+  // number of calls to InputSyncWriter::Write().
+  size_t write_count_ = 0;
+
+  // The current, incomplete sample. Moved to complete_samples_ every 10
+  // seconds.
+  Sample current_sample_;
+
+  // Samples that are ready to be uploaded once we are sure that they do not
+  // contain trailing errors.
+  std::vector<Sample> complete_samples_;
+
+  // Contains the data for the whole lifetime of the stream.
+  struct GlobalSample : Sample {
+    // Error counts that occur while the renderer process is being shut down,
+    // that will be subtracted when calculating the final statistics. Only used
+    // for calculating the statistics for streams of less than 10 seconds.
+    size_t trailing_missed_read_deadline_count_ = 0;
+    size_t trailing_dropped_data_count_ = 0;
+  } global_sample_;
+
+  base::RepeatingCallback<void(const std::string&)> log_callback_;
+
+  // The number of calls to ReportMissedReadDeadline(), which corresponds to
+  // InputSyncWriter::Write(), that constitute a sample period. For 10ms buffer
+  // sizes this corresponds to 10 seconds.
+  static constexpr int kSampleInterval = 1000;
+};
+
+}  // namespace audio
+
+#endif  // SERVICES_AUDIO_INPUT_GLITCH_COUNTER_H_
diff --git a/services/audio/input_glitch_counter_unittest.cc b/services/audio/input_glitch_counter_unittest.cc
new file mode 100644
index 0000000..ba69a21
--- /dev/null
+++ b/services/audio/input_glitch_counter_unittest.cc
@@ -0,0 +1,113 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/audio/input_glitch_counter.h"
+
+#include <memory>
+#include "base/test/bind.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace audio {
+namespace {
+
+const std::string kDroppedData10sIntervals =
+    "Media.AudioCapturerDroppedData10sIntervals";
+const std::string kMissedReadDeadline10sIntervals =
+    "Media.AudioCapturerMissedReadDeadline10sIntervals";
+const std::string kDroppedDataBelow10s =
+    "Media.AudioCapturerDroppedDataBelow10s";
+const std::string kMissedReadDeadlineBelow10s =
+    "Media.AudioCapturerMissedReadDeadlineBelow10s";
+
+class InputGlitchCounterTest : public ::testing::Test {
+ public:
+  InputGlitchCounterTest() = default;
+
+  InputGlitchCounterTest(const InputGlitchCounterTest&) = delete;
+  InputGlitchCounterTest& operator=(const InputGlitchCounterTest&) = delete;
+
+  base::HistogramTester histogram_tester_;
+
+  std::unique_ptr<InputGlitchCounter> input_glitch_counter_ =
+      std::make_unique<InputGlitchCounter>(
+          base::BindLambdaForTesting([](const std::string& s) {}));
+};
+
+TEST_F(InputGlitchCounterTest, IntervalHistograms) {
+  for (int i = 0; i < 1000; i++) {
+    // Miss 5 of the first 1000 deadlines.
+    input_glitch_counter_->ReportMissedReadDeadline(i % (1000 / 5) == 0);
+    // Drop 2 of the first 1000 data blocks.
+    input_glitch_counter_->ReportDroppedData(i % (1000 / 2) == 0);
+  }
+  histogram_tester_.ExpectUniqueSample(kDroppedData10sIntervals, 2, 1);
+  histogram_tester_.ExpectUniqueSample(kMissedReadDeadline10sIntervals, 5, 1);
+
+  for (int i = 0; i < 1000; i++) {
+    // Miss 10 of the second 1000 deadlines.
+    input_glitch_counter_->ReportMissedReadDeadline(i % (1000 / 10) == 0);
+    // Drop 4 of the second 1000 data blocks.
+    input_glitch_counter_->ReportDroppedData(i % (1000 / 4) == 0);
+  }
+
+  histogram_tester_.ExpectTotalCount(kDroppedData10sIntervals, 2);
+  histogram_tester_.ExpectBucketCount(kDroppedData10sIntervals, 4, 1);
+  histogram_tester_.ExpectTotalCount(kMissedReadDeadline10sIntervals, 2);
+  histogram_tester_.ExpectBucketCount(kMissedReadDeadline10sIntervals, 10, 1);
+
+  // Since the stream lasted for longer than 10 seconds, we do not expect it to
+  // upload data for the histograms for less than 10 seconds.
+  input_glitch_counter_.reset();
+  histogram_tester_.ExpectTotalCount(kDroppedDataBelow10s, 0);
+  histogram_tester_.ExpectTotalCount(kMissedReadDeadlineBelow10s, 0);
+}
+
+TEST_F(InputGlitchCounterTest, Below10sHistograms) {
+  for (int i = 0; i < 100; i++) {
+    // Miss 5 of the first 100 deadlines.
+    input_glitch_counter_->ReportMissedReadDeadline(i % (100 / 5) == 0);
+    // Drop 2 of the first 100 data blocks.
+    input_glitch_counter_->ReportDroppedData(i % (100 / 2) == 0);
+  }
+
+  // Report 30 seconds of trailing errors. We expect these not to be reflected
+  // in the histograms.
+  for (int i = 0; i < 3000; i++) {
+    input_glitch_counter_->ReportDroppedData(true);
+    input_glitch_counter_->ReportMissedReadDeadline(true);
+  }
+
+  // This histograms should be uploaded upon destruction of
+  // input_glitch_counter_.
+  histogram_tester_.ExpectTotalCount(kDroppedDataBelow10s, 0);
+  histogram_tester_.ExpectTotalCount(kMissedReadDeadlineBelow10s, 0);
+  input_glitch_counter_.reset();
+  histogram_tester_.ExpectUniqueSample(kDroppedDataBelow10s, 2, 1);
+  histogram_tester_.ExpectUniqueSample(kMissedReadDeadlineBelow10s, 5, 1);
+
+  // Since the stream was shorter than 10 seconds, no 10 second interval data
+  // should be logged.
+  histogram_tester_.ExpectTotalCount(kDroppedData10sIntervals, 0);
+  histogram_tester_.ExpectTotalCount(kMissedReadDeadline10sIntervals, 0);
+}
+
+TEST_F(InputGlitchCounterTest, BinaryGlitchMetricTrue) {
+  input_glitch_counter_->ReportDroppedData(true);
+  input_glitch_counter_->ReportDroppedData(false);
+  input_glitch_counter_.reset();
+  histogram_tester_.ExpectUniqueSample("Media.AudioCapturerAudioGlitches", 1,
+                                       1);
+}
+
+TEST_F(InputGlitchCounterTest, BinaryGlitchMetricFalse) {
+  // This drop will be considered trailing.
+  input_glitch_counter_->ReportDroppedData(true);
+  input_glitch_counter_.reset();
+  histogram_tester_.ExpectUniqueSample("Media.AudioCapturerAudioGlitches", 0,
+                                       1);
+}
+
+}  // namespace
+}  // namespace audio
diff --git a/services/audio/input_sync_writer.cc b/services/audio/input_sync_writer.cc
index fcd5c00..065180b 100644
--- a/services/audio/input_sync_writer.cc
+++ b/services/audio/input_sync_writer.cc
@@ -5,6 +5,7 @@
 #include "services/audio/input_sync_writer.h"
 
 #include <algorithm>
+#include <memory>
 #include <utility>
 
 #include "base/check.h"
@@ -14,6 +15,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
+#include "services/audio/input_glitch_counter.h"
 
 namespace audio {
 
@@ -49,7 +51,8 @@
     base::MappedReadOnlyRegion shared_memory,
     std::unique_ptr<base::CancelableSyncSocket> socket,
     uint32_t shared_memory_segment_count,
-    const media::AudioParameters& params)
+    const media::AudioParameters& params,
+    std::unique_ptr<InputGlitchCounter> glitch_counter)
     : log_callback_(std::move(log_callback)),
       socket_(std::move(socket)),
       shared_memory_region_(std::move(shared_memory.region)),
@@ -58,7 +61,8 @@
           (CHECK(shared_memory_segment_count > 0),
            shared_memory_mapping_.size() / shared_memory_segment_count)),
       creation_time_(base::TimeTicks::Now()),
-      audio_bus_memory_size_(media::AudioBus::CalculateMemorySize(params)) {
+      audio_bus_memory_size_(media::AudioBus::CalculateMemorySize(params)),
+      glitch_counter_(std::move(glitch_counter)) {
   // We use CHECKs since this class is used for IPC.
   DCHECK(log_callback_);
   CHECK(socket_);
@@ -71,6 +75,7 @@
   DVLOG(1) << "shared memory size: " << shared_memory_mapping_.size();
   DVLOG(1) << "shared memory segment count: " << shared_memory_segment_count;
   DVLOG(1) << "audio bus memory size: " << audio_bus_memory_size_;
+  DCHECK(glitch_counter_);
 
   audio_buses_.resize(shared_memory_segment_count);
 
@@ -87,72 +92,7 @@
   }
 }
 
-InputSyncWriter::~InputSyncWriter() {
-  // We log the following:
-  // - Percentage of data written to fifo (and not to shared memory).
-  // - Percentage of data dropped (fifo reached max size or socket buffer full).
-  // - Glitch yes/no (at least 1 drop).
-
-  // The amount of data that has either been dropped or successfully written.
-  // This number does not include data that is in the fifo, which we do not know
-  // if it would have been dropped or successfully written.
-  size_t total_processed_data_count =
-      dropped_data_count_ + successful_write_count_;
-
-  DCHECK_LE(trailing_shared_memory_full_count_, shared_memory_full_count_);
-  DCHECK_LE(trailing_shared_memory_full_count_, write_count_);
-  DCHECK_LE(trailing_dropped_data_count_, dropped_data_count_);
-  DCHECK_LE(trailing_dropped_data_count_, total_processed_data_count);
-
-  // Subtract 'trailing' counts that will happen if the renderer process was
-  // killed or e.g. the page refreshed while the input device was open etc.
-  // This trims off the end of both the error and write counts so that we
-  // preserve the proportion of counts before the teardown period.
-  shared_memory_full_count_ -= trailing_shared_memory_full_count_;
-  write_count_ -= trailing_shared_memory_full_count_;
-  dropped_data_count_ -= trailing_dropped_data_count_;
-  total_processed_data_count -= trailing_dropped_data_count_;
-
-  if (write_count_ == 0 || total_processed_data_count == 0)
-    return;
-
-  base::UmaHistogramEnumeration("Media.AudioCapturerAudioGlitches",
-                                dropped_data_count_ == 0
-                                    ? AudioGlitchResult::kNoGlitches
-                                    : AudioGlitchResult::kGlitches);
-
-  const int kPermilleScaling = 1000;
-  // 10%: if we have more that 10% of callbacks having issues, the details are
-  // not very interesting any more, so we just log all those cases together to
-  // have a better resolution for lower values.
-  const int kHistogramRange = kPermilleScaling / 10;
-
-  // 30 s for 10 ms buffers.
-  const int kShortStreamMaxCallbackCount = 3000;
-  const std::string suffix =
-      write_count_ < kShortStreamMaxCallbackCount ? "Short" : "Long";
-
-  int missed_deadline =
-      std::ceil(kPermilleScaling *
-                static_cast<double>(shared_memory_full_count_) / write_count_);
-
-  base::UmaHistogramCustomCounts(
-      "Media.AudioCapturerMissedReadDeadline2." + suffix,
-      std::min(missed_deadline, kHistogramRange), 0, kHistogramRange + 1, 100);
-
-  int dropped_data =
-      std::ceil(kPermilleScaling * static_cast<double>(dropped_data_count_) /
-                total_processed_data_count);
-
-  base::UmaHistogramCustomCounts("Media.AudioCapturerDroppedData2." + suffix,
-                                 std::min(dropped_data, kHistogramRange), 0,
-                                 kHistogramRange + 1, 100);
-
-  std::string log_string = base::StringPrintf(
-      "AISW: number of detected audio glitches: %" PRIuS " out of %" PRIuS,
-      dropped_data_count_, total_processed_data_count);
-  log_callback_.Run(log_string);
-}
+InputSyncWriter::~InputSyncWriter() = default;
 
 // static
 std::unique_ptr<InputSyncWriter> InputSyncWriter::Create(
@@ -181,9 +121,11 @@
     return nullptr;
   }
 
+  auto glitch_counter = std::make_unique<InputGlitchCounter>(log_callback);
+
   return std::make_unique<InputSyncWriter>(
       std::move(log_callback), std::move(shared_memory), std::move(socket),
-      shared_memory_segment_count, params);
+      shared_memory_segment_count, params, std::move(glitch_counter));
 }
 
 base::ReadOnlySharedMemoryRegion InputSyncWriter::TakeSharedMemoryRegion() {
@@ -197,7 +139,6 @@
                             base::TimeTicks capture_time) {
   TRACE_EVENT1("audio", "InputSyncWriter::Write", "capture time (ms)",
                (capture_time - base::TimeTicks()).InMillisecondsF());
-  ++write_count_;
   CheckTimeSinceLastWrite();
 
   // Check that the renderer side has read data so that we don't overwrite data
@@ -218,27 +159,23 @@
     }
   }
 
+  const size_t segment_count = audio_buses_.size();
+  // If the shared memory is full, then we consider the deadline to be missed.
+  glitch_counter_->ReportMissedReadDeadline(number_of_filled_segments_ ==
+                                            segment_count);
+
   // If there is data in the fifo, write as much of it to shared memory as
   // possible.
   if (!overflow_data_.empty()) {
-    const size_t segment_count = audio_buses_.size();
     auto data_it = overflow_data_.begin();
 
     while (data_it != overflow_data_.end() &&
            number_of_filled_segments_ < segment_count) {
-      // Write parameters to shared memory.
-      if (WriteDataToCurrentSegment(*data_it->audio_bus_, data_it->volume_,
-                                    data_it->key_pressed_,
-                                    data_it->capture_time_)) {
-        ++successful_write_count_;
-        trailing_shared_memory_full_count_ = 0;
-        trailing_dropped_data_count_ = 0;
-      } else {
-        // This happens only if writing to the socket buffer fails, which should
-        // be rare.
-        ++dropped_data_count_;
-        ++trailing_dropped_data_count_;
-      }
+      // Write parameters to shared memory, and report whether it was dropped.
+      const bool successful_write = WriteDataToCurrentSegment(
+          *data_it->audio_bus_, data_it->volume_, data_it->key_pressed_,
+          data_it->capture_time_);
+      glitch_counter_->ReportDroppedData(!successful_write);
       ++data_it;
     }
 
@@ -255,24 +192,13 @@
   // put it in the fifo.
   if (number_of_filled_segments_ < audio_buses_.size()) {
     DCHECK(overflow_data_.empty());
-    if (WriteDataToCurrentSegment(*data, volume, key_pressed, capture_time)) {
-      ++successful_write_count_;
-      trailing_shared_memory_full_count_ = 0;
-      trailing_dropped_data_count_ = 0;
-    } else {
-      // This happens only if writing to the socket buffer fails, which should
-      // be rare.
-      ++dropped_data_count_;
-      ++trailing_dropped_data_count_;
-    }
+    const bool successful_write =
+        WriteDataToCurrentSegment(*data, volume, key_pressed, capture_time);
+    glitch_counter_->ReportDroppedData(!successful_write);
   } else {
     if (!PushDataToFifo(*data, volume, key_pressed, capture_time)) {
-      ++dropped_data_count_;
-      ++trailing_dropped_data_count_;
+      glitch_counter_->ReportDroppedData(true);
     }
-
-    ++shared_memory_full_count_;
-    ++trailing_shared_memory_full_count_;
   }
 }
 
@@ -315,23 +241,21 @@
   TRACE_EVENT1("audio", "InputSyncWriter::PushDataToFifo", "capture time (ms)",
                (capture_time - base::TimeTicks()).InMillisecondsF());
   if (overflow_data_.size() == kMaxOverflowBusesSize) {
-    // We use |dropped_data_count_| for capping number of log messages.
-    // |dropped_data_count_| also includes socket Send() errors, but those
-    // should be rare.
     TRACE_EVENT_INSTANT0(
         "audio", "InputSyncWriter::PushDataToFifo - overflow - dropped data",
         TRACE_EVENT_SCOPE_THREAD);
-    if (dropped_data_count_ <= 50 && dropped_data_count_ % 10 == 0) {
+    if (fifo_full_count_ <= 50 && fifo_full_count_ % 10 == 0) {
       static const char* error_message = "AISW: No room in fifo.";
       LOG(WARNING) << error_message;
       log_callback_.Run(error_message);
-      if (dropped_data_count_ == 50) {
+      if (fifo_full_count_ == 50) {
         static const char* cap_error_message =
             "AISW: Log cap reached, suppressing further fifo overflow logs.";
         LOG(WARNING) << cap_error_message;
         log_callback_.Run(error_message);
       }
     }
+    ++fifo_full_count_;
     return false;
   }
 
diff --git a/services/audio/input_sync_writer.h b/services/audio/input_sync_writer.h
index 7758f2d..b6394176 100644
--- a/services/audio/input_sync_writer.h
+++ b/services/audio/input_sync_writer.h
@@ -17,6 +17,7 @@
 #include "base/sync_socket.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
+#include "input_glitch_counter.h"
 #include "media/base/audio_bus.h"
 #include "media/base/audio_parameters.h"
 #include "services/audio/input_controller.h"
@@ -42,7 +43,8 @@
       base::MappedReadOnlyRegion shared_memory,
       std::unique_ptr<base::CancelableSyncSocket> socket,
       uint32_t shared_memory_segment_count,
-      const media::AudioParameters& params);
+      const media::AudioParameters& params,
+      std::unique_ptr<InputGlitchCounter> glitch_counter);
 
   InputSyncWriter(const InputSyncWriter&) = delete;
   InputSyncWriter& operator=(const InputSyncWriter&) = delete;
@@ -134,31 +136,13 @@
   // ensure the we don't overwrite data that hasn't been read yet.
   size_t number_of_filled_segments_ = 0;
 
-  // Counts the total number of calls to InputSyncWriter::Write().
-  size_t write_count_ = 0;
-
-  // Counts the number of calls to InputSyncWriter::Write() when the shared
-  // memory is full and we instead have to attempt to write to the fifo.
-  size_t shared_memory_full_count_ = 0;
-
-  // Counts the number of times that data is dropped, due to either the fifo or
-  // the socket buffer being full.
-  size_t dropped_data_count_ = 0;
-
-  // Counts the number of times we have written data to the shared memory and
-  // successfully communicated the write over the socket.
-  size_t successful_write_count_ = 0;
+  // Used for logging.
+  size_t fifo_full_count_ = 0;
 
   // Denotes that the most recent socket error has been logged. Used to avoid
   // log spam.
   bool had_socket_error_ = false;
 
-  // Counts the missed deadlines and drops we get during renderer process
-  // teardown so that we can account for that (subtract) when we calculate the
-  // overall counts.
-  size_t trailing_shared_memory_full_count_ = 0;
-  size_t trailing_dropped_data_count_ = 0;
-
   // Vector of audio buses allocated during construction and deleted in the
   // destructor.
   std::vector<std::unique_ptr<media::AudioBus>> audio_buses_;
@@ -189,6 +173,8 @@
   };
 
   std::vector<OverflowData> overflow_data_;
+
+  std::unique_ptr<InputGlitchCounter> glitch_counter_;
 };
 
 }  // namespace audio
diff --git a/services/audio/input_sync_writer_unittest.cc b/services/audio/input_sync_writer_unittest.cc
index 060bcb5..2be1cbd 100644
--- a/services/audio/input_sync_writer_unittest.cc
+++ b/services/audio/input_sync_writer_unittest.cc
@@ -23,6 +23,7 @@
 #include "media/base/audio_bus.h"
 #include "media/base/audio_parameters.h"
 #include "media/base/channel_layout.h"
+#include "services/audio/input_glitch_counter.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -103,6 +104,18 @@
   uint32_t read_buffer_index_;
 };
 
+class MockInputGlitchCounter : public InputGlitchCounter {
+ public:
+  explicit MockInputGlitchCounter(
+      base::RepeatingCallback<void(const std::string&)> log_callback)
+      : InputGlitchCounter(std::move(log_callback)) {}
+  MockInputGlitchCounter(const MockInputGlitchCounter&) = delete;
+  MockInputGlitchCounter& operator=(const MockInputGlitchCounter&) = delete;
+
+  MOCK_METHOD1(ReportDroppedData, void(bool));
+  MOCK_METHOD1(ReportMissedReadDeadline, void(bool));
+};
+
 class InputSyncWriterTest : public testing::Test {
  public:
   InputSyncWriterTest() {
@@ -119,9 +132,14 @@
 
     auto socket = std::make_unique<MockCancelableSyncSocket>(kSegments);
     socket_ = socket.get();
+
+    auto mock_input_glitch_counter =
+        std::make_unique<MockInputGlitchCounter>(mock_logger_.Get());
+    mock_input_glitch_counter_ = mock_input_glitch_counter.get();
+
     writer_ = std::make_unique<InputSyncWriter>(
         mock_logger_.Get(), std::move(shared_memory), std::move(socket),
-        kSegments, audio_params);
+        kSegments, audio_params, std::move(mock_input_glitch_counter));
     audio_bus_ = media::AudioBus::Create(audio_params);
   }
 
@@ -163,12 +181,15 @@
   MockLogger mock_logger_;
   std::unique_ptr<InputSyncWriter> writer_;
   raw_ptr<MockCancelableSyncSocket> socket_;
+  raw_ptr<MockInputGlitchCounter> mock_input_glitch_counter_;
   std::unique_ptr<media::AudioBus> audio_bus_;
 };
 
 TEST_F(InputSyncWriterTest, SingleWriteAndRead) {
   EXPECT_CALL(mock_logger_, Run(_)).Times(GetTotalNumberOfExpectedLogCalls(0));
 
+  EXPECT_CALL(*mock_input_glitch_counter_, ReportDroppedData(false));
+  EXPECT_CALL(*mock_input_glitch_counter_, ReportMissedReadDeadline(false));
   writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
   EXPECT_TRUE(TestSocketAndFifoExpectations(1, 0, 0));
 
@@ -180,6 +201,8 @@
   EXPECT_CALL(mock_logger_, Run(_)).Times(GetTotalNumberOfExpectedLogCalls(0));
 
   for (int i = 1; i <= 2 * kSegments; ++i) {
+    EXPECT_CALL(*mock_input_glitch_counter_, ReportDroppedData(false));
+    EXPECT_CALL(*mock_input_glitch_counter_, ReportMissedReadDeadline(false));
     writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
     EXPECT_TRUE(TestSocketAndFifoExpectations(1, 0, 0));
     socket_->Read(1);
@@ -192,6 +215,8 @@
 
   // Fill the ring buffer.
   for (int i = 1; i <= kSegments; ++i) {
+    EXPECT_CALL(*mock_input_glitch_counter_, ReportDroppedData(false));
+    EXPECT_CALL(*mock_input_glitch_counter_, ReportMissedReadDeadline(false));
     writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
     EXPECT_TRUE(TestSocketAndFifoExpectations(i, 0, 0));
   }
@@ -199,6 +224,7 @@
   // Now the ring buffer is full, do more writes. We should start filling the
   // fifo and should get one extra log call for that.
   for (size_t i = 1; i <= kSegments; ++i) {
+    EXPECT_CALL(*mock_input_glitch_counter_, ReportMissedReadDeadline(true));
     writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
     EXPECT_TRUE(TestSocketAndFifoExpectations(kSegments, 0, i));
   }
@@ -209,6 +235,8 @@
 
   // Fill the ring buffer.
   for (int i = 1; i <= kSegments; ++i) {
+    EXPECT_CALL(*mock_input_glitch_counter_, ReportDroppedData(false));
+    EXPECT_CALL(*mock_input_glitch_counter_, ReportMissedReadDeadline(false));
     writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
   }
   EXPECT_TRUE(TestSocketAndFifoExpectations(kSegments, 0, 0));
@@ -222,12 +250,15 @@
   // Fill up again. The first write should do receive until that queue is
   // empty.
   for (int i = kSegments - buffers_to_read + 1; i <= kSegments; ++i) {
+    EXPECT_CALL(*mock_input_glitch_counter_, ReportDroppedData(false));
+    EXPECT_CALL(*mock_input_glitch_counter_, ReportMissedReadDeadline(false));
     writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
     EXPECT_TRUE(TestSocketAndFifoExpectations(i, 0, 0));
   }
 
   // Another write, should put the data in the fifo, and render an extra log
   // call.
+  EXPECT_CALL(*mock_input_glitch_counter_, ReportMissedReadDeadline(true));
   writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
   EXPECT_TRUE(TestSocketAndFifoExpectations(kSegments, 0, 1));
 
@@ -238,6 +269,8 @@
 
   // Another write, should do receive until that queue is empty and write both
   // the data in the fifo and the new data, and render a log call.
+  EXPECT_CALL(*mock_input_glitch_counter_, ReportDroppedData(false)).Times(2);
+  EXPECT_CALL(*mock_input_glitch_counter_, ReportMissedReadDeadline(false));
   writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
   EXPECT_TRUE(TestSocketAndFifoExpectations(2, 0, 0));
 
@@ -251,6 +284,8 @@
 
   // Fill the ring buffer.
   for (int i = 1; i <= kSegments; ++i) {
+    EXPECT_CALL(*mock_input_glitch_counter_, ReportDroppedData(false));
+    EXPECT_CALL(*mock_input_glitch_counter_, ReportMissedReadDeadline(false));
     writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
   }
   EXPECT_TRUE(TestSocketAndFifoExpectations(kSegments, 0, 0));
@@ -258,11 +293,14 @@
   // Fill the fifo. Should render one log call for starting filling it.
   const size_t max_fifo_size = InputSyncWriter::kMaxOverflowBusesSize;
   for (size_t i = 1; i <= max_fifo_size; ++i) {
+    EXPECT_CALL(*mock_input_glitch_counter_, ReportMissedReadDeadline(true));
     writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
   }
   EXPECT_TRUE(TestSocketAndFifoExpectations(kSegments, 0, max_fifo_size));
 
   // Another write, data should be dropped and render one log call.
+  EXPECT_CALL(*mock_input_glitch_counter_, ReportDroppedData(true));
+  EXPECT_CALL(*mock_input_glitch_counter_, ReportMissedReadDeadline(true));
   writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
   EXPECT_TRUE(TestSocketAndFifoExpectations(kSegments, 0, max_fifo_size));
 }
@@ -272,6 +310,8 @@
 
   // Fill the ring buffer.
   for (int i = 1; i <= kSegments; ++i) {
+    EXPECT_CALL(*mock_input_glitch_counter_, ReportDroppedData(false));
+    EXPECT_CALL(*mock_input_glitch_counter_, ReportMissedReadDeadline(false));
     writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
   }
   EXPECT_TRUE(TestSocketAndFifoExpectations(kSegments, 0, 0));
@@ -279,6 +319,7 @@
   // Write more data, should be put in the fifo and render one log call for
   // starting filling it.
   for (size_t i = 1; i <= 2 * kSegments; ++i) {
+    EXPECT_CALL(*mock_input_glitch_counter_, ReportMissedReadDeadline(true));
     writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
   }
   EXPECT_TRUE(TestSocketAndFifoExpectations(kSegments, 0, 2 * kSegments));
@@ -290,6 +331,9 @@
 
   // Another write should fill up the ring buffer with data from the fifo and
   // put this data into the fifo.
+  EXPECT_CALL(*mock_input_glitch_counter_, ReportDroppedData(false))
+      .Times(kSegments);
+  EXPECT_CALL(*mock_input_glitch_counter_, ReportMissedReadDeadline(false));
   writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
   EXPECT_TRUE(TestSocketAndFifoExpectations(kSegments, 0, kSegments + 1));
 
@@ -300,6 +344,9 @@
 
   // Another write should fill up the ring buffer with data from the fifo and
   // put this data into the fifo.
+  EXPECT_CALL(*mock_input_glitch_counter_, ReportDroppedData(false))
+      .Times(kSegments);
+  EXPECT_CALL(*mock_input_glitch_counter_, ReportMissedReadDeadline(false));
   writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
   EXPECT_TRUE(TestSocketAndFifoExpectations(kSegments, 0, 2));
 
@@ -310,6 +357,8 @@
 
   // Another write should put the remaining data in the fifo in the ring buffer
   // together with this data. Should render a log call for emptying the fifo.
+  EXPECT_CALL(*mock_input_glitch_counter_, ReportDroppedData(false)).Times(3);
+  EXPECT_CALL(*mock_input_glitch_counter_, ReportMissedReadDeadline(false));
   writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
   EXPECT_TRUE(TestSocketAndFifoExpectations(3, 0, 0));
 
@@ -320,12 +369,20 @@
   // Fill the ring buffer and part of the fifo. Should render one log call for
   // starting filling it.
   for (int i = 1; i <= kSegments + 2; ++i) {
+    if (i <= kSegments) {
+      EXPECT_CALL(*mock_input_glitch_counter_, ReportDroppedData(false));
+      EXPECT_CALL(*mock_input_glitch_counter_, ReportMissedReadDeadline(false));
+    } else {
+      EXPECT_CALL(*mock_input_glitch_counter_, ReportMissedReadDeadline(true));
+    }
     writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
   }
   EXPECT_TRUE(TestSocketAndFifoExpectations(kSegments, 0, 2));
 
   // Empty both. Should render a log call for emptying the fifo.
   socket_->Read(kSegments);
+  EXPECT_CALL(*mock_input_glitch_counter_, ReportDroppedData(false)).Times(3);
+  EXPECT_CALL(*mock_input_glitch_counter_, ReportMissedReadDeadline(false));
   writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
   socket_->Read(3);
   EXPECT_TRUE(TestSocketAndFifoExpectations(0, 3 * sizeof(uint32_t), 0));
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index c926c671..c55b977 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -3433,21 +3433,6 @@
             ]
         }
     ],
-    "CrostiniLxd4Rollout": [
-        {
-            "platforms": [
-                "chromeos"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled_V2",
-                    "enable_features": [
-                        "CrostiniUseLxd4"
-                    ]
-                }
-            ]
-        }
-    ],
     "CursiveStylusPreinstall": [
         {
             "platforms": [
@@ -11977,20 +11962,20 @@
     "WebRTC-FrameBuffer3": [
         {
             "platforms": [
-                "windows",
-                "mac",
+                "android",
+                "android_webview",
                 "chromeos",
                 "chromeos_lacros",
-                "fuchsia",
                 "linux",
-                "ios",
-                "android",
-                "android_weblayer",
-                "android_webview"
+                "mac",
+                "windows"
             ],
             "experiments": [
                 {
-                    "name": "arm:SyncDecoding,_Beta"
+                    "name": "arm:SyncDecoding,_Beta50",
+                    "enable_features": [
+                        "WebRtcMetronome"
+                    ]
                 }
             ]
         }
diff --git a/third_party/blink/public/web/modules/mediastream/media_stream_video_source.h b/third_party/blink/public/web/modules/mediastream/media_stream_video_source.h
index ad6b8b1..1c4900b 100644
--- a/third_party/blink/public/web/modules/mediastream/media_stream_video_source.h
+++ b/third_party/blink/public/web/modules/mediastream/media_stream_video_source.h
@@ -223,7 +223,7 @@
 
   using WebPlatformMediaStreamSource::GetTaskRunner;
 
-  virtual base::WeakPtr<MediaStreamVideoSource> GetWeakPtr() const = 0;
+  virtual base::WeakPtr<MediaStreamVideoSource> GetWeakPtr() = 0;
 
  protected:
   // MediaStreamSource implementation.
diff --git a/third_party/blink/renderer/core/css/document_style_sheet_collection.cc b/third_party/blink/renderer/core/css/document_style_sheet_collection.cc
index aaabb39..8f1dd4c 100644
--- a/third_party/blink/renderer/core/css/document_style_sheet_collection.cc
+++ b/third_party/blink/renderer/core/css/document_style_sheet_collection.cc
@@ -50,6 +50,8 @@
 void DocumentStyleSheetCollection::CollectStyleSheetsFromCandidates(
     StyleEngine& engine,
     DocumentStyleSheetCollector& collector) {
+  StyleEngine::RuleSetScope rule_set_scope;
+
   for (Node* n : style_sheet_candidate_nodes_) {
     StyleSheetCandidate candidate(*n);
 
@@ -63,12 +65,13 @@
 
     collector.AppendSheetForList(sheet);
     if (!candidate.CanBeActivated(
-            GetDocument().GetStyleEngine().PreferredStylesheetSetName()))
+            GetDocument().GetStyleEngine().PreferredStylesheetSetName())) {
       continue;
+    }
 
     CSSStyleSheet* css_sheet = To<CSSStyleSheet>(sheet);
-    collector.AppendActiveStyleSheet(
-        std::make_pair(css_sheet, engine.RuleSetForSheet(*css_sheet)));
+    collector.AppendActiveStyleSheet(std::make_pair(
+        css_sheet, rule_set_scope.RuleSetForSheet(engine, css_sheet)));
   }
   if (!GetTreeScope().HasAdoptedStyleSheets())
     return;
diff --git a/third_party/blink/renderer/core/css/shadow_tree_style_sheet_collection.cc b/third_party/blink/renderer/core/css/shadow_tree_style_sheet_collection.cc
index 9f2d36a..4efe530a 100644
--- a/third_party/blink/renderer/core/css/shadow_tree_style_sheet_collection.cc
+++ b/third_party/blink/renderer/core/css/shadow_tree_style_sheet_collection.cc
@@ -48,6 +48,8 @@
 void ShadowTreeStyleSheetCollection::CollectStyleSheets(
     StyleEngine& engine,
     StyleSheetCollection& collection) {
+  StyleEngine::RuleSetScope rule_set_scope;
+
   for (Node* n : style_sheet_candidate_nodes_) {
     StyleSheetCandidate candidate(*n);
     DCHECK(!candidate.IsXSL());
@@ -59,8 +61,8 @@
     collection.AppendSheetForList(sheet);
     if (candidate.CanBeActivated(g_null_atom)) {
       CSSStyleSheet* css_sheet = To<CSSStyleSheet>(sheet);
-      collection.AppendActiveStyleSheet(
-          std::make_pair(css_sheet, engine.RuleSetForSheet(*css_sheet)));
+      collection.AppendActiveStyleSheet(std::make_pair(
+          css_sheet, rule_set_scope.RuleSetForSheet(engine, css_sheet)));
     }
   }
   if (!GetTreeScope().HasAdoptedStyleSheets())
diff --git a/third_party/blink/renderer/core/css/style_engine.cc b/third_party/blink/renderer/core/css/style_engine.cc
index 529bd740..73cd5aa5 100644
--- a/third_party/blink/renderer/core/css/style_engine.cc
+++ b/third_party/blink/renderer/core/css/style_engine.cc
@@ -658,6 +658,23 @@
                                           add_rule_flags);
 }
 
+RuleSet* StyleEngine::RuleSetScope::RuleSetForSheet(StyleEngine& engine,
+                                                    CSSStyleSheet* css_sheet) {
+  RuleSet* rule_set = engine.RuleSetForSheet(*css_sheet);
+  if (rule_set && rule_set->HasCascadeLayers() &&
+      !css_sheet->Contents()->HasSingleOwnerNode() &&
+      !layer_rule_sets_.insert(rule_set).is_new_entry) {
+    // The condition above is met for a stylesheet with cascade layers which
+    // shares StyleSheetContents with another stylesheet in this TreeScope.
+    // WillMutateRules() creates a unique StyleSheetContents for this sheet to
+    // avoid incorrectly identifying two separate anonymous layers as the same
+    // layer.
+    css_sheet->WillMutateRules();
+    rule_set = engine.RuleSetForSheet(*css_sheet);
+  }
+  return rule_set;
+}
+
 void StyleEngine::ClearResolvers() {
   DCHECK(!GetDocument().InStyleRecalc());
 
diff --git a/third_party/blink/renderer/core/css/style_engine.h b/third_party/blink/renderer/core/css/style_engine.h
index ba55cc2..dee045fc 100644
--- a/third_party/blink/renderer/core/css/style_engine.h
+++ b/third_party/blink/renderer/core/css/style_engine.h
@@ -247,6 +247,24 @@
     return global_rule_set_->WatchedSelectorsRuleSet();
   }
 
+  // Helper class for making sure RuleSets that are ensured when collecting
+  // sheets for a TreeScope are not shared between two equal sheets which
+  // contain @layer rules since anonymous layers need to be unique.
+  class RuleSetScope {
+    STACK_ALLOCATED();
+
+   public:
+    RuleSetScope() = default;
+
+    // Ensure a RuleSet for the passed in css_sheet
+    RuleSet* RuleSetForSheet(StyleEngine& engine, CSSStyleSheet* css_sheet);
+
+   private:
+    // Keep track of ensured RuleSets with @layer rules to detect
+    // StyleSheetContents sharing.
+    HeapHashSet<Member<const RuleSet>> layer_rule_sets_;
+  };
+
   RuleSet* RuleSetForSheet(CSSStyleSheet&);
   void MediaQueryAffectingValueChanged(MediaValueChange change);
   void UpdateActiveStyle();
diff --git a/third_party/blink/renderer/core/html/html_script_element.cc b/third_party/blink/renderer/core/html/html_script_element.cc
index cae3ce1..487f29cd 100644
--- a/third_party/blink/renderer/core/html/html_script_element.cc
+++ b/third_party/blink/renderer/core/html/html_script_element.cc
@@ -165,11 +165,11 @@
       string_or_trusted_script, GetExecutionContext(), exception_state);
   if (exception_state.HadException())
     return;
-  // https://w3c.github.io/webappsec-trusted-types/dist/spec/#setting-slot-values
-  // On setting, the innerText [...] perform the regular steps, and then set
-  // content object's [[ScriptText]] internal slot value [...].
-  HTMLElement::setInnerText(value);
+  // https://w3c.github.io/trusted-types/dist/spec/#setting-slot-values
+  // "On setting the innerText [...]: Set [[ScriptText]] internal slot value to
+  // the stringified attribute value. Perform the usual attribute setter steps."
   script_text_internal_slot_ = ParkableString(value.Impl());
+  HTMLElement::setInnerText(value);
 }
 
 void HTMLScriptElement::setTextContentForBinding(
@@ -179,19 +179,15 @@
       TrustedTypesCheckForScript(value, GetExecutionContext(), exception_state);
   if (exception_state.HadException())
     return;
-  // https://w3c.github.io/webappsec-trusted-types/dist/spec/#setting-slot-values
-  // On setting, [..] textContent [..] perform the regular steps, and then set
-  // content object's [[ScriptText]] internal slot value [...].
-  Node::setTextContent(string);
-  script_text_internal_slot_ = ParkableString(string.Impl());
+  setTextContent(string);
 }
 
 void HTMLScriptElement::setTextContent(const String& string) {
-  // https://w3c.github.io/webappsec-trusted-types/dist/spec/#setting-slot-values
-  // On setting, [..] textContent [..] perform the regular steps, and then set
-  // content object's [[ScriptText]] internal slot value [...].
-  Node::setTextContent(string);
+  // https://w3c.github.io/trusted-types/dist/spec/#setting-slot-values
+  // "On setting [.. textContent ..]: Set [[ScriptText]] internal slot value to
+  // the stringified attribute value. Perform the usual attribute setter steps."
   script_text_internal_slot_ = ParkableString(string.Impl());
+  Node::setTextContent(string);
 }
 
 void HTMLScriptElement::setAsync(bool async) {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc
index 86dc678..a14ad80 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc
@@ -988,17 +988,6 @@
 
     const auto& first_column =
         To<NGPhysicalBoxFragment>(new_columns[0].Fragment());
-    if (!has_processed_first_column_) {
-      has_processed_first_column_ = true;
-
-      // According to the spec, we should only look for a baseline in the first
-      // column.
-      //
-      // TODO(layout-dev): It might make sense to look for baselines inside
-      // every column that's first in a row, not just the first column in the
-      // multicol container.
-      PropagateBaselineFromChild(first_column, row_offset);
-    }
 
     // Only the first column in a row may attempt to place any unpositioned
     // list-item. This matches the behavior in Gecko, and also to some extent
@@ -1017,6 +1006,7 @@
   for (auto result_with_offset : new_columns) {
     const NGPhysicalBoxFragment& column = result_with_offset.Fragment();
     container_builder_.AddChild(column, result_with_offset.offset);
+    PropagateBaselineFromChild(column, result_with_offset.offset.block_offset);
   }
 
   if (min_break_appeal)
@@ -1146,21 +1136,21 @@
 void NGColumnLayoutAlgorithm::PropagateBaselineFromChild(
     const NGPhysicalBoxFragment& child,
     LayoutUnit block_offset) {
-  // Bail if a baseline was already found.
-  if (container_builder_.FirstBaseline())
-    return;
+  NGBoxFragment fragment(ConstraintSpace().GetWritingDirection(), child);
 
-  // According to the spec, multicol containers have no "last baseline set", so,
-  // unless we're looking for a "first baseline set", we have no work to do.
-  if (ConstraintSpace().BaselineAlgorithmType() ==
-      NGBaselineAlgorithmType::kInlineBlock)
-    return;
+  // Only propagate the first-baseline from the first-column.
+  if (child.IsFirstForNode() && !container_builder_.FirstBaseline()) {
+    if (auto first_baseline = fragment.FirstBaseline())
+      container_builder_.SetFirstBaseline(block_offset + *first_baseline);
+  }
 
-  NGBoxFragment logical_fragment(ConstraintSpace().GetWritingDirection(),
-                                 child);
-
-  if (auto baseline = logical_fragment.FirstBaseline())
-    container_builder_.SetFirstBaseline(block_offset + *baseline);
+  // The last-baseline is the lowest last-baseline of all fragments.
+  if (auto last_baseline = fragment.LastBaseline()) {
+    LayoutUnit baseline =
+        std::max(block_offset + *last_baseline,
+                 container_builder_.LastBaseline().value_or(LayoutUnit::Min()));
+    container_builder_.SetLastBaseline(baseline);
+  }
   container_builder_.SetUseLastBaselineForInlineBaseline();
 }
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h
index 135fabd9..6ce5994 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h
@@ -144,8 +144,6 @@
   // the first piece of content of the multicol container. It is used to check
   // if we're at a valid class A  breakpoint (between block-level siblings).
   bool has_processed_first_child_ = false;
-
-  bool has_processed_first_column_ = false;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/breakout_box/pushable_media_stream_video_source.cc b/third_party/blink/renderer/modules/breakout_box/pushable_media_stream_video_source.cc
index d32ec4f..767d1d1 100644
--- a/third_party/blink/renderer/modules/breakout_box/pushable_media_stream_video_source.cc
+++ b/third_party/blink/renderer/modules/breakout_box/pushable_media_stream_video_source.cc
@@ -174,7 +174,7 @@
 }
 
 base::WeakPtr<MediaStreamVideoSource>
-PushableMediaStreamVideoSource::GetWeakPtr() const {
+PushableMediaStreamVideoSource::GetWeakPtr() {
   return weak_factory_.GetWeakPtr();
 }
 
@@ -189,7 +189,7 @@
       GetTaskRunner(),
       WTF::BindRepeating(
           &PushableMediaStreamVideoSource::ProcessFeedbackInternal,
-          weak_factory_.GetWeakPtr()));
+          weak_factory_.GetMutableWeakPtr()));
 }
 
 void PushableMediaStreamVideoSource::ProcessFeedbackInternal(
diff --git a/third_party/blink/renderer/modules/breakout_box/pushable_media_stream_video_source.h b/third_party/blink/renderer/modules/breakout_box/pushable_media_stream_video_source.h
index 1caf8d7..072ac99e 100644
--- a/third_party/blink/renderer/modules/breakout_box/pushable_media_stream_video_source.h
+++ b/third_party/blink/renderer/modules/breakout_box/pushable_media_stream_video_source.h
@@ -100,7 +100,7 @@
       EncodedVideoFrameCB encoded_frame_callback,
       VideoCaptureCropVersionCB crop_version_callback) override;
   void StopSourceImpl() override;
-  base::WeakPtr<MediaStreamVideoSource> GetWeakPtr() const override;
+  base::WeakPtr<MediaStreamVideoSource> GetWeakPtr() override;
   void SetCanDiscardAlpha(bool can_discard_alpha) override;
   // This function can be called on any thread.
   media::VideoCaptureFeedbackCB GetFeedbackCallback() const override;
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_set_test.cc b/third_party/blink/renderer/modules/mediastream/media_stream_set_test.cc
index 3cb4c34..e8485237 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_set_test.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_set_test.cc
@@ -32,7 +32,7 @@
             blink::scheduler::GetSingleThreadTaskRunnerForTesting()) {}
 
  private:
-  base::WeakPtr<MediaStreamVideoSource> GetWeakPtr() const override {
+  base::WeakPtr<MediaStreamVideoSource> GetWeakPtr() override {
     return weak_factory_.GetWeakPtr();
   }
 
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.cc b/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.cc
index a652fde..c16f9966 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.cc
@@ -222,7 +222,7 @@
 }
 
 base::WeakPtr<MediaStreamVideoSource>
-MediaStreamVideoCapturerSource::GetWeakPtr() const {
+MediaStreamVideoCapturerSource::GetWeakPtr() {
   return weak_factory_.GetWeakPtr();
 }
 
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.h b/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.h
index 79517f0..ef777626 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.h
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.h
@@ -99,7 +99,7 @@
   absl::optional<uint32_t> GetNextCropVersion() override;
 #endif
   uint32_t GetCropVersion() const override;
-  base::WeakPtr<MediaStreamVideoSource> GetWeakPtr() const override;
+  base::WeakPtr<MediaStreamVideoSource> GetWeakPtr() override;
 
   // Method to bind as RunningCallback in VideoCapturerSource::StartCapture().
   void OnRunStateChanged(const media::VideoCaptureParams& new_capture_params,
diff --git a/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.cc b/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.cc
index 63f24cd..390ed4ba 100644
--- a/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.cc
+++ b/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.cc
@@ -72,8 +72,7 @@
   is_suspended_ = !has_consumers;
 }
 
-base::WeakPtr<MediaStreamVideoSource> MockMediaStreamVideoSource::GetWeakPtr()
-    const {
+base::WeakPtr<MediaStreamVideoSource> MockMediaStreamVideoSource::GetWeakPtr() {
   return weak_factory_.GetWeakPtr();
 }
 
diff --git a/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.h b/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.h
index 3998710..f7aa0aab 100644
--- a/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.h
+++ b/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.h
@@ -86,7 +86,7 @@
   // Implements blink::MediaStreamVideoSource.
   void RequestRefreshFrame() override;
   void OnHasConsumers(bool has_consumers) override;
-  base::WeakPtr<MediaStreamVideoSource> GetWeakPtr() const override;
+  base::WeakPtr<MediaStreamVideoSource> GetWeakPtr() override;
 
  protected:
   // Implements MediaStreamSource.
diff --git a/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.cc b/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.cc
index 0d84cf38..976ffc2 100644
--- a/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.cc
+++ b/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.cc
@@ -399,8 +399,8 @@
   }
 }
 
-base::WeakPtr<MediaStreamVideoSource> MediaStreamRemoteVideoSource::GetWeakPtr()
-    const {
+base::WeakPtr<MediaStreamVideoSource>
+MediaStreamRemoteVideoSource::GetWeakPtr() {
   return weak_factory_.GetWeakPtr();
 }
 
diff --git a/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.h b/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.h
index ee0fea3..cdeb7c5 100644
--- a/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.h
+++ b/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.h
@@ -42,7 +42,7 @@
   // MediaStreamVideoSource overrides.
   bool SupportsEncodedOutput() const override;
   void RequestRefreshFrame() override;
-  base::WeakPtr<MediaStreamVideoSource> GetWeakPtr() const override;
+  base::WeakPtr<MediaStreamVideoSource> GetWeakPtr() override;
 
  protected:
   // Implements MediaStreamVideoSource.
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
index 5ca6f774e..aaa5494 100644
--- a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
+++ b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
@@ -465,6 +465,9 @@
 crbug.com/591099 external/wpt/css/css-flexbox/alignment/flex-align-baseline-line-clamp-001.tentative.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-flexbox/alignment/flex-align-baseline-line-clamp-002.tentative.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-flexbox/alignment/flex-align-baseline-line-clamp-003.tentative.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-flexbox/alignment/flex-align-baseline-multicol-001.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-flexbox/alignment/flex-align-baseline-multicol-002.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-flexbox/alignment/flex-align-baseline-multicol-003.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-flexbox/alignment/flex-align-baseline-overflow-001.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-flexbox/alignment/flex-align-baseline-overflow-002.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-flexbox/alignment/flex-align-baseline-overflow-003.html [ Failure ]
@@ -634,6 +637,9 @@
 crbug.com/1045599 external/wpt/css/css-grid/alignment/grid-align-baseline-line-clamp-001.tentative.html [ Failure ]
 crbug.com/1045599 external/wpt/css/css-grid/alignment/grid-align-baseline-line-clamp-002.tentative.html [ Failure ]
 crbug.com/1045599 external/wpt/css/css-grid/alignment/grid-align-baseline-line-clamp-003.tentative.html [ Failure ]
+crbug.com/1045599 external/wpt/css/css-grid/alignment/grid-align-baseline-multicol-001.html [ Failure ]
+crbug.com/1045599 external/wpt/css/css-grid/alignment/grid-align-baseline-multicol-002.html [ Failure ]
+crbug.com/1045599 external/wpt/css/css-grid/alignment/grid-align-baseline-multicol-003.html [ Failure ]
 crbug.com/1045599 external/wpt/css/css-grid/alignment/grid-align-baseline-overflow-001.html [ Failure ]
 crbug.com/1045599 external/wpt/css/css-grid/alignment/grid-align-baseline-overflow-002.html [ Failure ]
 crbug.com/1045599 external/wpt/css/css-grid/alignment/grid-align-baseline-overflow-003.html [ Failure ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 70b226fd..4ba2a7d9 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -769,9 +769,6 @@
 crbug.com/1308431 external/wpt/css/css-masking/clip-path/clip-path-shape-interpolation-001.html [ Failure ]
 crbug.com/1308431 external/wpt/css/css-masking/clip-path/clip-path-shape-interpolation-002.html [ Failure ]
 
-# CSS cascade layers
-crbug.com/1277637 external/wpt/css/css-cascade/layer-stylesheet-sharing.html [ Failure ]
-
 # Fails, at a minimum, due to lack of support for CSS mask property in html elements
 crbug.com/432153 external/wpt/svg/painting/reftests/display-none-mask.html [ Skip ]
 
@@ -5220,9 +5217,6 @@
 crbug.com/1365858 http/tests/devtools/console/console-functions.js [ Failure Pass ]
 crbug.com/1365858 http/tests/devtools/sources/debugger/properties-special.js [ Failure Pass ]
 
-# Temporarily disabled to land the V8 CL https://crrev.com/c/3929037
-crbug.com/1371072 http/tests/devtools/tracing/timeline-js/timeline-microtasks.js [ Failure Pass ]
-
 crbug.com/1093445 http/tests/loading/pdf-commit-load-callbacks.html [ Failure Pass ]
 crbug.com/1093497 http/tests/history/client-redirect-after-push-state.html [ Failure Pass ]
 
@@ -7245,8 +7239,5 @@
 # Investigate the flake
 crbug.com/1371395 virtual/not-restored-reasons/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-bfcache.window.html [ Failure Pass ]
 
-crbug.com/1370050 http/tests/devtools/network/network-columns-sorted.js [ Skip ]
-crbug.com/1370050 http/tests/devtools/network/waterfall-header-height-updates.js [ Skip ]
-
 # Sheriff 2022-10-07
 crbug.com/1372556 [ Linux ] external/wpt/css/css-text/text-transform/text-transform-capitalize-* [ Failure Pass ]
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 f80b0c54..87aadbf 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
@@ -142142,7 +142142,7 @@
       ]
      ],
      "baseline-008.html": [
-      "89381ab3d5950bb6487d3c78678ce2eb4057b9fe",
+      "beb19ca44741aad5bc8f4fd55af8694d615972c5",
       [
        null,
        [
@@ -275454,6 +275454,10 @@
        "2acc510d2d23c28a952753bdb54017eff2af8632",
        []
       ],
+      "font-palette-values-valid-expected.txt": [
+       "be5b205e314f55cf7151293ff06def1061a77f14",
+       []
+      ],
       "font-size-adjust-computed-expected.txt": [
        "c824213e0a9e82e61b31deac83c0dcdaecc30276",
        []
@@ -302703,6 +302707,10 @@
       "3c086eba4b94d008892cbbe3b1b07cda02014efb",
       []
      ],
+     "cssstyledeclaration-csstext-all-shorthand-expected.txt": [
+      "2a5760cd78da8ef5b1b2333dae9a0feede431806",
+      []
+     ],
      "cssstyledeclaration-csstext-expected.txt": [
       "5313c13a7a426063057b8d902880f400cf63028f",
       []
@@ -309651,7 +309659,7 @@
      []
     ],
     "OWNERS": [
-     "7f44d1b6e2ffff87a3e265b9ba62518534468d80",
+     "8a638a4d46a9e97a2fd2a4f3043ad63762ba98a1",
      []
     ],
     "README.md": [
@@ -336199,7 +336207,7 @@
      []
     ],
     "OWNERS": [
-     "7f44d1b6e2ffff87a3e265b9ba62518534468d80",
+     "8a638a4d46a9e97a2fd2a4f3043ad63762ba98a1",
      []
     ],
     "README.md": [
@@ -339935,7 +339943,7 @@
      []
     ],
     "getdisplaymedia.https-expected.txt": [
-     "4cdf6f2574d11071332d57eef4113c77b312ee9d",
+     "baa9eb85b191ff7a5e4d747e2935ad1ef5408cb6",
      []
     ],
     "idlharness.https.window-expected.txt": [
@@ -392630,6 +392638,27 @@
         {}
        ]
       ],
+      "flex-align-baseline-multicol-001.html": [
+       "14db395889a8570deb331d48a8b90364677f9d5c",
+       [
+        null,
+        {}
+       ]
+      ],
+      "flex-align-baseline-multicol-002.html": [
+       "cf663a25ddcca08d548fe3aafbc614e64d4d3af8",
+       [
+        null,
+        {}
+       ]
+      ],
+      "flex-align-baseline-multicol-003.html": [
+       "663c351ede53442cc34539e456138cd021d428da",
+       [
+        null,
+        {}
+       ]
+      ],
       "flex-align-baseline-overflow-001.html": [
        "382112ed210b8563c73a4449847754ced0221cbb",
        [
@@ -394490,6 +394519,13 @@
        {}
       ]
      ],
+     "font-palette-vs-shorthand.html": [
+      "6c5cc97da94162edf86374032dfd257eeded61c0",
+      [
+       null,
+       {}
+      ]
+     ],
      "font-shorthand-serialization-001.html": [
       "e44cc7b7c8ddb8de06c6366f251afc96affdd89d",
       [
@@ -394760,14 +394796,14 @@
        ]
       ],
       "font-palette-values-invalid.html": [
-       "d439f6440fc6246c23db5d01c010f7702a629a8e",
+       "2056055f3412d5d63cfc079b082dded04cb653a1",
        [
         null,
         {}
        ]
       ],
       "font-palette-values-valid.html": [
-       "e6e3dda9eb1ced5b187137bceb2a85ee8207e700",
+       "3c0c0626f5871b4fce1ca9ceec4c01491a83faa5",
        [
         null,
         {}
@@ -395783,6 +395819,27 @@
         {}
        ]
       ],
+      "grid-align-baseline-multicol-001.html": [
+       "d7d6faabb1afac1bfd97def7017e51ec31fa5924",
+       [
+        null,
+        {}
+       ]
+      ],
+      "grid-align-baseline-multicol-002.html": [
+       "d237f4c2e2b0f1eee8369e7ba76af04edb8f27c3",
+       [
+        null,
+        {}
+       ]
+      ],
+      "grid-align-baseline-multicol-003.html": [
+       "52b2403f881ddc1bdb8ceab1c387547f5dd255b4",
+       [
+        null,
+        {}
+       ]
+      ],
       "grid-align-baseline-overflow-001.html": [
        "66f9eb1bcf059676465689f39cceffe43565ca84",
        [
@@ -415161,6 +415218,13 @@
        {}
       ]
      ],
+     "cssstyledeclaration-csstext-all-shorthand.html": [
+      "6619538cf109e0fed0a15ba37eddba72e708abdd",
+      [
+       null,
+       {}
+      ]
+     ],
      "cssstyledeclaration-csstext-final-delimiter.html": [
       "01b0a32c3fe2739f70377d7673b54a5fa7c50d61",
       [
@@ -441706,35 +441770,35 @@
      ]
     ],
     "feature-policy-header-policy-allowed-for-all.https.sub.html": [
-     "bfbdd6a20c93dc013d0008cf8b80bbcd7aee00a6",
+     "a036859451ee5bdf2a3a333f06f651de958e4008",
      [
       null,
       {}
      ]
     ],
     "feature-policy-header-policy-allowed-for-self.https.sub.html": [
-     "8641746ec8fb9db9af9f284d098b32b8663ca85c",
+     "b6fbdd2cc2449c902afe8b57bbeb62b99a3a3125",
      [
       null,
       {}
      ]
     ],
     "feature-policy-header-policy-allowed-for-some.https.sub.html": [
-     "d89ccef5c90676f0a682dbf07a3da20d3f017a83",
+     "5eda8baa0849c6803a5ae7ebf789dc7e96dbe92a",
      [
       null,
       {}
      ]
     ],
     "feature-policy-header-policy-declined.https.sub.html": [
-     "ebe09ec9873d6ef2c1946e0c408d9582923889cc",
+     "17378e3e13f2dc0de2606e16f6fbab3bf3a39f4a",
      [
       null,
       {}
      ]
     ],
     "feature-policy-header-policy-disallowed-for-all.https.sub.html": [
-     "971af0fa070d9ad40fd4f693500c38b8c85af0ef",
+     "936f26193787a722fa30b201a73ac252476c4561",
      [
       null,
       {}
@@ -441817,7 +441881,7 @@
      ]
     ],
     "permissions-policy-header-policy-allowed-for-self.https.sub.html": [
-     "5c4c6568f2fc6161de8d5017576c2606acfc11ab",
+     "32df2b71c328f06de73af6ceb42171039de6f1c7",
      [
       null,
       {}
@@ -524121,7 +524185,7 @@
      ]
     ],
     "permissions-policy-header-policy-allowed-for-all.https.sub.html": [
-     "a089866c7af7ac4a798844cff3fd1a938bb5cede",
+     "16a2b60c75d5f870a8364d2a2bdf913112f6b58c",
      [
       null,
       {}
@@ -524135,14 +524199,14 @@
      ]
     ],
     "permissions-policy-header-policy-allowed-for-self.https.sub.html": [
-     "dba317e64e441fe5da5f6f6a79576cbf89ef27bb",
+     "363ff0b9819f7139d51867141d0a40108e981ea5",
      [
       null,
       {}
      ]
     ],
     "permissions-policy-header-policy-allowed-for-some.https.sub.html": [
-     "0035eea7d5e04e1155d452246925a7a7560fd951",
+     "e9d8ac145866eaff144f4d5b87197c3c40e44673",
      [
       null,
       {}
@@ -524156,14 +524220,14 @@
      ]
     ],
     "permissions-policy-header-policy-declined.https.sub.html": [
-     "247f23893ba09cbe2639c4df01aa70b4fa553595",
+     "f02cdce7d1e7db0f5416a3085eacb628eb715dc4",
      [
       null,
       {}
      ]
     ],
     "permissions-policy-header-policy-disallowed-for-all.https.sub.html": [
-     "6c6f6ef73f382e9915b091ae315ca9b053c4e39f",
+     "f787b7de12ad9408535fa315aad1b2857c08d6aa",
      [
       null,
       {}
@@ -542010,7 +542074,7 @@
      ]
     ],
     "getdisplaymedia.https.html": [
-     "69b47474be0192f5fa860fec89133b14320f0760",
+     "c92a7154ee6728c1841a2e7e130f71ba521ae14e",
      [
       null,
       {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/alignment/flex-align-baseline-multicol-001.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/alignment/flex-align-baseline-multicol-001.html
new file mode 100644
index 0000000..14db395
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/alignment/flex-align-baseline-multicol-001.html
@@ -0,0 +1,142 @@
+<!DOCTYPE html>
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7639">
+<style>
+.target {
+  display: flex;
+  inline-size: 100px;
+  position: relative;
+  line-height: 0;
+  padding: 10px;
+}
+.target > div {
+  background: hotpink;
+  font-size: 20px;
+}
+.multicol {
+  columns: 3;
+  column-fill: auto;
+  padding: 10px;
+  border: solid 10px;
+}
+.multicol > div {
+  break-inside: avoid;
+  break-before: column;
+  break-after: column;
+}
+span {
+  display: inline-block;
+  width: 1em;
+  height: 1em;
+  outline: solid cyan 3px;
+  outline-offset: -3px;
+}
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<body onload="checkLayout('.target > *')">
+
+<!-- Three columns, largest in the middle. -->
+<div class="target" style="align-items: first baseline;">
+  <div data-offset-y="20"><span></span></div>
+  <div class="multicol" data-offset-y="10">
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<div class="target" style="align-items: last baseline;">
+  <div data-offset-y="100"><span></span></div>
+  <div class="multicol" data-offset-y="10">
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<!-- Start spanning element. -->
+<div class="target" style="align-items: first baseline;">
+  <div data-offset-y="30"><span></span></div>
+  <div class="multicol" data-offset-y="10">
+    <div style="column-span: all; background: orange;">
+      <span></span><br><span></span>
+    </div>
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<div class="target" style="align-items: last baseline;">
+  <div data-offset-y="140"><span></span></div>
+  <div class="multicol" data-offset-y="10">
+    <div style="column-span: all; background: orange;">
+      <span></span><br><span></span>
+    </div>
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<!-- End spanning element. -->
+<div class="target" style="align-items: first baseline;">
+  <div data-offset-y="20"><span></span></div>
+  <div class="multicol" data-offset-y="10">
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="column-span: all; background: orange;">
+      <span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<div class="target" style="align-items: last baseline;">
+  <div data-offset-y="140"><span></span></div>
+  <div class="multicol" data-offset-y="10">
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="column-span: all; background: orange;">
+      <span></span><br><span></span>
+    </div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/alignment/flex-align-baseline-multicol-002.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/alignment/flex-align-baseline-multicol-002.html
new file mode 100644
index 0000000..cf663a2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/alignment/flex-align-baseline-multicol-002.html
@@ -0,0 +1,144 @@
+<!DOCTYPE html>
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7639">
+<style>
+.target {
+  display: flex;
+  inline-size: 200px;
+  position: relative;
+  line-height: 0;
+  margin: 40px;
+  padding: 10px;
+  writing-mode: vertical-rl;
+}
+.target > div {
+  background: hotpink;
+  font-size: 20px;
+}
+.multicol {
+  columns: 3;
+  column-fill: auto;
+  padding: 10px;
+  border: solid 10px;
+}
+.multicol > div {
+  break-inside: avoid;
+  break-before: column;
+  break-after: column;
+}
+span {
+  display: inline-block;
+  width: 1em;
+  height: 1em;
+  outline: solid cyan 3px;
+  outline-offset: -3px;
+}
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<body onload="checkLayout('.target > *')">
+
+<!-- Three columns, largest in the middle. -->
+<div class="target" style="align-items: first baseline;">
+  <div data-offset-x="105"><span></span></div>
+  <div class="multicol" data-offset-x="10">
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<div class="target" style="align-items: last baseline;">
+  <div data-offset-x="35"><span></span></div>
+  <div class="multicol" data-offset-x="10">
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<!-- Start spanning element. -->
+<div class="target" style="align-items: first baseline;">
+  <div data-offset-x="140"><span></span></div>
+  <div class="multicol" data-offset-x="10">
+    <div style="column-span: all; background: orange;">
+      <span></span><br><span></span>
+    </div>
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<div class="target" style="align-items: last baseline;">
+  <div data-offset-x="35"><span></span></div>
+  <div class="multicol" data-offset-x="10">
+    <div style="column-span: all; background: orange;">
+      <span></span><br><span></span>
+    </div>
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<!-- End spanning element. -->
+<div class="target" style="align-items: first baseline;">
+  <div data-offset-x="145"><span></span></div>
+  <div class="multicol" data-offset-x="10">
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="column-span: all; background: orange;">
+      <span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<div class="target" style="align-items: last baseline;">
+  <div data-offset-x="30"><span></span></div>
+  <div class="multicol" data-offset-x="10">
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="column-span: all; background: orange;">
+      <span></span><br><span></span>
+    </div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/alignment/flex-align-baseline-multicol-003.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/alignment/flex-align-baseline-multicol-003.html
new file mode 100644
index 0000000..663c351
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/alignment/flex-align-baseline-multicol-003.html
@@ -0,0 +1,144 @@
+<!DOCTYPE html>
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7639">
+<style>
+.target {
+  display: flex;
+  inline-size: 200px;
+  position: relative;
+  line-height: 0;
+  margin: 40px;
+  padding: 10px;
+  writing-mode: vertical-lr;
+}
+.target > div {
+  background: hotpink;
+  font-size: 20px;
+}
+.multicol {
+  columns: 3;
+  column-fill: auto;
+  padding: 10px;
+  border: solid 10px;
+}
+.multicol > div {
+  break-inside: avoid;
+  break-before: column;
+  break-after: column;
+}
+span {
+  display: inline-block;
+  width: 1em;
+  height: 1em;
+  outline: solid cyan 3px;
+  outline-offset: -3px;
+}
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<body onload="checkLayout('.target > *')">
+
+<!-- Three columns, largest in the middle. -->
+<div class="target" style="align-items: first baseline;">
+  <div data-offset-x="25"><span></span></div>
+  <div class="multicol" data-offset-x="10">
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<div class="target" style="align-items: last baseline;">
+  <div data-offset-x="95"><span></span></div>
+  <div class="multicol" data-offset-x="10">
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<!-- Start spanning element. -->
+<div class="target" style="align-items: first baseline;">
+  <div data-offset-x="30"><span></span></div>
+  <div class="multicol" data-offset-x="10">
+    <div style="column-span: all; background: orange;">
+      <span></span><br><span></span>
+    </div>
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<div class="target" style="align-items: last baseline;">
+  <div data-offset-x="135"><span></span></div>
+  <div class="multicol" data-offset-x="10">
+    <div style="column-span: all; background: orange;">
+      <span></span><br><span></span>
+    </div>
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<!-- End spanning element. -->
+<div class="target" style="align-items: first baseline;">
+  <div data-offset-x="25"><span></span></div>
+  <div class="multicol" data-offset-x="10">
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="column-span: all; background: orange;">
+      <span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<div class="target" style="align-items: last baseline;">
+  <div data-offset-x="140"><span></span></div>
+  <div class="multicol" data-offset-x="10">
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="column-span: all; background: orange;">
+      <span></span><br><span></span>
+    </div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/font-palette-vs-shorthand.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/font-palette-vs-shorthand.html
new file mode 100644
index 0000000..6c5cc97
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/font-palette-vs-shorthand.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 4: interaction of font-palette and font shorthand</title>
+<link rel="help" href="https://drafts.csswg.org/css-fonts/#font-prop">
+<meta name="assert" content="font-palette is reset to normal by font shorthand.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style id="style">
+@font-face {
+    font-family: colr;
+    src: url("resources/COLR-palettes-test-font.ttf") format("truetype");
+}
+div {
+    margin: 10px;
+}
+#a {
+    font: 50px colr;
+    font-palette: dark;
+}
+#b {
+    font-palette: dark;
+    font: 50px colr;  /* should reset font-palette to normal */
+}
+#c {
+    font-palette: dark;
+    font-size: 50px;
+    font-family: colr;
+}
+#d {
+    font-palette: dark;
+    font-size: 50px;
+    font-family: colr;
+    font-palette: normal;
+}
+</style>
+</head>
+<body>
+<p>The first and third examples should use the 'dark' palette; the second and fourth, 'normal'.</p>
+<div id=a>A</div>
+<div id=b>A</div>
+<div id=c>A</div>
+<div id=d>A</div>
+<script>
+test(function() {
+    let testElem = document.getElementById("a");
+    let computed = window.getComputedStyle(testElem);
+    assert_equals(computed.fontPalette, "dark");
+    assert_equals(computed.font, "");
+    assert_equals(computed.fontFamily, "colr");
+    assert_equals(computed.fontSize, "50px");
+});
+
+test(function() {
+    let testElem = document.getElementById("b");
+    let computed = window.getComputedStyle(testElem);
+    assert_equals(computed.fontPalette, "normal");
+    assert_not_equals(computed.font, "");
+    /* The exact form of the font shorthand varies, but should include these pieces: */
+    assert_not_equals(computed.font.indexOf("50px"), -1);
+    assert_not_equals(computed.font.indexOf("colr"), -1);
+    /* And there should be no trace of this: */
+    assert_equals(computed.font.indexOf("dark"), -1);
+});
+
+test(function() {
+    let testElem = document.getElementById("c");
+    let computed = window.getComputedStyle(testElem);
+    assert_equals(computed.fontPalette, "dark");
+    assert_equals(computed.font, "");
+});
+
+test(function() {
+    let testElem = document.getElementById("d");
+    let computed = window.getComputedStyle(testElem);
+    assert_equals(computed.fontPalette, "normal");
+    assert_not_equals(computed.font.indexOf("50px"), -1);
+    assert_not_equals(computed.font.indexOf("colr"), -1);
+});
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-palette-values-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-palette-values-invalid.html
index d439f644..2056055f 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-palette-values-invalid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-palette-values-invalid.html
@@ -19,7 +19,7 @@
 
 /* 0 */
 @font-palette-values --A {
-    font-family: a, b;
+    font-family: a, serif;  /* multiple families are allowed, but not generics */
 }
 
 /* 1 */
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-palette-values-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-palette-values-valid-expected.txt
new file mode 100644
index 0000000..be5b205
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-palette-values-valid-expected.txt
@@ -0,0 +1,36 @@
+This is a testharness.js-based test.
+PASS CSS Fonts Module Level 4: parsing @font-palette-values
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 1
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 2
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 3
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 4
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 5
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 6
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 7
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 8
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 9
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 10
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 11
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 12
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 13
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 14
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 15
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 16
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 17
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 18
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 19
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 20
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 21
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 22
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 23
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 24
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 25
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 26
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 27
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 28
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 29
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 30
+PASS CSS Fonts Module Level 4: parsing @font-palette-values 31
+FAIL CSS Fonts Module Level 4: parsing @font-palette-values 32 assert_equals: expected "foo, bar, baz" but got ""
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-palette-values-valid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-palette-values-valid.html
index e6e3dda..3c0c0626 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-palette-values-valid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-palette-values-valid.html
@@ -98,6 +98,11 @@
 /* 15 */
 @font-palette-values -- {
 }
+
+/* 16 */
+@font-palette-values --P {
+    font-family: foo, bar, baz;
+}
 </style>
 </head>
 <body>
@@ -204,7 +209,7 @@
 test(function() {
     let rule = rules[5];
     assert_equals(rule.name, "--F");
-    assert_equals(rule.fontFamily, "foo");
+    assert_in_array(rule.fontFamily, ["foo", "\"foo\""]);
     assert_equals(rule.basePalette, "");
     assert_equals(rule.overrideColors, "");
 });
@@ -372,6 +377,14 @@
     assert_equals(rule.basePalette, "");
     assert_equals(rule.overrideColors, "");
 });
+
+test(function() {
+    let rule = rules[16];
+    assert_equals(rule.name, "--P");
+    assert_equals(rule.fontFamily, "foo, bar, baz");
+    assert_equals(rule.basePalette, "");
+    assert_equals(rule.overrideColors, "");
+});
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/alignment/grid-align-baseline-multicol-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/alignment/grid-align-baseline-multicol-001.html
new file mode 100644
index 0000000..d7d6faa
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/alignment/grid-align-baseline-multicol-001.html
@@ -0,0 +1,143 @@
+<!DOCTYPE html>
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7639">
+<style>
+.target {
+  display: grid;
+  grid-auto-flow: column;
+  inline-size: 100px;
+  position: relative;
+  line-height: 0;
+  padding: 10px;
+}
+.target > div {
+  background: hotpink;
+  font-size: 20px;
+}
+.multicol {
+  columns: 3;
+  column-fill: auto;
+  padding: 10px;
+  border: solid 10px;
+}
+.multicol > div {
+  break-inside: avoid;
+  break-before: column;
+  break-after: column;
+}
+span {
+  display: inline-block;
+  width: 1em;
+  height: 1em;
+  outline: solid cyan 3px;
+  outline-offset: -3px;
+}
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<body onload="checkLayout('.target > *')">
+
+<!-- Three columns, largest in the middle. -->
+<div class="target" style="align-items: first baseline;">
+  <div data-offset-y="20"><span></span></div>
+  <div class="multicol" data-offset-y="10">
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<div class="target" style="align-items: last baseline;">
+  <div data-offset-y="100"><span></span></div>
+  <div class="multicol" data-offset-y="10">
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<!-- Start spanning element. -->
+<div class="target" style="align-items: first baseline;">
+  <div data-offset-y="30"><span></span></div>
+  <div class="multicol" data-offset-y="10">
+    <div style="column-span: all; background: orange;">
+      <span></span><br><span></span>
+    </div>
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<div class="target" style="align-items: last baseline;">
+  <div data-offset-y="140"><span></span></div>
+  <div class="multicol" data-offset-y="10">
+    <div style="column-span: all; background: orange;">
+      <span></span><br><span></span>
+    </div>
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<!-- End spanning element. -->
+<div class="target" style="align-items: first baseline;">
+  <div data-offset-y="20"><span></span></div>
+  <div class="multicol" data-offset-y="10">
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="column-span: all; background: orange;">
+      <span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<div class="target" style="align-items: last baseline;">
+  <div data-offset-y="140"><span></span></div>
+  <div class="multicol" data-offset-y="10">
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="column-span: all; background: orange;">
+      <span></span><br><span></span>
+    </div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/alignment/grid-align-baseline-multicol-002.html b/third_party/blink/web_tests/external/wpt/css/css-grid/alignment/grid-align-baseline-multicol-002.html
new file mode 100644
index 0000000..d237f4c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/alignment/grid-align-baseline-multicol-002.html
@@ -0,0 +1,145 @@
+<!DOCTYPE html>
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7639">
+<style>
+.target {
+  display: grid;
+  grid-auto-flow: column;
+  inline-size: 200px;
+  position: relative;
+  line-height: 0;
+  margin: 40px;
+  padding: 10px;
+  writing-mode: vertical-rl;
+}
+.target > div {
+  background: hotpink;
+  font-size: 20px;
+}
+.multicol {
+  columns: 3;
+  column-fill: auto;
+  padding: 10px;
+  border: solid 10px;
+}
+.multicol > div {
+  break-inside: avoid;
+  break-before: column;
+  break-after: column;
+}
+span {
+  display: inline-block;
+  width: 1em;
+  height: 1em;
+  outline: solid cyan 3px;
+  outline-offset: -3px;
+}
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<body onload="checkLayout('.target > *')">
+
+<!-- Three columns, largest in the middle. -->
+<div class="target" style="align-items: first baseline;">
+  <div data-offset-x="105"><span></span></div>
+  <div class="multicol" data-offset-x="10">
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<div class="target" style="align-items: last baseline;">
+  <div data-offset-x="35"><span></span></div>
+  <div class="multicol" data-offset-x="10">
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<!-- Start spanning element. -->
+<div class="target" style="align-items: first baseline;">
+  <div data-offset-x="140"><span></span></div>
+  <div class="multicol" data-offset-x="10">
+    <div style="column-span: all; background: orange;">
+      <span></span><br><span></span>
+    </div>
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<div class="target" style="align-items: last baseline;">
+  <div data-offset-x="35"><span></span></div>
+  <div class="multicol" data-offset-x="10">
+    <div style="column-span: all; background: orange;">
+      <span></span><br><span></span>
+    </div>
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<!-- End spanning element. -->
+<div class="target" style="align-items: first baseline;">
+  <div data-offset-x="145"><span></span></div>
+  <div class="multicol" data-offset-x="10">
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="column-span: all; background: orange;">
+      <span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<div class="target" style="align-items: last baseline;">
+  <div data-offset-x="30"><span></span></div>
+  <div class="multicol" data-offset-x="10">
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="column-span: all; background: orange;">
+      <span></span><br><span></span>
+    </div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/alignment/grid-align-baseline-multicol-003.html b/third_party/blink/web_tests/external/wpt/css/css-grid/alignment/grid-align-baseline-multicol-003.html
new file mode 100644
index 0000000..52b2403
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/alignment/grid-align-baseline-multicol-003.html
@@ -0,0 +1,145 @@
+<!DOCTYPE html>
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7639">
+<style>
+.target {
+  display: grid;
+  grid-auto-flow: column;
+  inline-size: 200px;
+  position: relative;
+  line-height: 0;
+  margin: 40px;
+  padding: 10px;
+  writing-mode: vertical-lr;
+}
+.target > div {
+  background: hotpink;
+  font-size: 20px;
+}
+.multicol {
+  columns: 3;
+  column-fill: auto;
+  padding: 10px;
+  border: solid 10px;
+}
+.multicol > div {
+  break-inside: avoid;
+  break-before: column;
+  break-after: column;
+}
+span {
+  display: inline-block;
+  width: 1em;
+  height: 1em;
+  outline: solid cyan 3px;
+  outline-offset: -3px;
+}
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<body onload="checkLayout('.target > *')">
+
+<!-- Three columns, largest in the middle. -->
+<div class="target" style="align-items: first baseline;">
+  <div data-offset-x="25"><span></span></div>
+  <div class="multicol" data-offset-x="10">
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<div class="target" style="align-items: last baseline;">
+  <div data-offset-x="95"><span></span></div>
+  <div class="multicol" data-offset-x="10">
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<!-- Start spanning element. -->
+<div class="target" style="align-items: first baseline;">
+  <div data-offset-x="30"><span></span></div>
+  <div class="multicol" data-offset-x="10">
+    <div style="column-span: all; background: orange;">
+      <span></span><br><span></span>
+    </div>
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<div class="target" style="align-items: last baseline;">
+  <div data-offset-x="135"><span></span></div>
+  <div class="multicol" data-offset-x="10">
+    <div style="column-span: all; background: orange;">
+      <span></span><br><span></span>
+    </div>
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<!-- End spanning element. -->
+<div class="target" style="align-items: first baseline;">
+  <div data-offset-x="25"><span></span></div>
+  <div class="multicol" data-offset-x="10">
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="column-span: all; background: orange;">
+      <span></span><br><span></span>
+    </div>
+  </div>
+</div>
+
+<div class="target" style="align-items: last baseline;">
+  <div data-offset-x="140"><span></span></div>
+  <div class="multicol" data-offset-x="10">
+    <div style="font-size: 10px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 30px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="font-size: 20px;">
+      <span></span><br><span></span><br><span></span>
+    </div>
+    <div style="column-span: all; background: orange;">
+      <span></span><br><span></span>
+    </div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/baseline-008.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/baseline-008.html
index 89381ab..beb19ca 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-multicol/baseline-008.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/baseline-008.html
@@ -2,7 +2,7 @@
 <link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
 <link rel="help" href="https://drafts.csswg.org/css-multicol-1">
 <link rel="help" href="https://drafts.csswg.org/css-align/#baseline-export">
-<meta name="assert" content="According to the spec, a multicol container has no last baseline, only a first baseline. So, when aligning with an inline-block, the block-end outer edge of the multicol is what's used for alignment.">
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7639">
 <link rel="match" href="baseline-008-ref.html">
 <style>
   .part {
@@ -10,6 +10,7 @@
       width: 50px;
       height: 100px;
       background: green;
+      color: transparent;
   }
   .multicol {
       columns: 2;
@@ -17,6 +18,8 @@
   }
 </style>
 <p>There should be a green square below.</p>
-<div class="part"></div><div class="part multicol">
-  <br>
+<div class="part">
+  <div>line1<br>line2</div>
+</div><div class="part multicol">
+  <div>line1<br>line2</div>
 </div>
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/cssstyledeclaration-csstext-all-shorthand-expected.txt b/third_party/blink/web_tests/external/wpt/css/cssom/cssstyledeclaration-csstext-all-shorthand-expected.txt
new file mode 100644
index 0000000..2a5760c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/cssstyledeclaration-csstext-all-shorthand-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+PASS 'all' shorthand alone
+PASS 'all' shorthand with 'width' and 'height'
+PASS 'all' shorthand with 'direction' and 'unicode-bidi'
+PASS 'all' shorthand with 'width', 'height' and custom properties
+FAIL 'all' shorthand with all longhands assert_equals: expected "all: inherit; direction: inherit; unicode-bidi: inherit;" but got "all: inherit; direction: inherit; unicode-bidi: inherit; -webkit-border-image: inherit;"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/cssstyledeclaration-csstext-all-shorthand.html b/third_party/blink/web_tests/external/wpt/css/cssom/cssstyledeclaration-csstext-all-shorthand.html
new file mode 100644
index 0000000..6619538
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/cssstyledeclaration-csstext-all-shorthand.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<title>CSSOM test: serialization of the 'all' shorthand in cssText</title>
+<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/cssom-1/#dom-cssstyledeclaration-csstext">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+const style = document.createElement("div").style;
+
+test(function() {
+  style.cssText = "all: inherit";
+  assert_equals(style.cssText, "all: inherit;");
+}, "'all' shorthand alone");
+
+test(function() {
+  style.cssText = "width: 100px; all: inherit; height: inherit";
+  assert_equals(style.cssText, "all: inherit;");
+}, "'all' shorthand with 'width' and 'height'");
+
+test(function() {
+  style.cssText = "direction: ltr; all: inherit; unicode-bidi: plaintext";
+  assert_equals(style.cssText, "direction: ltr; all: inherit; unicode-bidi: plaintext;");
+}, "'all' shorthand with 'direction' and 'unicode-bidi'");
+
+test(function() {
+  style.cssText = "width: 100px; --a: a; all: inherit; --b: b; height: inherit";
+  assert_equals(style.cssText, "--a: a; all: inherit; --b: b;");
+}, "'all' shorthand with 'width', 'height' and custom properties");
+
+test(function() {
+  let cssText = "all: inherit; ";
+  for (let longhand of getComputedStyle(document.documentElement)) {
+    cssText += longhand + ": inherit; ";
+  }
+  style.cssText = cssText;
+  assert_equals(style.cssText, "all: inherit; direction: inherit; unicode-bidi: inherit;");
+}, "'all' shorthand with all longhands");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/history-traversal/document-state.tentative.https.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/history-traversal/document-state.tentative.https.html
new file mode 100644
index 0000000..d0e629f6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/history-traversal/document-state.tentative.https.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test the properties of a session history entry's document state</title>
+<link rel="help" href="https://html.spec.whatwg.org/#document-state">
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+<script>
+// In this test, we create an auxiliary window with a session history A -> B,
+// where the document on site B is the current active document. Bf-cache is
+// disabled via `Cache-Control: no-store` headers. We then `history.back()` to
+// site A, and perform `location.replace(B)`. This makes the first document in
+// the session history now same-origin/site with the URL in the subsequent
+// session history entry's document state.
+//
+// We then perform `history.forward()` in the first document, which loads the
+// second document (from network). We confirm that the resulting navigation
+// request was made with the expected state, stored on the history entry's
+// document state. The consequences of this are:
+//  - The navigation is made with the `Sec-Fetch-Site: cross-site` header,
+//    indicating that the *original* document state's initiator origin was
+//    preserved
+//  - The navigation is made with a cross-origin `Referer` header, indicating
+//    that the *original* document state's referrer was preserved
+//  - The resulting document has a cross-origin `document.referrer`, indicating
+//    the same as above
+promise_test(async t => {
+  const rcHelper = new RemoteContextHelper();
+  const A = await rcHelper.addWindow();
+
+  // Create B on a new origin (with bf-cache disabled).
+  const B = await A.navigateToNew({
+    origin: 'HTTPS_NOTSAMESITE_ORIGIN',
+    headers: [['Cache-Control', 'no-store']],
+  });
+
+  // This is the origin we're going to navigate A to, so that it becomes
+  // same-origin with B.
+  const originB = new URL(await B.executeScript(() => location.href)).origin;
+  await B.historyBack();
+
+  // Make A navigate to the same document but in origin B:
+  const urlA = await A.executeScript(() => location.href);
+  const originA = new URL(urlA).origin;
+  assert_not_equals(originA, originB, 'Contexts A and B are cross-origin');
+
+  // Load A's current document but on origin B.
+  const newUrlOnOriginB = urlA.replace(originA, originB);
+  await A.navigate((url) => {
+    location.replace(url);
+  }, [newUrlOnOriginB]);
+
+  // Assert that A and B are now same-origin:
+  const newUrlA = await A.executeScript(() => {
+    return location.href;
+  });
+
+  // Now the session history looks like:
+  // B -> B (initiator origin: A)
+  assert_equals(new URL(newUrlA).origin, originB);
+
+  // This means that when we navigate forward, we should request the second
+  // document with the history entry's document state, which mostly preserves
+  // parameters from the original initiator (a cross-site document), despite a
+  // now-same-origin document initiating this navigation via history.
+  await A.historyForward();
+
+  const secFetchSite = await B.executeScript(() => window.requestHeaders['sec-fetch-site']);
+  const referrer = await B.executeScript(() => window.requestHeaders['referer']);
+  const documentReferrer = await B.executeScript(() => document.referrer);
+
+  assert_equals(secFetchSite, 'cross-site',
+      'Same-origin forward history navigation to a document whose original ' +
+      'initiator was cross-site, ends up with Sec-Fetch-Dest: cross-site ' +
+      'header');
+  assert_equals(referrer, originA + '/',
+      'Same-origin forward history navigation to a document whose original ' +
+      'initiator was cross-site ends up with the Referer header that is the ' +
+      'original cross-site initiator');
+  assert_equals(documentReferrer, originA + '/',
+      'Same-origin forward history navigation to a document whose original ' +
+      'initiator was cross-site ends up with document.referrer that is the ' +
+      'original cross-site initiator');
+}, "A navigation's initiator origin and referrer are stored in the document state");
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/remote-context-helper/resources/executor.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/remote-context-helper/resources/executor.html
deleted file mode 100644
index 9aec263..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/remote-context-helper/resources/executor.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE HTML>
-<script src="/common/dispatcher/dispatcher.js"></script>
-<script src="./executor-common.js"></script>
-<script src="./executor-window.js"></script>
-
-<body>
-  <script>
-    requestExecutor();
-  </script>
-</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/remote-context-helper/resources/executor.sub.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/remote-context-helper/resources/executor.sub.html
new file mode 100644
index 0000000..38f4429
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/remote-context-helper/resources/executor.sub.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="./executor-common.js"></script>
+<script src="./executor-window.js"></script>
+
+<body>
+  <script>
+    window.requestHeaders = {
+      'sec-fetch-mode': '{{header_or_default(sec-fetch-mode, absent)}}',
+      'sec-fetch-site': '{{header_or_default(sec-fetch-site, absent)}}',
+      'sec-fetch-dest': '{{header_or_default(sec-fetch-dest, absent)}}',
+      'referer': '{{header_or_default(referer, absent)}}',
+    };
+    requestExecutor();
+  </script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
index 300eded..7a4b399a 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
@@ -49,7 +49,7 @@
 {
   const RESOURCES_PATH =
       '/html/browsers/browsing-the-web/remote-context-helper/resources';
-  const WINDOW_EXECUTOR_PATH = `${RESOURCES_PATH}/executor.html`;
+  const WINDOW_EXECUTOR_PATH = `${RESOURCES_PATH}/executor.sub.html`;
   const WORKER_EXECUTOR_PATH = `${RESOURCES_PATH}/executor-worker.js`;
 
   /**
diff --git a/third_party/blink/web_tests/external/wpt/screen-capture/getdisplaymedia.https-expected.txt b/third_party/blink/web_tests/external/wpt/screen-capture/getdisplaymedia.https-expected.txt
index 4cdf6f2..baa9eb8 100644
--- a/third_party/blink/web_tests/external/wpt/screen-capture/getdisplaymedia.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/screen-capture/getdisplaymedia.https-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 54 tests; 49 PASS, 5 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 56 tests; 51 PASS, 5 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS getDisplayMedia in navigator.mediaDevices
 FAIL getDisplayMedia() must require user activation assert_unreached: Should have rejected: getDisplayMedia should have returned an already-rejected promise. Reached unreachable code
 FAIL getDisplayMedia() must adhere to frameRate if set assert_greater_than_equal: expected a number greater than or equal to 2.5 but got NaN
@@ -40,7 +40,9 @@
 PASS getDisplayMedia({"video":{"height":{"max":-1}}}) must fail with OverconstrainedError
 PASS getDisplayMedia({"video":{"frameRate":{"max":-1}}}) must fail with OverconstrainedError
 PASS getDisplayMedia() resolves with stream with video track
-PASS getDisplayMedia() with getSettings
+PASS getDisplayMedia({"video":{"displaySurface":"monitor"}}) with getSettings
+PASS getDisplayMedia({"video":{"displaySurface":"window"}}) with getSettings
+PASS getDisplayMedia({"video":{"displaySurface":"browser"}}) with getSettings
 PASS displaySurface is supported
 PASS getDisplayMedia({"video":{"displaySurface":"monitor"}}) must succeed
 PASS getDisplayMedia({"video":{"displaySurface":"window"}}) must succeed
diff --git a/third_party/blink/web_tests/external/wpt/screen-capture/getdisplaymedia.https.html b/third_party/blink/web_tests/external/wpt/screen-capture/getdisplaymedia.https.html
index 69b4747..c92a7154 100644
--- a/third_party/blink/web_tests/external/wpt/screen-capture/getdisplaymedia.https.html
+++ b/third_party/blink/web_tests/external/wpt/screen-capture/getdisplaymedia.https.html
@@ -197,16 +197,19 @@
   assert_equals(track.readyState, "ended");
 }, 'getDisplayMedia() resolves with stream with video track');
 
-promise_test(async t => {
-  const stream = await getDisplayMedia({video: true});
-  t.add_cleanup(() => stopTracks(stream));
-  const settings = stream.getVideoTracks()[0].getSettings();
-  assert_any(
-      assert_equals, settings.displaySurface,
-      ['monitor', 'window', 'browser']);
-  assert_any(assert_equals, settings.logicalSurface, [true, false]);
-  assert_any(assert_equals, settings.cursor, ['never', 'always', 'motion']);
-}, 'getDisplayMedia() with getSettings');
+{
+  const displaySurfaces = ['monitor', 'window', 'browser'];
+  displaySurfaces.forEach((displaySurface) => {
+    promise_test(async t => {
+      const stream = await getDisplayMedia({video: {displaySurface}});
+      t.add_cleanup(() => stopTracks(stream));
+      const settings = stream.getVideoTracks()[0].getSettings();
+      assert_equals(settings.displaySurface, displaySurface);
+      assert_any(assert_equals, settings.logicalSurface, [true, false]);
+      assert_any(assert_equals, settings.cursor, ['never', 'always', 'motion']);
+    }, `getDisplayMedia({"video":{"displaySurface":"${displaySurface}"}}) with getSettings`);
+  })
+}
 
 {
   const properties = ["displaySurface"];
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/HTMLElement-generic.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/HTMLElement-generic.tentative.html
index 3ec6cfa60..8e54fa9 100644
--- a/third_party/blink/web_tests/external/wpt/trusted-types/HTMLElement-generic.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/trusted-types/HTMLElement-generic.tentative.html
@@ -6,45 +6,77 @@
 </head>
 <body>
 <script>
-  var testnb = 0;
+const policy = trustedTypes.createPolicy("testpolicy", {
+  createScript: s => s,
+  createHTML: s => s,
+  createScriptURL: s => s,
+});
 
-  // TrustedScriptURL Assignments
-  const scriptURLTestCases = [
-    [ 'embed', 'src' ],
-    [ 'script', 'src' ]
-  ];
+function getTrusted(element, attr) {
+  const type = trustedTypes.getPropertyType(element, attr);
+  if (type == "TrustedScript") {
+    return policy.createScript("2+2");
+  } else if (type == "TrustedScriptURL") {
+    return policy.createScript("https://example.test/");
+  } else if (type == "TrustedHTML") {
+    return policy.createHTML("<b>hello</b>");
+  } else {
+    return "a simple string";
+  }
+}
 
-  testnb = 0;
-  scriptURLTestCases.forEach(c => {
-    test(t => {
-      assert_element_accepts_trusted_script_url(window, ++testnb, t, c[0], c[1], RESULTS.SCRIPTURL);
-    }, c[0] + "." + c[1] + " assigned via policy (successful ScriptURL transformation)");
-  });
+// This test will run a simple, TT-relevant assignment, in a number of
+// circumstances. We've had issues where subtle difference in DOM behaviour -
+// for example a connected element or a non-connected element - produce
+// different results, and no test catching it because the tests were written
+// to do it one particular way. So this test does one thing, but in all the
+// different ways we can think of.
+//
+// - With TT disabled or enabled,
+// - with any of the trusted types,
+// - with a string or a TT value,
+// - with a element that's connected to the DOM (or not).
+//
+// Run the set of tests, assuming that is_tt_enabled reflects whether Trusted
+// Types is currently enabled (& enforced) or not.
+function runTests(is_tt_enabled) {
+  for (const [element, attr] of [
+      [ 'embed', 'src' ],
+      [ 'script', 'src' ],
+      [ 'div', 'innerHTML' ],
+      [ 'iframe', 'srcdoc' ],
+      [ 'script', 'text' ],
+      [ 'script', 'innerText' ],
+      [ 'script', 'textContent' ],
+    ]) {
+    const trusted = getTrusted(element, attr);
+    for (const value of [trusted, trusted.toString()]) {
+      for (const connected of [true, false]) {
 
-  // TrustedHTML Assignments
-  const HTMLTestCases = [
-    [ 'div', 'innerHTML' ],
-    [ 'iframe', 'srcdoc' ]
-  ];
+        const expect_exception = is_tt_enabled &&
+            value.constructor.name != trustedTypes.getPropertyType(element, attr);
+        test(t => {
+          const elem = document.createElement(element);
+          if (connected) document.body.appendChild(elem);
+          if (expect_exception) {
+            assert_throws_js(TypeError, _ => { elem[attr] = value; });
+          } else {
+            elem[attr] = value;
+          }
+        }, `${is_tt_enabled ? "TT enabled" : "TT disabled"}: ${element}.${attr} = ${value.constructor.name} on a ${connected ? "connected" : "non-connected"} element.`);
+      }
+    }
+  }
+}
 
-  testnb = 0;
-  HTMLTestCases.forEach(c => {
-    test(t => {
-      assert_element_accepts_trusted_html(window, ++testnb, t, c[0], c[1], RESULTS.HTML);
-    }, c[0] + "." + c[1] + " assigned via policy (successful HTML transformation)");
-  });
+// Run the tests without TT first.
+runTests(false);
 
-  // TrustedScript Assignments
-  const scriptTestCases = [
-    [ 'script', 'text' ],
-    [ 'script', 'innerText' ],
-    [ 'script', 'textContent' ]
-  ];
-
-  testnb = 0;
-  scriptTestCases.forEach(c => {
-    test(t => {
-      assert_element_accepts_trusted_script(window, c, t, c[0], c[1], RESULTS.SCRIPT);
-    }, c[0] + "." + c[1] + " assigned via policy (successful Script transformation)");
-  });
+// Now run the tests a second time, with TT enabled. To accomplish this, insert
+// a suitable <meta> element.
+const meta = document.createElement("meta");
+meta.setAttribute("http-equiv", "Content-Security-Policy");
+meta.setAttribute("content", "require-trusted-types-for 'script';");
+document.head.appendChild(meta);
+runTests(true);
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/HTMLScriptElement-internal-slot.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/HTMLScriptElement-internal-slot.tentative.html
index 4f523bb..3a4b905 100644
--- a/third_party/blink/web_tests/external/wpt/trusted-types/HTMLScriptElement-internal-slot.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/trusted-types/HTMLScriptElement-internal-slot.tentative.html
@@ -45,6 +45,115 @@
       });
     });
   }, "Test TT application when manipulating <script> elements during loading.");
+
+  // Test that a script set via textContent or innerTest actually executes
+  // (and not only doesn't throw an exception, which it wouldn't do due to the
+  // "internal slot" mechanism).
+  const policy = trustedTypes.createPolicy("testpolicy", {
+      createScript: x => x, createScriptURL: x => x});
+  promise_test(t => {
+    const s = document.createElement("script");
+    document.body.appendChild(s);
+    s.textContent = policy.createScript("window.postMessage('hello');");
+    return new Promise(resolve => {
+      window.addEventListener("message", e => {
+        if (e.data == "hello") resolve();
+      });
+    });
+  }, "Script set via .textContent executes on a connected HTMLScriptElement.");
+  promise_test(t => {
+    const s = document.createElement("script");
+    s.textContent = policy.createScript("window.postMessage('world');");
+    document.body.appendChild(s);
+    return new Promise(resolve => {
+      window.addEventListener("message", e => {
+        if (e.data == "world") resolve();
+      });
+    });
+  }, "Script set via .textContent executes on an unconnected HTMLScriptElement.");
+  promise_test(t => {
+    const s = document.createElement("script");
+    document.body.appendChild(s);
+    s.innerText = policy.createScript("window.postMessage('hello');");
+    return new Promise(resolve => {
+      window.addEventListener("message", e => {
+        if (e.data == "hello") resolve();
+      });
+    });
+  }, "Script set via .innerText executes on a connected HTMLScriptElement.");
+  promise_test(t => {
+    const s = document.createElement("script");
+    s.innerText= policy.createScript("window.postMessage('world');");
+    document.body.appendChild(s);
+    return new Promise(resolve => {
+      window.addEventListener("message", e => {
+        if (e.data == "world") resolve();
+      });
+    });
+  }, "Script set via .innerText executes on an unconnected HTMLScriptElement.");
+
+  // Test that interactions between the script content, the .src attribute, and
+  // exceptions still work correctly with TT and the "internal slot" thingy.
+  promise_test(t => {
+    const s = document.createElement("script");
+    s.textContent = policy.createScript("window.postMessage('script body');");
+    try {
+      s.src = "support/HTMLScriptElement-internal-slot-support.js";
+    } catch (e) {}
+    document.body.appendChild(s);
+    return new Promise((resolve, reject) => {
+      window.addEventListener("message", e => {
+        // .src was set with plain string => should not have been accepted.
+        if (e.data == "script body") resolve();
+        if (e.data == "script url") reject();
+      });
+    });
+  }, "Setting .src to a plain string should throw an exception and not modify the script state, on an unconnected script element.");
+
+  promise_test(t => {
+    const s = document.createElement("script");
+    s.textContent = policy.createScript("window.postMessage('script body');");
+    s.src = policy.createScriptURL("support/HTMLScriptElement-internal-slot-support.js");
+    document.body.appendChild(s);
+    return new Promise((resolve, reject) => {
+      window.addEventListener("message", e => {
+        // .src was set with a TrustedScriptURL => the .src should get executed.
+        if (e.data == "script body") reject();
+        if (e.data == "script url") resolve();
+      });
+    });
+  }, "Setting .src to a TrustedScriptURL should work and should execute the referenced script instead of the script body, on an unconnected script element.");
+
+  promise_test(t => {
+    const s = document.createElement("script");
+    document.body.appendChild(s);
+    s.textContent = policy.createScript("window.postMessage('script body');");
+    try {
+      s.src = "support/HTMLScriptElement-internal-slot-support.js";
+    } catch (e) {}
+    return new Promise((resolve, reject) => {
+      window.addEventListener("message", e => {
+        // .src was set with plain string => should not have been accepted.
+        if (e.data == "script body") resolve();
+        if (e.data == "script url") reject();
+      });
+    });
+  }, "Setting .src to a plain string should throw an exception and not modify the script state, on a connected script element.");
+
+  promise_test(t => {
+    const s = document.createElement("script");
+    s.textContent = policy.createScript("window.postMessage('script body');");
+    s.src = policy.createScriptURL("support/HTMLScriptElement-internal-slot-support.js");
+    document.body.appendChild(s);
+    return new Promise((resolve, reject) => {
+      window.addEventListener("message", e => {
+        // .src was set with a TrustedScriptURL => the .src should get executed.
+        if (e.data == "script body") reject();
+        if (e.data == "script url") resolve();
+      });
+    });
+  },  "Setting .src to a TrustedScriptURL should work and should execute the referenced script instead of the script body, on a onnected script element.");
+
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/support/HTMLScriptElement-internal-slot-support.js b/third_party/blink/web_tests/external/wpt/trusted-types/support/HTMLScriptElement-internal-slot-support.js
new file mode 100644
index 0000000..7d574a6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/trusted-types/support/HTMLScriptElement-internal-slot-support.js
@@ -0,0 +1,2 @@
+window.postMessage("script url", "*");
+
diff --git a/third_party/blink/web_tests/http/tests/devtools/network/network-columns-sorted.js b/third_party/blink/web_tests/http/tests/devtools/network/network-columns-sorted.js
index 06bfe61..dcf5aa4 100644
--- a/third_party/blink/web_tests/http/tests/devtools/network/network-columns-sorted.js
+++ b/third_party/blink/web_tests/http/tests/devtools/network/network-columns-sorted.js
@@ -32,7 +32,7 @@
   function sortGrid() {
     var logView = UI.panels.network.networkLogView;
     var dataGrid = logView.dataGrid;
-    var columnsView = logView.columns;
+    var columnsView = logView.columns();
     TestRunner.addSniffer(columnsView, 'dataGridSortedForTest', dataGridSorted.bind(null, logView), true);
 
     dataGrid.markColumnAsSortedBy('name', DataGrid.DataGrid.Order.Ascending);
diff --git a/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-js/timeline-microtasks-expected.txt b/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-js/timeline-microtasks-expected.txt
index 0a23e26..cee85bd 100644
--- a/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-js/timeline-microtasks-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-js/timeline-microtasks-expected.txt
@@ -3,7 +3,7 @@
 RunMicrotasks Properties:
 {
     data : {
-        microtask_count : 1
+        microtask_count : 2
     }
     endTime : <number>
     startTime : <number>
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-fonts/font-palette-vs-shorthand-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/css/css-fonts/font-palette-vs-shorthand-expected.txt
new file mode 100644
index 0000000..b9913eda
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/external/wpt/css/css-fonts/font-palette-vs-shorthand-expected.txt
@@ -0,0 +1,7 @@
+This is a testharness.js-based test.
+FAIL CSS Fonts Module Level 4: interaction of font-palette and font shorthand assert_equals: expected "" but got "50px colr"
+FAIL CSS Fonts Module Level 4: interaction of font-palette and font shorthand 1 assert_equals: expected "normal" but got "dark"
+FAIL CSS Fonts Module Level 4: interaction of font-palette and font shorthand 2 assert_equals: expected "" but got "50px colr"
+PASS CSS Fonts Module Level 4: interaction of font-palette and font shorthand 3
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-fonts/font-palette-vs-shorthand-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/css/css-fonts/font-palette-vs-shorthand-expected.txt
new file mode 100644
index 0000000..b9913eda
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/external/wpt/css/css-fonts/font-palette-vs-shorthand-expected.txt
@@ -0,0 +1,7 @@
+This is a testharness.js-based test.
+FAIL CSS Fonts Module Level 4: interaction of font-palette and font shorthand assert_equals: expected "" but got "50px colr"
+FAIL CSS Fonts Module Level 4: interaction of font-palette and font shorthand 1 assert_equals: expected "normal" but got "dark"
+FAIL CSS Fonts Module Level 4: interaction of font-palette and font shorthand 2 assert_equals: expected "" but got "50px colr"
+PASS CSS Fonts Module Level 4: interaction of font-palette and font shorthand 3
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win10/external/wpt/css/css-fonts/font-palette-vs-shorthand-expected.txt b/third_party/blink/web_tests/platform/win10/external/wpt/css/css-fonts/font-palette-vs-shorthand-expected.txt
new file mode 100644
index 0000000..b9913eda
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win10/external/wpt/css/css-fonts/font-palette-vs-shorthand-expected.txt
@@ -0,0 +1,7 @@
+This is a testharness.js-based test.
+FAIL CSS Fonts Module Level 4: interaction of font-palette and font shorthand assert_equals: expected "" but got "50px colr"
+FAIL CSS Fonts Module Level 4: interaction of font-palette and font shorthand 1 assert_equals: expected "normal" but got "dark"
+FAIL CSS Fonts Module Level 4: interaction of font-palette and font shorthand 2 assert_equals: expected "" but got "50px colr"
+PASS CSS Fonts Module Level 4: interaction of font-palette and font shorthand 3
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/wpt_internal/trust-tokens/trust-token-api-rate-limiting.https.html b/third_party/blink/web_tests/wpt_internal/trust-tokens/trust-token-api-rate-limiting.https.html
new file mode 100644
index 0000000..2356e4a
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/trust-tokens/trust-token-api-rate-limiting.https.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Tests trust token issuance and redemption</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script>
+    'use strict';
+
+    function issue_token() {
+        return fetch('/wpt_internal/trust-tokens/resources/trust_token_issuance.py', {
+            trustToken: { type: 'token-request' }
+        });
+    }
+
+    function redeem_token() {
+        return fetch('/wpt_internal/trust-tokens/resources/trust_token_redemption.py', {
+            trustToken: { type: 'token-redemption', refreshPolicy: "refresh" }
+        });
+    }
+
+    promise_test(async function () {
+        // Issue a batch of tokens
+        const batch_size = 10;
+        const requests = [];
+        for (let i = 0; i < batch_size; i++) {
+            requests.push(issue_token());
+        }
+        await Promise.all(requests).then(responses =>
+            responses.forEach(response => assert_equals(response.status, 200)));
+
+        // Redeem three tokens - the last attempt should fail due to rate limiting
+        var response = await redeem_token();
+        assert_equals(response.status, 200);
+        response = await redeem_token();
+        assert_equals(response.status, 200);
+        return promise_rejects_dom(this, 'OperationError', redeem_token());
+
+    }, 'Token redemption is rate limited.');
+
+</script>
\ No newline at end of file
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 954b1d6..2a85ae21 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -58173,6 +58173,7 @@
   <int value="-1169571217" label="SharingDesktopScreenshotsEdit:disabled"/>
   <int value="-1168910727"
       label="enable-experimental-accessibility-language-detection-dynamic"/>
+  <int value="-1168123287" label="WebRTC-FrameBuffer3:disabled"/>
   <int value="-1167992523" label="DesktopPWAsCustomTabUI:disabled"/>
   <int value="-1166745977"
       label="BluetoothAggressiveAppearanceFilter:disabled"/>
@@ -58190,6 +58191,7 @@
   <int value="-1161384421" label="ContextualSuggestionsAboveArticles:enabled"/>
   <int value="-1160941363" label="AffiliationBasedMatching:disabled"/>
   <int value="-1160797265" label="PasswordScriptsFetching:enabled"/>
+  <int value="-1160730312" label="WebRTC-FrameBuffer3:enabled"/>
   <int value="-1160097262" label="WebAuthenticationCableSecondFactor:enabled"/>
   <int value="-1160026273" label="enable-web-notification-custom-layouts"/>
   <int value="-1159563774" label="enable-accessibility-script-injection"/>
@@ -62142,7 +62144,6 @@
   <int value="1241162639" label="debug-chime-notification"/>
   <int value="1242100010" label="AutofillProfileClientValidation:disabled"/>
   <int value="1242632259" label="ContentSuggestionsCategoryOrder:disabled"/>
-  <int value="1242669640" label="AutofillServerTypeTakesPrecedence:enabled"/>
   <int value="1243180545" label="HarfBuzzPDFSubsetter:enabled"/>
   <int value="1243704644" label="ArcFixupWindowFeature:enabled"/>
   <int value="1243890754" label="ForbidSyncXHRInPageDismissal:disabled"/>
@@ -62826,7 +62827,6 @@
   <int value="1673776797"
       label="ThrottleDisplayNoneAndVisibilityHiddenCrossOriginIframes:disabled"/>
   <int value="1675848452" label="BluetoothQualityReport:disabled"/>
-  <int value="1677066216" label="AutofillServerTypeTakesPrecedence:disabled"/>
   <int value="1677167062" label="AutomaticPasswordGeneration:enabled"/>
   <int value="1677258310" label="DragAppsInTabletMode:disabled"/>
   <int value="1678259296" label="ChromeWhatsNewInMainMenuNewBadge:enabled"/>
@@ -90446,6 +90446,7 @@
   <int value="37" label="Sign-in promo on NTP feed top section."/>
   <int value="38" label="Sync off settings row"/>
   <int value="39" label="Post device restore sign-in promo"/>
+  <int value="40" label="Post device restore background sign-in"/>
 </enum>
 
 <enum name="SigninAccountReconcilorState">
@@ -95076,6 +95077,7 @@
   <int value="2" label="Sync Turned On After Interrupted Advanced Flow"/>
   <int value="3" label="Sync Left Off After Interrupted Advanced Flow"/>
   <int value="4" label="Engine Initialized With Auto Start"/>
+  <int value="5" label="Restored backup of a syncing device on Android"/>
 </enum>
 
 <enum name="SyncFSConflictResolutionPolicy">
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml
index ec960ad..3f2f47b 100644
--- a/tools/metrics/histograms/metadata/media/histograms.xml
+++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -1338,8 +1338,26 @@
   </summary>
 </histogram>
 
+<histogram name="Media.AudioCapturerDroppedData10sIntervals" units="drops"
+    expires_after="2023-10-05">
+  <owner>fhernqvist@google.com</owner>
+  <owner>olka@chromium.org</owner>
+  <summary>
+    The number of input audio data blocks that were dropped at the
+    browser/renderer boundary due to for example buffer overflow in the writer
+    side buffer or in the socket. This value is aggregated over a period of 1000
+    input data pushes (every 10 seconds for buffer size 10 ms) and is logged at
+    the end of each collection interval. Not recorded for streams with less than
+    1000 input data pushes.
+  </summary>
+</histogram>
+
 <histogram name="Media.AudioCapturerDroppedData2.{Duration}" units="permille"
     expires_after="2023-10-05">
+  <obsolete>
+    Deprecated in favor of Media.AudioCapturerDroppedData10sIntervals and
+    Media.AudioCapturerDroppedDataBelow10s. Data is no longer collected.
+  </obsolete>
   <owner>olka@chromium.org</owner>
   <owner>gustaf@chromium.org</owner>
   <summary>
@@ -1354,8 +1372,38 @@
   </token>
 </histogram>
 
+<histogram name="Media.AudioCapturerDroppedDataBelow10s" units="drops"
+    expires_after="2023-10-05">
+  <owner>fhernqvist@google.com</owner>
+  <owner>olka@chromium.org</owner>
+  <summary>
+    The number of input audio data blocks that were dropped at the
+    browser/renderer boundary due to for example buffer overflow in the writer
+    side buffer or in the socket. This value is only logged for streams with
+    less than 1000 input data pushes (10 seconds for buffer size 10 ms).
+  </summary>
+</histogram>
+
+<histogram name="Media.AudioCapturerMissedReadDeadline10sIntervals"
+    units="misses" expires_after="2023-10-05">
+  <owner>fhernqvist@google.com</owner>
+  <owner>olka@chromium.org</owner>
+  <summary>
+    The number of times input audio data blocks that had to be buffered because
+    there was not room in the shared memory ring buffer on the browser/renderer
+    boundary. This happens if the reading side hasn't read data in time. This
+    value is aggregated over a period of 1000 input data pushes (every 10
+    seconds for buffer size 10 ms) and is logged at the end of each collection
+    interval. Not recorded for streams with less than 1000 input data pushes.
+  </summary>
+</histogram>
+
 <histogram name="Media.AudioCapturerMissedReadDeadline2.{Duration}"
     units="permille" expires_after="2023-10-05">
+  <obsolete>
+    Deprecated in favor of Media.AudioCapturerMissedReadDeadline10sIntervals and
+    Media.AudioCapturerMissedReadDeadlineBelow10s. Data is no longer collected.
+  </obsolete>
   <owner>olka@chromium.org</owner>
   <owner>gustaf@chromium.org</owner>
   <summary>
@@ -1371,6 +1419,19 @@
   </token>
 </histogram>
 
+<histogram name="Media.AudioCapturerMissedReadDeadlineBelow10s" units="misses"
+    expires_after="2023-10-05">
+  <owner>fhernqvist@google.com</owner>
+  <owner>olka@chromium.org</owner>
+  <summary>
+    The number of times input audio data blocks that had to be buffered because
+    there was not room in the shared memory ring buffer on the browser/renderer
+    boundary. This happens if the reading side hasn't read data in time. This
+    value is only logged for streams with less than 1000 input data pushes (10
+    seconds for buffer size 10 ms).
+  </summary>
+</histogram>
+
 <histogram name="Media.AudioCodec" enum="AudioCodec" expires_after="never">
 <!-- expires-never: Codec support planning metric. -->
 
diff --git a/tools/metrics/histograms/metadata/mobile/histograms.xml b/tools/metrics/histograms/metadata/mobile/histograms.xml
index 58b000e..2b5e6f9 100644
--- a/tools/metrics/histograms/metadata/mobile/histograms.xml
+++ b/tools/metrics/histograms/metadata/mobile/histograms.xml
@@ -104,6 +104,16 @@
   </summary>
 </histogram>
 
+<histogram name="Mobile.ContextMenu.CopyImage" enum="ContextMenuIOSCopyImage"
+    expires_after="2023-10-16">
+  <owner>djean@chromium.org</owner>
+  <owner>gambard@chromium.org</owner>
+  <summary>
+    Logged when &quot;copy image&quot; from context menu is invoked. Log the
+    events happening during the copying image procedure.
+  </summary>
+</histogram>
+
 <histogram name="Mobile.ContextMenu.EntryPoints" enum="IOSMenuScenario"
     expires_after="2023-04-01">
   <owner>seblalancette@chromium.org</owner>
@@ -115,6 +125,49 @@
   </summary>
 </histogram>
 
+<histogram name="Mobile.ContextMenu.GetImageDataByJsResult"
+    enum="ContextMenuIOSGetImageDataByJsResult" expires_after="2023-10-16">
+  <owner>djean@chromium.org</owner>
+  <owner>gambard@chromium.org</owner>
+  <summary>
+    Result of getting image data by JavaScript for CopyImage, SaveImage and
+    SearchByImage from iOS context menu. Recorded when the JavaScript returns,
+    or fails for timeout.
+  </summary>
+</histogram>
+
+<histogram name="Mobile.ContextMenu.LensSupportStatus"
+    enum="IOSLensSupportStatus" expires_after="2023-02-26">
+  <owner>hujasonx@google.com</owner>
+  <owner>lens-in-bling-team@google.com</owner>
+  <summary>
+    Whether or not Lens is supported, and if not, the reason why. Recorded only
+    if the feature is enabled when the long-press context menu is shown for an
+    image.
+  </summary>
+</histogram>
+
+<histogram name="Mobile.ContextMenu.LensWebUploadStatus"
+    enum="IOSLensWebUploadStatus" expires_after="2023-06-23">
+  <owner>hujasonx@google.com</owner>
+  <owner>lens-in-bling-team@google.com</owner>
+  <summary>
+    The status of the upload of image data to Lens. Recorded only when the Lens
+    feature is triggered via the context menu entry from an image long-press.
+  </summary>
+</histogram>
+
+<histogram name="Mobile.ContextMenu.LensWebUploadTime" units="ms"
+    expires_after="2023-06-28">
+  <owner>hujasonx@google.com</owner>
+  <owner>lens-in-bling-team@google.com</owner>
+  <summary>
+    Logs the time it takes to upload image data to the Lens Web servers.
+    Recorded only when the Lens feature is triggered via the context menu entry
+    from an image long-press.
+  </summary>
+</histogram>
+
 <histogram name="Mobile.ContextMenu.{EntryPoint}.Actions" enum="IOSMenuAction"
     expires_after="2023-04-01">
   <owner>seblalancette@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml
index 927bb284..07e84944 100644
--- a/tools/metrics/histograms/metadata/others/histograms.xml
+++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -3068,9 +3068,9 @@
 </histogram>
 
 <histogram name="ContextMenu.iOS.CopyImage" enum="ContextMenuIOSCopyImage"
-    expires_after="2021-12-05">
+    expires_after="M108">
   <obsolete>
-    Previously removed from code.
+    Replaced by Mobile.ContextMenu.CopyImage
   </obsolete>
   <owner>mrsuyi@chromium.org</owner>
   <owner>gambard@chromium.org</owner>
@@ -3081,7 +3081,10 @@
 </histogram>
 
 <histogram name="ContextMenu.iOS.GetImageDataByJsResult"
-    enum="ContextMenuIOSGetImageDataByJsResult" expires_after="2022-10-16">
+    enum="ContextMenuIOSGetImageDataByJsResult" expires_after="M108">
+  <obsolete>
+    Replaced by Mobile.ContextMenu.GetImageDataByJsResult
+  </obsolete>
   <owner>mrsuyi@chromium.org</owner>
   <owner>gambard@chromium.org</owner>
   <summary>
@@ -3092,7 +3095,10 @@
 </histogram>
 
 <histogram name="ContextMenu.iOS.LensSupportStatus" enum="IOSLensSupportStatus"
-    expires_after="2023-02-26">
+    expires_after="M108">
+  <obsolete>
+    Replaced by Mobile.ContextMenu.LensSupportStatus
+  </obsolete>
   <owner>hujasonx@google.com</owner>
   <owner>lens-in-bling-team@google.com</owner>
   <summary>
@@ -3103,7 +3109,10 @@
 </histogram>
 
 <histogram name="ContextMenu.iOS.LensWebUploadStatus"
-    enum="IOSLensWebUploadStatus" expires_after="2023-06-23">
+    enum="IOSLensWebUploadStatus" expires_after="M108">
+  <obsolete>
+    Replaced by Mobile.ContextMenu.LensWebUploadStatus
+  </obsolete>
   <owner>hujasonx@google.com</owner>
   <owner>lens-in-bling-team@google.com</owner>
   <summary>
@@ -3113,7 +3122,10 @@
 </histogram>
 
 <histogram name="ContextMenu.iOS.LensWebUploadTime" units="ms"
-    expires_after="2023-06-28">
+    expires_after="M108">
+  <obsolete>
+    Replaced by Mobile.ContextMenu.LensWebUploadTime
+  </obsolete>
   <owner>hujasonx@google.com</owner>
   <owner>lens-in-bling-team@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/web_rtc/histograms.xml b/tools/metrics/histograms/metadata/web_rtc/histograms.xml
index 73ba584..07547236 100644
--- a/tools/metrics/histograms/metadata/web_rtc/histograms.xml
+++ b/tools/metrics/histograms/metadata/web_rtc/histograms.xml
@@ -133,52 +133,6 @@
   </summary>
 </histogram>
 
-<histogram name="WebRTC.Audio.Agc.ClippingPredictor.F1Score" units="%"
-    expires_after="2022-04-03">
-  <owner>alessiob@chromium.org</owner>
-  <owner>silen@chromium.org</owner>
-  <summary>
-    Logs the F1 score for the clipping predictor used in AgcManagerDirect. A log
-    call is made every 30 seconds during an active WebRTC call using the analog
-    gain controller and the clipping predictor feature.
-  </summary>
-</histogram>
-
-<histogram name="WebRTC.Audio.Agc.ClippingPredictor.Precision" units="%"
-    expires_after="2022-04-24">
-  <owner>silen@chromium.org</owner>
-  <owner>alessiob@chromium.org</owner>
-  <summary>
-    Logs the precision for the clipping predictor used in AgcManagerDirect. A
-    log call is made every 30 seconds during an active WebRTC call using the
-    analog gain controller and the clipping predictor feature.
-  </summary>
-</histogram>
-
-<histogram name="WebRTC.Audio.Agc.ClippingPredictor.PredictionInterval"
-    units="frames" expires_after="2022-04-03">
-  <owner>alessiob@chromium.org</owner>
-  <owner>silen@chromium.org</owner>
-  <summary>
-    Logs the time elapsed between a clipping prediction and a matched clipping
-    detection for the clipping predictor used in AgcManagerDirect. A log call is
-    made every time a predicted clipping event is matched (theoretical upper
-    bound: one call every 10 ms) during an active WebRTC call using the analog
-    gain controller and the clipping predictor feature.
-  </summary>
-</histogram>
-
-<histogram name="WebRTC.Audio.Agc.ClippingPredictor.Recall" units="%"
-    expires_after="2022-05-01">
-  <owner>silen@chromium.org</owner>
-  <owner>alessiob@chromium.org</owner>
-  <summary>
-    Logs the recall for the clipping predictor used in AgcManagerDirect. A log
-    call is made every 30 seconds during an active WebRTC call using the analog
-    gain controller and the clipping predictor feature.
-  </summary>
-</histogram>
-
 <histogram name="WebRTC.Audio.Agc.DigitalGainApplied" units="dB"
     expires_after="2023-02-26">
   <owner>alessiob@chromium.org</owner>
@@ -337,7 +291,7 @@
 </histogram>
 
 <histogram name="WebRTC.Audio.ApmAnalogGainIncreaseRate" units="changes/minute"
-    expires_after="2022-10-05">
+    expires_after="2023-02-12">
   <owner>silen@chromium.org</owner>
   <owner>alessiob@chromium.org</owner>
   <summary>
@@ -1491,6 +1445,9 @@
 
 <histogram name="WebRTC.PeerConnection.IceServers.{MeasuredAt}" units="servers"
     expires_after="2023-04-15">
+  <obsolete>
+    Removed 10/2022.
+  </obsolete>
   <owner>hta@chromium.org</owner>
   <owner>webrtc-dev@chromium.org</owner>
   <summary>
@@ -1649,12 +1606,16 @@
 </histogram>
 
 <histogram name="WebRTC.PeerConnection.RtcpMux" enum="PeerConnectionRtcpMux"
-    expires_after="2020-02-23">
-  <owner>pthatcher@chromium.org</owner>
+    expires_after="2023-04-07">
+  <owner>hta@chromium.org</owner>
+  <owner>webrtc-dev@chromium.org</owner>
   <summary>
     Whether RTCP-mux is used for the PeerConnection (both the local and remote
     description enable RTCP-mux). Recorded after SetLocalDescription and
     SetRemoteDescription are called, once per PeerConnection.
+
+    Warning: This histogram was expired from 2020-02-23 to 2022-10-10. Data may
+    be missing.
   </summary>
 </histogram>
 
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index b240769..74b0ba1 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,24 +5,24 @@
             "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux_arm64/49b4b5dcbc312d8d2c3751cf29238b8efeb4e494/trace_processor_shell"
         },
         "win": {
-            "hash": "8e4a2236e8f81df7763b3fd72cb8890a302e96e8",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/5c42ac9c2c8efd77f14d56462d18eb644f36b78b/trace_processor_shell.exe"
+            "hash": "1323c769a4f9a4f54ffbee56c44e7583a160bad3",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/fec36b962880a07fc589185bab8b2f0cc3f9c9ff/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "58893933be305d3bfe0a72ebebcacde2ac3ca893",
             "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux_arm/49b4b5dcbc312d8d2c3751cf29238b8efeb4e494/trace_processor_shell"
         },
         "mac": {
-            "hash": "4c1aee5a287ffe32741df55c393fdefa71cbd6f6",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/5c42ac9c2c8efd77f14d56462d18eb644f36b78b/trace_processor_shell"
+            "hash": "1b5478e8c595694b89b1f55051e78750c6ca7fc8",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/fec36b962880a07fc589185bab8b2f0cc3f9c9ff/trace_processor_shell"
         },
         "mac_arm64": {
             "hash": "e1ad4861384b06d911a65f035317914b8cc975c6",
             "full_remote_path": "perfetto-luci-artifacts/v25.0/mac-arm64/trace_processor_shell"
         },
         "linux": {
-            "hash": "9695f69cb1481779df72a567967889c22772cec9",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/099aff9404a0b944aa2d90a08a4e21655655e73e/trace_processor_shell"
+            "hash": "5c275de3a0ece764faa6d5c93c91485f1d950b82",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/fec36b962880a07fc589185bab8b2f0cc3f9c9ff/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/ui/accessibility/ax_tree.cc b/ui/accessibility/ax_tree.cc
index 0a55e69e..f7e452d1 100644
--- a/ui/accessibility/ax_tree.cc
+++ b/ui/accessibility/ax_tree.cc
@@ -21,6 +21,7 @@
 #include "base/notreached.h"
 #include "base/observer_list.h"
 #include "base/strings/stringprintf.h"
+#include "base/timer/elapsed_timer.h"
 #include "components/crash/core/common/crash_key.h"
 #include "ui/accessibility/accessibility_switches.h"
 #include "ui/accessibility/ax_enums.mojom.h"
@@ -789,6 +790,8 @@
 }
 
 void AXTree::Destroy() {
+  base::ElapsedThreadTimer timer;
+
   table_info_map_.clear();
   if (!root_)
     return;
@@ -801,6 +804,9 @@
     // raw_ptr instance that is allowed to dangle.
     DestroyNodeAndSubtree(root_.ExtractAsDangling(), nullptr);
   }  // tree_update_in_progress.
+
+  UMA_HISTOGRAM_TIMES("Accessibility.Performance.AXTree.Destroy",
+                      timer.Elapsed());
 }
 
 void AXTree::UpdateDataForTesting(const AXTreeData& new_data) {
diff --git a/ui/accessibility/platform/ax_system_caret_win.cc b/ui/accessibility/platform/ax_system_caret_win.cc
index 78da26c..19c5c88d 100644
--- a/ui/accessibility/platform/ax_system_caret_win.cc
+++ b/ui/accessibility/platform/ax_system_caret_win.cc
@@ -16,9 +16,15 @@
 
 namespace ui {
 
+// static
+void AXSystemCaretWin::AXPlatformNodeWinDeleter(AXPlatformNodeWin* ptr) {
+  ptr->Destroy();
+}
+
 AXSystemCaretWin::AXSystemCaretWin(gfx::AcceleratedWidget event_target)
     : event_target_(event_target) {
-  caret_ = static_cast<AXPlatformNodeWin*>(AXPlatformNodeWin::Create(this));
+  caret_.reset(
+      static_cast<AXPlatformNodeWin*>(AXPlatformNodeWin::Create(this)));
   // The caret object is not part of the accessibility tree and so doesn't need
   // a node ID. A globally unique ID is used when firing Win events, retrieved
   // via |unique_id|.
@@ -42,7 +48,6 @@
     ::NotifyWinEvent(EVENT_OBJECT_DESTROY, event_target_, OBJID_CARET,
                      -caret_->GetUniqueId());
   }
-  caret_->Destroy();
 }
 
 Microsoft::WRL::ComPtr<IAccessible> AXSystemCaretWin::GetCaret() const {
diff --git a/ui/accessibility/platform/ax_system_caret_win.h b/ui/accessibility/platform/ax_system_caret_win.h
index 8713de3b..ef91666 100644
--- a/ui/accessibility/platform/ax_system_caret_win.h
+++ b/ui/accessibility/platform/ax_system_caret_win.h
@@ -5,6 +5,8 @@
 #ifndef UI_ACCESSIBILITY_PLATFORM_AX_SYSTEM_CARET_WIN_H_
 #define UI_ACCESSIBILITY_PLATFORM_AX_SYSTEM_CARET_WIN_H_
 
+#include <type_traits>
+
 #include <oleacc.h>
 #include <wrl/client.h>
 
@@ -48,7 +50,12 @@
   bool ShouldIgnoreHoveredStateForTesting() override;
   const ui::AXUniqueId& GetUniqueId() const override;
 
-  raw_ptr<AXPlatformNodeWin, DanglingUntriaged> caret_;
+  static void AXPlatformNodeWinDeleter(AXPlatformNodeWin* ptr);
+
+  using deleter = std::integral_constant<
+      decltype(AXSystemCaretWin::AXPlatformNodeWinDeleter)*,
+      AXSystemCaretWin::AXPlatformNodeWinDeleter>;
+  std::unique_ptr<AXPlatformNodeWin, deleter> caret_;
   gfx::AcceleratedWidget event_target_;
   AXNodeData data_;
   ui::AXUniqueId unique_id_;
diff --git a/ui/aura/env.h b/ui/aura/env.h
index 746f642..7b17df5a 100644
--- a/ui/aura/env.h
+++ b/ui/aura/env.h
@@ -206,8 +206,7 @@
   std::unique_ptr<ui::PlatformEventSource> event_source_;
 
   // TODO(crbug.com/1298696): Breaks content_unittests.
-  raw_ptr<ui::ContextFactory, DanglingUntriagedDegradeToNoOpWhenMTE>
-      context_factory_ = nullptr;
+  raw_ptr<ui::ContextFactory, DegradeToNoOpWhenMTE> context_factory_ = nullptr;
 
   static bool initial_throttle_input_on_resize_;
   bool throttle_input_on_resize_ = initial_throttle_input_on_resize_;
diff --git a/ui/file_manager/file_manager/BUILD.gn b/ui/file_manager/file_manager/BUILD.gn
index c2308e3..a9fe281 100644
--- a/ui/file_manager/file_manager/BUILD.gn
+++ b/ui/file_manager/file_manager/BUILD.gn
@@ -71,6 +71,7 @@
     "foreground/images/files/ui/photos_logo.svg",
     "foreground/images/files/ui/empty_folder.svg",
     "foreground/images/files/ui/empty_trash_folder.svg",
+    "foreground/images/files/ui/error.svg",
     "foreground/images/files/ui/external_link.svg",
     "foreground/images/files/ui/filetype_placeholder_generic.svg",
     "foreground/images/files/ui/holding_space_welcome_image.svg",
@@ -79,6 +80,7 @@
     "foreground/images/files/ui/menu_ng.svg",
     "foreground/images/files/ui/nudge_star_icon.svg",
     "foreground/images/files/ui/offline.svg",
+    "foreground/images/files/ui/in_progress_indicator.svg",
     "foreground/images/files/ui/refresh.svg",
     "foreground/images/files/ui/restore.svg",
     "foreground/images/files/ui/search.svg",
diff --git a/ui/file_manager/file_manager/background/js/BUILD.gn b/ui/file_manager/file_manager/background/js/BUILD.gn
index 9fcf6b9..1addd4b 100644
--- a/ui/file_manager/file_manager/background/js/BUILD.gn
+++ b/ui/file_manager/file_manager/background/js/BUILD.gn
@@ -61,14 +61,14 @@
     ":volume_manager_util",
   ]
 
-  closure_flags =
-      strict_error_checking_closure_args + [
-        "language_in=ECMASCRIPT_2020",
-        "js_module_root=./gen/ui",
-        "js_module_root=" + rebase_path("//ui", root_build_dir),
-        "browser_resolver_prefix_replacements=\"chrome://webui-test/=./\"",
-        "hide_warnings_for=third_party/",
-      ]
+  closure_flags = strict_error_checking_closure_args + [
+                    "language_in=ECMASCRIPT_2020",
+                    "js_module_root=./gen/ui",
+                    "js_module_root=" + rebase_path("//ui", root_build_dir),
+                    "browser_resolver_prefix_replacements=\"chrome://webui-test/=./\"",
+                    "hide_warnings_for=third_party/",
+                    "browser_resolver_prefix_replacements=\"chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp/=./image_loader/\"",
+                  ]
 }
 
 js_type_check("test_support_modules_type_check") {
@@ -180,6 +180,7 @@
     "//ui/file_manager/file_manager/externs:drive_dialog_controller",
     "//ui/file_manager/file_manager/externs/background:drive_sync_handler",
     "//ui/file_manager/file_manager/externs/background:progress_center",
+    "//ui/file_manager/file_manager/foreground/js/metadata:metadata_model",
     "//ui/webui/resources/js/cr:event_target",
   ]
 }
@@ -192,6 +193,7 @@
     "//ui/file_manager/file_manager/common/js:mock_chrome",
     "//ui/file_manager/file_manager/common/js:progress_center_common",
     "//ui/file_manager/file_manager/common/js:url_constants",
+    "//ui/file_manager/file_manager/foreground/js/metadata:metadata_model",
     "//ui/webui/resources/js:load_time_data.m",
   ]
 }
@@ -503,12 +505,12 @@
     ":volume_manager_unittest",
   ]
 
-  closure_flags =
-      strict_error_checking_closure_args + [
-        "language_in=ECMASCRIPT_2020",
-        "js_module_root=./gen/ui",
-        "js_module_root=" + rebase_path("//ui", root_build_dir),
-        "browser_resolver_prefix_replacements=\"chrome://webui-test/=./\"",
-        "hide_warnings_for=third_party/",
-      ]
+  closure_flags = strict_error_checking_closure_args + [
+                    "language_in=ECMASCRIPT_2020",
+                    "js_module_root=./gen/ui",
+                    "js_module_root=" + rebase_path("//ui", root_build_dir),
+                    "browser_resolver_prefix_replacements=\"chrome://webui-test/=./\"",
+                    "hide_warnings_for=third_party/",
+                    "browser_resolver_prefix_replacements=\"chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp/=./image_loader/\"",
+                  ]
 }
diff --git a/ui/file_manager/file_manager/background/js/drive_sync_handler.js b/ui/file_manager/file_manager/background/js/drive_sync_handler.js
index 751d3f5..8aedf44 100644
--- a/ui/file_manager/file_manager/background/js/drive_sync_handler.js
+++ b/ui/file_manager/file_manager/background/js/drive_sync_handler.js
@@ -12,6 +12,7 @@
 import {DriveSyncHandler} from '../../externs/background/drive_sync_handler.js';
 import {ProgressCenter} from '../../externs/background/progress_center.js';
 import {DriveDialogControllerInterface} from '../../externs/drive_dialog_controller.js';
+import {MetadataModel} from '../../foreground/js/metadata/metadata_model.js';
 
 import {fileOperationUtil} from './file_operation_util.js';
 
@@ -33,6 +34,13 @@
     this.progressCenter_ = progressCenter;
 
     /**
+     * The metadata model to notify entries have changed.
+     * @type {?MetadataModel}
+     * @private
+     */
+    this.metadataModel_ = null;
+
+    /**
      * Predefined error ID for out of quota messages.
      * @type {number}
      * @const
@@ -185,6 +193,13 @@
   }
 
   /**
+   * @param {!MetadataModel} model
+   */
+  set metadataModel(model) {
+    this.metadataModel_ = model;
+  }
+
+  /**
    * Returns the completed event name.
    * @return {string}
    */
@@ -234,20 +249,35 @@
       this.progressCenter_.updateItem(item);
       return;
     }
-    switch (status.transferState) {
-      case 'in_progress':
-        await this.updateItem_(item, status);
-        break;
-      case 'completed':
-      case 'failed':
-        if ((status.hideWhenZeroJobs && status.numTotalJobs === 0) ||
-            (!status.hideWhenZeroJobs && status.numTotalJobs === 1)) {
-          await this.removeItem_(item, status);
-        }
-        break;
-      default:
-        throw new Error(
-            'Invalid transfer state: ' + status.transferState + '.');
+
+    try {
+      const entry = await util.urlToEntry(status.fileUrl);
+
+      if (util.isInlineSyncStatusEnabled()) {
+        this.metadataModel_.notifyEntriesChanged([entry]);
+        this.metadataModel_.get([entry], ['syncStatus']);
+
+        // If inline sync status is enabled, don't display visual signal for
+        // Drive syncing.
+        return;
+      }
+      switch (status.transferState) {
+        case 'in_progress':
+          await this.updateItem_(item, status, entry);
+          break;
+        case 'completed':
+        case 'failed':
+          if ((status.hideWhenZeroJobs && status.numTotalJobs === 0) ||
+              (!status.hideWhenZeroJobs && status.numTotalJobs === 1)) {
+            await this.removeItem_(item, status);
+          }
+          break;
+        default:
+          throw new Error(
+              'Invalid transfer state: ' + status.transferState + '.');
+      }
+    } catch (error) {
+      console.warn('Resolving URL ' + status.fileUrl + ' is failed: ', error);
     }
   }
 
@@ -256,15 +286,12 @@
    * @param {ProgressCenterItem} item Item to update.
    * @param {chrome.fileManagerPrivate.FileTransferStatus} status Transfer
    *     status.
+   * @param {!Entry} entry Transfer status' corresponding entry.
    * @private
    */
-  async updateItem_(item, status) {
+  async updateItem_(item, status, entry) {
     const unlock = await this.queue_.lock();
     try {
-      const entry = await new Promise((resolve, reject) => {
-        window.webkitResolveLocalFileSystemURL(status.fileUrl, resolve, reject);
-      });
-
       item.state = ProgressItemState.PROGRESSING;
       item.type = ProgressItemType.SYNC;
       item.quiet = true;
@@ -284,8 +311,6 @@
       item.remainingTime = speedometer.getRemainingTime();
 
       this.progressRateLimiter_.run();
-    } catch (error) {
-      console.warn('Resolving URL ' + status.fileUrl + ' is failed: ', error);
     } finally {
       unlock();
     }
diff --git a/ui/file_manager/file_manager/background/js/mock_drive_sync_handler.js b/ui/file_manager/file_manager/background/js/mock_drive_sync_handler.js
index 3225904a..0b7f070d 100644
--- a/ui/file_manager/file_manager/background/js/mock_drive_sync_handler.js
+++ b/ui/file_manager/file_manager/background/js/mock_drive_sync_handler.js
@@ -60,6 +60,11 @@
   }
 
   /**
+   * @param {Object} model
+   */
+  set metadataModel(model) {}
+
+  /**
    * Adds a dialog to be controlled by DriveSyncHandler.
    * @param {string} appId App ID of window containing the dialog.
    * @param {DriveDialogControllerInterface} dialog
diff --git a/ui/file_manager/file_manager/common/js/util.js b/ui/file_manager/file_manager/common/js/util.js
index 7b5198e9..c7f2e11e 100644
--- a/ui/file_manager/file_manager/common/js/util.js
+++ b/ui/file_manager/file_manager/common/js/util.js
@@ -1357,6 +1357,15 @@
 };
 
 /**
+ * Returns true if InlineSyncStatus feature flag is enabled.
+ * @returns {boolean}
+ */
+util.isInlineSyncStatusEnabled = () => {
+  return loadTimeData.valueExists('INLINE_SYNC_STATUS') &&
+      loadTimeData.getBoolean('INLINE_SYNC_STATUS');
+};
+
+/**
  * Retrieves all entries inside the given |rootEntry|.
  * @param {!DirectoryEntry} rootEntry
  * @param {function(!Array<!Entry>)} entriesCallback Called when some chunk of
diff --git a/ui/file_manager/file_manager/externs/background/drive_sync_handler.js b/ui/file_manager/file_manager/externs/background/drive_sync_handler.js
index 0da04b18..dda6f62 100644
--- a/ui/file_manager/file_manager/externs/background/drive_sync_handler.js
+++ b/ui/file_manager/file_manager/externs/background/drive_sync_handler.js
@@ -34,6 +34,11 @@
   get syncing() {}
 
   /**
+   * @param {Object} model
+   */
+  set metadataModel(model) {}
+
+  /**
    * Adds a dialog to be controlled by DriveSyncHandler.
    * @param {string} appId App ID of window containing the dialog.
    * @param {DriveDialogControllerInterface} dialog Dialog to be controlled.
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager.css b/ui/file_manager/file_manager/foreground/css/file_manager.css
index 87c6f2b..8dd0b86 100644
--- a/ui/file_manager/file_manager/foreground/css/file_manager.css
+++ b/ui/file_manager/file_manager/foreground/css/file_manager.css
@@ -1500,6 +1500,33 @@
   position: relative;
 }
 
+body.files-ng .thumbnail-frame > .sync-status {
+  height: 16px;
+  position: absolute;
+  right: 4px;
+  top: 4px;
+  width: 16px;
+}
+
+body.files-ng li:not([renaming]):not(.dim-offline) .thumbnail-frame > .sync-status {
+  background-position: center;
+  background-repeat: no-repeat;
+  background-size: 16px 16px;
+}
+
+body.files-ng li:not([renaming]):not(.dim-offline) .thumbnail-frame[data-sync-status=in_progress] > .sync-status {
+  background-image: url(../images/files/ui/in_progress_indicator.svg);
+}
+
+body.files-ng li:not([renaming]):not(.dim-offline) .thumbnail-frame[data-sync-status=error] > .sync-status {
+  background-image: url(../images/files/ui/error.svg);
+}
+
+body.files-ng li.directory .thumbnail-frame > .sync-status {
+  height: 100%;
+  top: 0;
+}
+
 html:not(.pointer-active) body[type='full-page'] .thumbnail-frame > .img-container,
 body[type='full-page'] .thumbnail-frame > .img-container:active,
 html:not(.pointer-active) body[type='full-page'] .detail-name .detail-icon,
@@ -2420,7 +2447,7 @@
 }
 
 body.files-ng #list-container
-    li.pinned:not([renaming]):not(.dim-offline) .detail-pinned {
+    li.pinned:not([renaming]):not(.dim-offline):not(.sync-in-progress):not(.sync-error) .detail-pinned {
   -webkit-mask-image: url(../images/files/ui/offline.svg);
   -webkit-mask-position: center;
   -webkit-mask-repeat: no-repeat;
@@ -2430,6 +2457,23 @@
   width: 40px;
 }
 
+body.files-ng #list-container li[data-sync-status]:not([renaming]):not(.dim-offline) .detail-pinned {
+  background-position: center;
+  background-repeat: no-repeat;
+  background-size: 16px 16px;
+  display: flex;
+  height: 32px;
+  width: 32px;
+}
+
+body.files-ng #list-container li[data-sync-status=in_progress]:not([renaming]):not(.dim-offline) .detail-pinned {
+  background-image: url(../images/files/ui/in_progress_indicator.svg);
+}
+
+body.files-ng #list-container li[data-sync-status=error]:not([renaming]):not(.dim-offline) .detail-pinned {
+  background-image: url(../images/files/ui/error.svg);
+}
+
 #new-folder-button {
   flex: none;
 }
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager_gm3.css b/ui/file_manager/file_manager/foreground/css/file_manager_gm3.css
index a06f9fb..398e43f 100644
--- a/ui/file_manager/file_manager/foreground/css/file_manager_gm3.css
+++ b/ui/file_manager/file_manager/foreground/css/file_manager_gm3.css
@@ -1497,6 +1497,33 @@
   position: relative;
 }
 
+body.files-ng .thumbnail-frame > .sync-status {
+  height: 16px;
+  position: absolute;
+  right: 4px;
+  top: 4px;
+  width: 16px;
+}
+
+body.files-ng li:not([renaming]):not(.dim-offline) .thumbnail-frame > .sync-status {
+  background-position: center;
+  background-repeat: no-repeat;
+  background-size: 16px 16px;
+}
+
+body.files-ng li:not([renaming]):not(.dim-offline) .thumbnail-frame[data-sync-status=in_progress] > .sync-status {
+  background-image: url(../images/files/ui/in_progress_indicator.svg);
+}
+
+body.files-ng li:not([renaming]):not(.dim-offline) .thumbnail-frame[data-sync-status=error] > .sync-status {
+  background-image: url(../images/files/ui/error.svg);
+}
+
+body.files-ng li.directory .thumbnail-frame > .sync-status {
+  height: 100%;
+  top: 0;
+}
+
 html:not(.pointer-active) body[type='full-page'] .thumbnail-frame > .img-container,
 body[type='full-page'] .thumbnail-frame > .img-container:active,
 html:not(.pointer-active) body[type='full-page'] .detail-name .detail-icon,
@@ -2418,7 +2445,7 @@
 }
 
 body.files-ng #list-container
-    li.pinned:not([renaming]):not(.dim-offline) .detail-pinned {
+    li.pinned:not([renaming]):not(.dim-offline):not(.sync-in-progress):not(.sync-error) .detail-pinned {
   -webkit-mask-image: url(../images/files/ui/offline.svg);
   -webkit-mask-position: center;
   -webkit-mask-repeat: no-repeat;
@@ -2428,6 +2455,23 @@
   width: 40px;
 }
 
+body.files-ng #list-container li[data-sync-status]:not([renaming]):not(.dim-offline) .detail-pinned {
+  background-position: center;
+  background-repeat: no-repeat;
+  background-size: 16px 16px;
+  display: flex;
+  height: 32px;
+  width: 32px;
+}
+
+body.files-ng #list-container li[data-sync-status=in_progress]:not([renaming]):not(.dim-offline) .detail-pinned {
+  background-image: url(../images/files/ui/in_progress_indicator.svg);
+}
+
+body.files-ng #list-container li[data-sync-status=error]:not([renaming]):not(.dim-offline) .detail-pinned {
+  background-image: url(../images/files/ui/error.svg);
+}
+
 #new-folder-button {
   flex: none;
 }
diff --git a/ui/file_manager/file_manager/foreground/images/files/ui/error.svg b/ui/file_manager/file_manager/foreground/images/files/ui/error.svg
new file mode 100644
index 0000000..8a1b5391
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/files/ui/error.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><circle id="prefix__outline" cx="8" cy="8" r="6.6" fill="#fff"/><path fill="#d93025" d="M8 13.8A5.8 5.8 0 1113.8 8 5.8 5.8 0 018 13.8zm0-10A4.2 4.2 0 1012.2 8 4.2 4.2 0 008 3.8z"/><path fill="#d93025" d="M7.2 5h1.6v3.35H7.2zm0 4.5h1.6V11H7.2z"/></svg>
diff --git a/ui/file_manager/file_manager/foreground/images/files/ui/in_progress_indicator.svg b/ui/file_manager/file_manager/foreground/images/files/ui/in_progress_indicator.svg
new file mode 100644
index 0000000..1eb514d
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/files/ui/in_progress_indicator.svg
@@ -0,0 +1 @@
+<svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><mask id="prefix__a" maskUnits="userSpaceOnUse" x="1" y="1" width="14" height="14" fill="#000"><path fill="#fff" d="M1 1h14v14H1z"/><path fill-rule="evenodd" clip-rule="evenodd" d="M8 14a6 6 0 004.08-10.4h.72V2.4h-2.64a6 6 0 00-6.238 10H3.2v1.2h2.642c.67.258 1.397.4 2.158.4z"/></mask><path fill-rule="evenodd" clip-rule="evenodd" d="M8 14a6 6 0 004.08-10.4h.72V2.4h-2.64a6 6 0 00-6.238 10H3.2v1.2h2.642c.67.258 1.397.4 2.158.4z" fill="#fff"/><path d="M12.08 3.6v-1l-2.547.002L11.4 4.334l.68-.733zm.72 0v1h1v-1h-1zm0-1.2h1v-1h-1v1zm-2.64 0l-.36.933.173.067h.187v-1zm-6.238 10l-.001 1 2.551.002-1.87-1.734-.68.733zm-.722 0v-1h-1v1h1zm0 1.2h-1v1h1v-1zm2.642 0l.36-.933-.173-.067h-.187v1zM13 8a5 5 0 01-5 5v2a7 7 0 007-7h-2zm-1.6-3.666A4.984 4.984 0 0113 8h2a6.984 6.984 0 00-2.24-5.132L11.4 4.334zM12.8 2.6h-.72v2h.72v-2zm-1-.2v1.2h2V2.4h-2zm-1.64 1h2.64v-2h-2.64v2zM8 3c.636 0 1.242.118 1.8.333l.72-1.866A6.985 6.985 0 008 1v2zM3 8a5 5 0 015-5V1a7 7 0 00-7 7h2zm1.601 3.668A4.984 4.984 0 013 8H1c0 2.029.864 3.857 2.242 5.134l1.36-1.466zM3.2 13.4h.722l.001-2H3.2v2zm1 .2v-1.2h-2v1.2h2zm1.643-1H3.2v2h2.642v-2zM8 13a4.985 4.985 0 01-1.798-.333l-.72 1.867A6.987 6.987 0 008 15v-2z" fill="#fff" mask="url(#prefix__a)"/><path fill-rule="evenodd" clip-rule="evenodd" d="M7.2 2.457V4.08A4.001 4.001 0 006 11.465V9.6h1.2v4h-4v-1.2h1.337a5.602 5.602 0 012.475-9.914l.188-.03zm5.6-.057v1.2h-1.334A5.601 5.601 0 018.8 13.544V11.92a4.001 4.001 0 001.2-7.384V6.4H8.8v-4h4z" fill="#1A73E8"/></svg>
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager.js b/ui/file_manager/file_manager/foreground/js/file_manager.js
index ad741ae..30c981f 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager.js
@@ -655,6 +655,10 @@
     assert(this.fileOperationManager_);
     assert(this.dialogDom_);
 
+    if (util.isInlineSyncStatusEnabled()) {
+      this.fileBrowserBackground_.driveSyncHandler.metadataModel =
+          assert(this.metadataModel_);
+    }
     this.scanController_ = new ScanController(
         this.directoryModel_, this.ui_.listContainer, this.spinnerController_,
         this.selectionHandler_);
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider.js b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider.js
index 2c74cf2..3ba7370 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider.js
@@ -97,6 +97,7 @@
       item.isMachineRoot = prop.isMachineRoot;
       item.isExternalMedia = prop.isExternalMedia;
       item.isArbitrarySyncFolder = prop.isArbitrarySyncFolder;
+      item.syncStatus = prop.syncStatus;
       results.push(item);
     }
     return results;
@@ -134,4 +135,5 @@
   'isMachineRoot',
   'isExternalMedia',
   'isArbitrarySyncFolder',
+  'syncStatus',
 ];
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/metadata_item.js b/ui/file_manager/file_manager/foreground/js/metadata/metadata_item.js
index d17855d..5066c46d 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/metadata_item.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/metadata_item.js
@@ -292,5 +292,11 @@
      * @public {string|undefined}
      */
     this.sourceUrl;
+
+    /**
+     * Status indicating the current syncing behaviour for this item.
+     * @type {string|undefined}
+     */
+    this.syncStatus;
   }
 }
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_grid.js b/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
index b86f1b0a..e864e2a0 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
@@ -714,6 +714,7 @@
 
       this.decorateThumbnailBox_(assert(listItem), entry);
       this.updateSharedStatus_(assert(listItem), entry);
+      this.updateInlineSyncStatus_(assert(listItem), entry);
     }
     this.updateGroupHeading_();
   }
@@ -753,6 +754,12 @@
     frame.className = 'thumbnail-frame';
     li.appendChild(frame);
 
+    if (util.isInlineSyncStatusEnabled()) {
+      const syncStatus = li.ownerDocument.createElement('div');
+      syncStatus.className = 'sync-status';
+      frame.appendChild(syncStatus);
+    }
+
     const box = li.ownerDocument.createElement('div');
     box.classList.add('img-container', 'no-thumbnail');
     frame.appendChild(box);
@@ -784,6 +791,7 @@
     li.setAttribute('file-name', util.getEntryLabel(locationInfo, entry));
 
     this.updateSharedStatus_(li, entry);
+    this.updateInlineSyncStatus_(li, entry);
   }
 
   /**
@@ -846,6 +854,25 @@
   }
 
   /**
+   * Update sync status icon for file or directory entry.
+   * @param {!HTMLLIElement} li The grid item.
+   * @param {!Entry} entry File entry for the grid item.
+   * @private
+   */
+  updateInlineSyncStatus_(li, entry) {
+    if (!util.isInlineSyncStatusEnabled()) {
+      return;
+    }
+    const frame = li.querySelector('.thumbnail-frame');
+    const syncStatus =
+        this.metadataModel_.getCache([entry], ['syncStatus'])[0].syncStatus;
+    if (frame && syncStatus) {
+      frame.setAttribute('data-sync-status', syncStatus);
+      // TODO(msalomao): set sync status aria-label.
+    }
+  }
+
+  /**
    * Handles the splice event of the data model to change the view based on
    * whether image files is dominant or not in the directory.
    * @private
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_table.js b/ui/file_manager/file_manager/foreground/js/ui/file_table.js
index e26ff0b..6e95f341 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_table.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_table.js
@@ -973,6 +973,7 @@
                   'isExternalMedia',
                   'hosted',
                   'pinned',
+                  'syncStatus',
                 ])[0],
             util.isTeamDriveRoot(entry));
       });
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_table_list.js b/ui/file_manager/file_manager/foreground/js/ui/file_table_list.js
index 6e78747..73f3ea83 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_table_list.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_table_list.js
@@ -472,6 +472,13 @@
     iconDiv.classList.toggle(
         'external-media-root', !!externalProps.isExternalMedia);
   }
+
+  if (util.isInlineSyncStatusEnabled()) {
+    li.toggleAttribute(
+        'data-sync-status', externalProps.syncStatus !== 'not_found');
+    li.setAttribute('data-sync-status', externalProps.syncStatus);
+    // TODO(msalomao): set sync status aria-label.
+  }
 };
 
 /**
diff --git a/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.cc b/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.cc
index 39e5598..2c39409 100644
--- a/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.cc
+++ b/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.cc
@@ -30,7 +30,8 @@
     uint32_t name,
     const std::string& interface,
     uint32_t version) {
-  DCHECK_EQ(interface, kInterfaceName);
+  CHECK_EQ(interface, kInterfaceName) << "Expected \"" << kInterfaceName
+                                      << "\" but got \"" << interface << "\"";
 
   if (connection->gtk_primary_selection_device_manager() ||
       !wl::CanBind(interface, version, kMinVersion, kMinVersion)) {
diff --git a/ui/ozone/platform/wayland/host/gtk_shell1.cc b/ui/ozone/platform/wayland/host/gtk_shell1.cc
index cf8812f..041c71b 100644
--- a/ui/ozone/platform/wayland/host/gtk_shell1.cc
+++ b/ui/ozone/platform/wayland/host/gtk_shell1.cc
@@ -30,7 +30,8 @@
                             uint32_t name,
                             const std::string& interface,
                             uint32_t version) {
-  DCHECK_EQ(interface, kInterfaceName);
+  CHECK_EQ(interface, kInterfaceName) << "Expected \"" << kInterfaceName
+                                      << "\" but got \"" << interface << "\"";
 
   if (connection->gtk_shell1_ ||
       !wl::CanBind(interface, version, kMinVersion, kMaxVersion)) {
diff --git a/ui/ozone/platform/wayland/host/org_kde_kwin_idle.cc b/ui/ozone/platform/wayland/host/org_kde_kwin_idle.cc
index 011a5f38..2fcd249 100644
--- a/ui/ozone/platform/wayland/host/org_kde_kwin_idle.cc
+++ b/ui/ozone/platform/wayland/host/org_kde_kwin_idle.cc
@@ -57,7 +57,8 @@
                                  uint32_t name,
                                  const std::string& interface,
                                  uint32_t version) {
-  DCHECK_EQ(interface, kInterfaceName);
+  CHECK_EQ(interface, kInterfaceName) << "Expected \"" << kInterfaceName
+                                      << "\" but got \"" << interface << "\"";
 
   if (connection->org_kde_kwin_idle_ ||
       !wl::CanBind(interface, version, kMinVersion, kMinVersion)) {
diff --git a/ui/ozone/platform/wayland/host/overlay_prioritizer.cc b/ui/ozone/platform/wayland/host/overlay_prioritizer.cc
index 15026fe..562ed89 100644
--- a/ui/ozone/platform/wayland/host/overlay_prioritizer.cc
+++ b/ui/ozone/platform/wayland/host/overlay_prioritizer.cc
@@ -24,7 +24,8 @@
                                      uint32_t name,
                                      const std::string& interface,
                                      uint32_t version) {
-  DCHECK_EQ(interface, kInterfaceName);
+  CHECK_EQ(interface, kInterfaceName) << "Expected \"" << kInterfaceName
+                                      << "\" but got \"" << interface << "\"";
 
   if (connection->overlay_prioritizer_ ||
       !wl::CanBind(interface, version, kMinVersion, kMinVersion)) {
diff --git a/ui/ozone/platform/wayland/host/proxy/wayland_proxy_impl.cc b/ui/ozone/platform/wayland/host/proxy/wayland_proxy_impl.cc
index 49f10285..dee90b1a 100644
--- a/ui/ozone/platform/wayland/host/proxy/wayland_proxy_impl.cc
+++ b/ui/ozone/platform/wayland/host/proxy/wayland_proxy_impl.cc
@@ -27,7 +27,7 @@
   delegate_ = delegate;
   if (delegate_)
     connection_->wayland_window_manager()->AddObserver(this);
-  else if (!delegate_)
+  else
     connection_->wayland_window_manager()->RemoveObserver(this);
 }
 
diff --git a/ui/ozone/platform/wayland/host/surface_augmenter.cc b/ui/ozone/platform/wayland/host/surface_augmenter.cc
index 9e07db92..a7769414 100644
--- a/ui/ozone/platform/wayland/host/surface_augmenter.cc
+++ b/ui/ozone/platform/wayland/host/surface_augmenter.cc
@@ -27,7 +27,8 @@
                                    uint32_t name,
                                    const std::string& interface,
                                    uint32_t version) {
-  DCHECK_EQ(interface, kInterfaceName);
+  CHECK_EQ(interface, kInterfaceName) << "Expected \"" << kInterfaceName
+                                      << "\" but got \"" << interface << "\"";
 
   if (connection->surface_augmenter_ ||
       !wl::CanBind(interface, version, kMinVersion, kMaxVersion)) {
diff --git a/ui/ozone/platform/wayland/host/wayland_connection.cc b/ui/ozone/platform/wayland/host/wayland_connection.cc
index 48942eb..9b364791 100644
--- a/ui/ozone/platform/wayland/host/wayland_connection.cc
+++ b/ui/ozone/platform/wayland/host/wayland_connection.cc
@@ -340,7 +340,8 @@
 void WaylandConnection::RegisterGlobalObjectFactory(
     const char* interface_name,
     wl::GlobalObjectFactory factory) {
-  DCHECK_EQ(global_object_factories_.count(interface_name), 0U);
+  // If we get duplicate interface names, something is seriously wrong.
+  CHECK_EQ(global_object_factories_.count(interface_name), 0U);
 
   global_object_factories_[interface_name] = factory;
 }
diff --git a/ui/ozone/platform/wayland/host/wayland_data_device_manager.cc b/ui/ozone/platform/wayland/host/wayland_data_device_manager.cc
index 5f54830..a4cbec2f 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_device_manager.cc
+++ b/ui/ozone/platform/wayland/host/wayland_data_device_manager.cc
@@ -28,7 +28,8 @@
                                            uint32_t name,
                                            const std::string& interface,
                                            uint32_t version) {
-  DCHECK_EQ(interface, kInterfaceName);
+  CHECK_EQ(interface, kInterfaceName) << "Expected \"" << kInterfaceName
+                                      << "\" but got \"" << interface << "\"";
 
   if (connection->data_device_manager_ ||
       !wl::CanBind(interface, version, kMinVersion, kMaxVersion)) {
diff --git a/ui/ozone/platform/wayland/host/wayland_drm.cc b/ui/ozone/platform/wayland/host/wayland_drm.cc
index 6b8f0c0e..7edc0da 100644
--- a/ui/ozone/platform/wayland/host/wayland_drm.cc
+++ b/ui/ozone/platform/wayland/host/wayland_drm.cc
@@ -30,7 +30,8 @@
                              uint32_t name,
                              const std::string& interface,
                              uint32_t version) {
-  DCHECK_EQ(interface, kInterfaceName);
+  CHECK_EQ(interface, kInterfaceName) << "Expected \"" << kInterfaceName
+                                      << "\" but got \"" << interface << "\"";
 
   auto* buffer_factory = connection->wayland_buffer_factory();
   if (buffer_factory->wayland_drm_ ||
diff --git a/ui/ozone/platform/wayland/host/wayland_output.cc b/ui/ozone/platform/wayland/host/wayland_output.cc
index 436ddc9b..4719f2d 100644
--- a/ui/ozone/platform/wayland/host/wayland_output.cc
+++ b/ui/ozone/platform/wayland/host/wayland_output.cc
@@ -40,7 +40,8 @@
                                 uint32_t name,
                                 const std::string& interface,
                                 uint32_t version) {
-  DCHECK_EQ(interface, kInterfaceName);
+  CHECK_EQ(interface, kInterfaceName) << "Expected \"" << kInterfaceName
+                                      << "\" but got \"" << interface << "\"";
 
   if (!wl::CanBind(interface, version, kMinVersion, kMaxVersion)) {
     return;
diff --git a/ui/ozone/platform/wayland/host/wayland_seat.cc b/ui/ozone/platform/wayland/host/wayland_seat.cc
index f0e0b23..7720fbb5 100644
--- a/ui/ozone/platform/wayland/host/wayland_seat.cc
+++ b/ui/ozone/platform/wayland/host/wayland_seat.cc
@@ -30,7 +30,8 @@
                               uint32_t name,
                               const std::string& interface,
                               uint32_t version) {
-  DCHECK_EQ(interface, kInterfaceName);
+  CHECK_EQ(interface, kInterfaceName) << "Expected \"" << kInterfaceName
+                                      << "\" but got \"" << interface << "\"";
 
   if (connection->seat_ ||
       !wl::CanBind(interface, version, kMinVersion, kMaxVersion)) {
diff --git a/ui/ozone/platform/wayland/host/wayland_shm.cc b/ui/ozone/platform/wayland/host/wayland_shm.cc
index 14920a5..80d27227 100644
--- a/ui/ozone/platform/wayland/host/wayland_shm.cc
+++ b/ui/ozone/platform/wayland/host/wayland_shm.cc
@@ -23,7 +23,8 @@
                              uint32_t name,
                              const std::string& interface,
                              uint32_t version) {
-  DCHECK_EQ(interface, kInterfaceName);
+  CHECK_EQ(interface, kInterfaceName) << "Expected \"" << kInterfaceName
+                                      << "\" but got \"" << interface << "\"";
 
   auto* buffer_factory = connection->wayland_buffer_factory();
   if (buffer_factory->wayland_shm_ ||
diff --git a/ui/ozone/platform/wayland/host/wayland_zaura_shell.cc b/ui/ozone/platform/wayland/host/wayland_zaura_shell.cc
index e9bae3403..f6bbf17 100644
--- a/ui/ozone/platform/wayland/host/wayland_zaura_shell.cc
+++ b/ui/ozone/platform/wayland/host/wayland_zaura_shell.cc
@@ -32,7 +32,8 @@
                                     uint32_t name,
                                     const std::string& interface,
                                     uint32_t version) {
-  DCHECK_EQ(interface, kInterfaceName);
+  CHECK_EQ(interface, kInterfaceName) << "Expected \"" << kInterfaceName
+                                      << "\" but got \"" << interface << "\"";
 
   if (connection->zaura_shell_ ||
       !wl::CanBind(interface, version, kMinVersion, kMaxVersion)) {
diff --git a/ui/ozone/platform/wayland/host/wayland_zcr_color_manager.cc b/ui/ozone/platform/wayland/host/wayland_zcr_color_manager.cc
index 66013fc9..7a94db4e 100644
--- a/ui/ozone/platform/wayland/host/wayland_zcr_color_manager.cc
+++ b/ui/ozone/platform/wayland/host/wayland_zcr_color_manager.cc
@@ -34,7 +34,8 @@
                                          uint32_t name,
                                          const std::string& interface,
                                          uint32_t version) {
-  DCHECK_EQ(interface, kInterfaceName);
+  CHECK_EQ(interface, kInterfaceName) << "Expected \"" << kInterfaceName
+                                      << "\" but got \"" << interface << "\"";
   if (connection->zcr_color_manager_)
     return;
 
diff --git a/ui/ozone/platform/wayland/host/wayland_zcr_cursor_shapes.cc b/ui/ozone/platform/wayland/host/wayland_zcr_cursor_shapes.cc
index f8ddea7..9e3243d 100644
--- a/ui/ozone/platform/wayland/host/wayland_zcr_cursor_shapes.cc
+++ b/ui/ozone/platform/wayland/host/wayland_zcr_cursor_shapes.cc
@@ -31,7 +31,8 @@
                                          uint32_t name,
                                          const std::string& interface,
                                          uint32_t version) {
-  DCHECK_EQ(interface, kInterfaceName);
+  CHECK_EQ(interface, kInterfaceName) << "Expected \"" << kInterfaceName
+                                      << "\" but got \"" << interface << "\"";
 
   if (connection->zcr_cursor_shapes_ ||
       !wl::CanBind(interface, version, kMinVersion, kMinVersion)) {
diff --git a/ui/ozone/platform/wayland/host/wayland_zcr_touchpad_haptics.cc b/ui/ozone/platform/wayland/host/wayland_zcr_touchpad_haptics.cc
index 74c3579..6a8deb5 100644
--- a/ui/ozone/platform/wayland/host/wayland_zcr_touchpad_haptics.cc
+++ b/ui/ozone/platform/wayland/host/wayland_zcr_touchpad_haptics.cc
@@ -24,7 +24,8 @@
                                             uint32_t name,
                                             const std::string& interface,
                                             uint32_t version) {
-  DCHECK_EQ(interface, kInterfaceName);
+  CHECK_EQ(interface, kInterfaceName) << "Expected \"" << kInterfaceName
+                                      << "\" but got \"" << interface << "\"";
 
   if (connection->zcr_touchpad_haptics_ ||
       !wl::CanBind(interface, version, kMinVersion, kMinVersion)) {
diff --git a/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.cc b/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.cc
index 109e017..3db8cb5 100644
--- a/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.cc
+++ b/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.cc
@@ -29,7 +29,8 @@
                                         uint32_t name,
                                         const std::string& interface,
                                         uint32_t version) {
-  DCHECK_EQ(interface, kInterfaceName);
+  CHECK_EQ(interface, kInterfaceName) << "Expected \"" << kInterfaceName
+                                      << "\" but got \"" << interface << "\"";
   auto* buffer_factory = connection->wayland_buffer_factory();
   if (buffer_factory->wayland_zwp_dmabuf_ ||
       !wl::CanBind(interface, version, kMinVersion, kMaxVersion)) {
diff --git a/ui/ozone/platform/wayland/host/wayland_zwp_pointer_constraints.cc b/ui/ozone/platform/wayland/host/wayland_zwp_pointer_constraints.cc
index 97c40f0..5a01a54 100644
--- a/ui/ozone/platform/wayland/host/wayland_zwp_pointer_constraints.cc
+++ b/ui/ozone/platform/wayland/host/wayland_zwp_pointer_constraints.cc
@@ -28,7 +28,8 @@
                                                uint32_t name,
                                                const std::string& interface,
                                                uint32_t version) {
-  DCHECK_EQ(interface, kInterfaceName);
+  CHECK_EQ(interface, kInterfaceName) << "Expected \"" << kInterfaceName
+                                      << "\" but got \"" << interface << "\"";
 
   if (connection->wayland_zwp_pointer_constraints_ ||
       !wl::CanBind(interface, version, kMinVersion, kMinVersion)) {
diff --git a/ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures.cc b/ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures.cc
index 89e4b5bc..fc3fe56 100644
--- a/ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures.cc
+++ b/ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures.cc
@@ -33,7 +33,8 @@
                                             uint32_t name,
                                             const std::string& interface,
                                             uint32_t version) {
-  DCHECK_EQ(interface, kInterfaceName);
+  CHECK_EQ(interface, kInterfaceName) << "Expected \"" << kInterfaceName
+                                      << "\" but got \"" << interface << "\"";
 
   if (connection->wayland_zwp_pointer_gestures_ ||
       !wl::CanBind(interface, version, kMinVersion, kMinVersion)) {
diff --git a/ui/ozone/platform/wayland/host/wayland_zwp_relative_pointer_manager.cc b/ui/ozone/platform/wayland/host/wayland_zwp_relative_pointer_manager.cc
index afb3005..17a6543 100644
--- a/ui/ozone/platform/wayland/host/wayland_zwp_relative_pointer_manager.cc
+++ b/ui/ozone/platform/wayland/host/wayland_zwp_relative_pointer_manager.cc
@@ -28,7 +28,8 @@
     uint32_t name,
     const std::string& interface,
     uint32_t version) {
-  DCHECK_EQ(interface, kInterfaceName);
+  CHECK_EQ(interface, kInterfaceName) << "Expected \"" << kInterfaceName
+                                      << "\" but got \"" << interface << "\"";
 
   if (connection->wayland_zwp_relative_pointer_manager_ ||
       !wl::CanBind(interface, version, kMinVersion, kMinVersion)) {
diff --git a/ui/ozone/platform/wayland/host/xdg_activation.cc b/ui/ozone/platform/wayland/host/xdg_activation.cc
index b9d39f2..3385758 100644
--- a/ui/ozone/platform/wayland/host/xdg_activation.cc
+++ b/ui/ozone/platform/wayland/host/xdg_activation.cc
@@ -56,7 +56,8 @@
                                 uint32_t name,
                                 const std::string& interface,
                                 uint32_t version) {
-  DCHECK_EQ(interface, kInterfaceName);
+  CHECK_EQ(interface, kInterfaceName) << "Expected \"" << kInterfaceName
+                                      << "\" but got \"" << interface << "\"";
 
   if (connection->xdg_activation_)
     return;
diff --git a/ui/ozone/platform/wayland/host/zwp_idle_inhibit_manager.cc b/ui/ozone/platform/wayland/host/zwp_idle_inhibit_manager.cc
index 4045ec3..4ca26f5 100644
--- a/ui/ozone/platform/wayland/host/zwp_idle_inhibit_manager.cc
+++ b/ui/ozone/platform/wayland/host/zwp_idle_inhibit_manager.cc
@@ -24,7 +24,8 @@
                                         uint32_t name,
                                         const std::string& interface,
                                         uint32_t version) {
-  DCHECK_EQ(interface, kInterfaceName);
+  CHECK_EQ(interface, kInterfaceName) << "Expected \"" << kInterfaceName
+                                      << "\" but got \"" << interface << "\"";
 
   if (connection->zwp_idle_inhibit_manager_ ||
       !wl::CanBind(interface, version, kMinVersion, kMinVersion)) {
diff --git a/ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.cc b/ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.cc
index 85768d7..9d5d796 100644
--- a/ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.cc
+++ b/ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.cc
@@ -30,7 +30,8 @@
     uint32_t name,
     const std::string& interface,
     uint32_t version) {
-  DCHECK_EQ(interface, kInterfaceName);
+  CHECK_EQ(interface, kInterfaceName) << "Expected \"" << kInterfaceName
+                                      << "\" but got \"" << interface << "\"";
 
   if (connection->zwp_primary_selection_device_manager_ ||
       !wl::CanBind(interface, version, kMinVersion, kMinVersion)) {
diff --git a/ui/webui/resources/cr_elements/cr_auto_img/cr_auto_img.ts b/ui/webui/resources/cr_elements/cr_auto_img/cr_auto_img.ts
index e33d41d5..7df8e50 100644
--- a/ui/webui/resources/cr_elements/cr_auto_img/cr_auto_img.ts
+++ b/ui/webui/resources/cr_elements/cr_auto_img/cr_auto_img.ts
@@ -27,6 +27,12 @@
  *
  *      <img is="cr-auto-img" auto-src="[[calculateSrc()]]" clear-src>
  *
+ *      If you want your image to be always encoded as static PNG image (even if
+ *      the source image is animated), set the static-encode attribute:
+ *
+ *      <img is="cr-auto-img" auto-src="https://foo.com/bar.png"
+ *          static-encode>
+ *
  * NOTE: Since <cr-auto-img> may use the chrome://image data source some images
  * may be transcoded to PNG.
  */
@@ -37,14 +43,17 @@
 
 const IS_GOOGLE_PHOTOS: string = 'is-google-photos';
 
+const STATIC_ENCODE: string = 'static-encode';
+
 export class CrAutoImgElement extends HTMLImageElement {
   static get observedAttributes() {
-    return [AUTO_SRC, IS_GOOGLE_PHOTOS];
+    return [AUTO_SRC, IS_GOOGLE_PHOTOS, STATIC_ENCODE];
   }
 
   attributeChangedCallback(
       name: string, oldValue: string|null, newValue: string|null) {
-    if (name !== AUTO_SRC && name !== IS_GOOGLE_PHOTOS) {
+    if (name !== AUTO_SRC && name !== IS_GOOGLE_PHOTOS &&
+        name !== STATIC_ENCODE) {
       return;
     }
 
@@ -72,13 +81,24 @@
       // Loading chrome-untrusted:// via the chrome://image data source
       // results in a broken image.
       this.removeAttribute('src');
-    } else if (url.protocol === 'data:' || url.protocol === 'chrome:') {
+      return;
+    }
+    if (url.protocol === 'data:' || url.protocol === 'chrome:') {
       this.src = url.href;
-    } else if (this.hasAttribute(IS_GOOGLE_PHOTOS)) {
-      this.src = `chrome://image?url=${
-          encodeURIComponent(url.href)}&isGooglePhotos=true`;
-    } else {
+      return;
+    }
+    if (!this.hasAttribute(IS_GOOGLE_PHOTOS) &&
+        !this.hasAttribute(STATIC_ENCODE)) {
       this.src = 'chrome://image?' + url.href;
+      return;
+    }
+
+    this.src = `chrome://image?url=${encodeURIComponent(url.href)}`;
+    if (this.hasAttribute(IS_GOOGLE_PHOTOS)) {
+      this.src += `&isGooglePhotos=true`;
+    }
+    if (this.hasAttribute(STATIC_ENCODE)) {
+      this.src += `&staticEncode=true`;
     }
   }
 
@@ -109,6 +129,18 @@
   get isGooglePhotos(): boolean {
     return this.hasAttribute(IS_GOOGLE_PHOTOS);
   }
+
+  set staticEncode(enabled: boolean) {
+    if (enabled) {
+      this.setAttribute(STATIC_ENCODE, '');
+    } else {
+      this.removeAttribute(STATIC_ENCODE);
+    }
+  }
+
+  get staticEncode(): boolean {
+    return this.hasAttribute(STATIC_ENCODE);
+  }
 }
 
 customElements.define('cr-auto-img', CrAutoImgElement, {extends: 'img'});