diff --git a/DEPS b/DEPS
index 86037fe..ab830d5e 100644
--- a/DEPS
+++ b/DEPS
@@ -311,15 +311,15 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '351f2b691639284c49915ae31f7fcc8cae7bda4f',
+  'skia_revision': 'e96cb91c730324d81e4600de0bcbb3e1d133040f',
   # 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': '08b9a2279b351b5f8ae0f4de8c8194d62e245883',
+  'v8_revision': '07c1bc654d188fffeda01d5d50ac7a93c8e1f961',
   # 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': '122b292d96c923b67ca3065c89d90714daec46f6',
+  'angle_revision': '0e3d200d9caed5306dd74afdfe0f78152af8b01e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -327,7 +327,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '70c2db3e99bf97e1afbcd22ca37ef3b5ed101a51',
+  'pdfium_revision': '21ac43e7fb73582dec513672d8a6c5f3908d441b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -398,7 +398,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': 'f74ead4522edc13813e53493f8b6712d793855ee',
+  'devtools_frontend_revision': '5d1603a5d2e4bfb95aedc71298d7f4bccb45b891',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -438,7 +438,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': 'ed70ac0399fc13caf9cc63b9e3d1c0e975c37b51',
+  'dawn_revision': 'b5879ac034aff8319e34c3645280bcf242cff6ac',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -478,7 +478,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.
-  'cros_components_revision': 'fb81e965fbaabf2be1475a180630a011b0e21d3e',
+  'cros_components_revision': 'f47d8a6a115863f55f529e04b6302186a0df46b0',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -818,7 +818,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    'f92a3dbb19f1b2e7eba93fa66743dcdc48fdd08e',
+    '14e0cef4d2c104adb11da44c94e43ce8d9311b84',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -847,7 +847,7 @@
   },
 
   'src/ios/third_party/material_components_ios/src': {
-      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '63cfd8c6b21176aa594ca8bb5f3aa602b1e6ed52',
+      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '973011dd3df68bdea2076cd45610f756ce89920f',
       'condition': 'checkout_ios',
   },
 
@@ -1013,7 +1013,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'ev8uu14lKo-cysFlhDbKbHdTNEQ8izE37c55Wv_EUJUC',
+          'version': 'v8JL3E5KtNlFmho-mGQhRh5dg4wY33bqvymlJ0MKCdoC',
       },
     ],
     'condition': 'checkout_android',
@@ -1254,13 +1254,13 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'c5305b39f473d64ddcb313a22584e22666b1da3b',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'f0fba1d307d511620e29c9d2b623abc6904e794c',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
 
   'src/third_party/devtools-frontend-internal': {
-      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + 'e07d8560b78c6bdc967960c66d6452e9f89e2199',
+      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + 'a5e5af40f7f1fc0a8fa577a9292609967326d045',
     'condition': 'checkout_src_internal',
   },
 
@@ -1730,7 +1730,7 @@
     Var('pdfium_git') + '/pdfium.git' + '@' +  Var('pdfium_revision'),
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '442335b6aee106bc7cc024f2d85dd5cf03dec521',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '92e38d71f075f5cd47e3703b2dcb7dbb911266af',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1915,7 +1915,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '086261bcd213f8ae6f57ebdc293283ed6262097d',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '0c1c7221853b34f3d407dc698c01ad30dbb4e635',
+    Var('webrtc_git') + '/src.git' + '@' + '365a5717ae0defda2ec179c866290801543b0307',
 
   # 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.
@@ -2073,7 +2073,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/projector_app/app',
-        'version': '_0am1HjNwAk_RDqQX1o-8LkhW0DIRg8ckRZZLPjwU38C',
+        'version': 'wDBCXbtdye0P5nlGPv81QMzHC8EHsQWC2vYdYqxICJ8C',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -4204,7 +4204,7 @@
 
   'src/ios_internal':  {
       'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' +
-        'f9a4ee0b40a5bfd8db3dcc29f53527d0d1c72973',
+        '25494ef1cc0dff02b43c08dae16318fb403797a5',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
diff --git a/ash/components/arc/compat_mode/resize_confirmation_dialog_view.cc b/ash/components/arc/compat_mode/resize_confirmation_dialog_view.cc
index dc39646e..7cdfca5 100644
--- a/ash/components/arc/compat_mode/resize_confirmation_dialog_view.cc
+++ b/ash/components/arc/compat_mode/resize_confirmation_dialog_view.cc
@@ -30,6 +30,14 @@
 
 namespace arc {
 
+void ResizeConfirmationDialogView::TestApi::SelectDoNotAskCheckbox() {
+  if (chromeos::features::IsJellyEnabled()) {
+    view_->do_not_ask_checkbox_jelly_->SetSelected(true);
+  } else {
+    view_->do_not_ask_checkbox_->SetChecked(true);
+  }
+}
+
 ResizeConfirmationDialogView::ResizeConfirmationDialogView(
     ResizeConfirmationCallback callback)
     : callback_(std::move(callback)) {
diff --git a/ash/components/arc/compat_mode/resize_confirmation_dialog_view.h b/ash/components/arc/compat_mode/resize_confirmation_dialog_view.h
index 7ba1ccc8f..d5ac6d5 100644
--- a/ash/components/arc/compat_mode/resize_confirmation_dialog_view.h
+++ b/ash/components/arc/compat_mode/resize_confirmation_dialog_view.h
@@ -40,9 +40,7 @@
 
     views::LabelButton* accept_button() const { return view_->accept_button_; }
     views::LabelButton* cancel_button() const { return view_->cancel_button_; }
-    views::Checkbox* do_not_ask_checkbox() const {
-      return view_->do_not_ask_checkbox_;
-    }
+    void SelectDoNotAskCheckbox();
 
    private:
     const raw_ptr<ResizeConfirmationDialogView, ExperimentalAsh> view_;
diff --git a/ash/components/arc/compat_mode/resize_confirmation_dialog_view_unittest.cc b/ash/components/arc/compat_mode/resize_confirmation_dialog_view_unittest.cc
index 7c69df7..26bfd7a8 100644
--- a/ash/components/arc/compat_mode/resize_confirmation_dialog_view_unittest.cc
+++ b/ash/components/arc/compat_mode/resize_confirmation_dialog_view_unittest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "ash/components/arc/compat_mode/test/compat_mode_test_base.h"
+#include "ash/style/ash_color_provider.h"
 #include "base/functional/bind.h"
 #include "base/memory/raw_ptr.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -40,8 +41,9 @@
  protected:
   void ClickDialogButton(bool accept, bool with_checkbox) {
     ResizeConfirmationDialogView::TestApi dialog_view_test(dialog_view_);
-    if (with_checkbox)
-      dialog_view_test.do_not_ask_checkbox()->SetChecked(true);
+    if (with_checkbox) {
+      dialog_view_test.SelectDoNotAskCheckbox();
+    }
 
     auto* target_button = accept ? dialog_view_test.accept_button()
                                  : dialog_view_test.cancel_button();
@@ -68,6 +70,9 @@
   // A LayoutProvider must exist in scope in order to set up views.
   views::LayoutProvider layout_provider;
 
+  // An AshColorProvider must exist in scope in order to set up views.
+  ash::AshColorProvider ash_color_provider_;
+
   raw_ptr<ResizeConfirmationDialogView, ExperimentalAsh> dialog_view_;
   std::unique_ptr<views::Widget> widget_;
 };
diff --git a/ash/fast_ink/fast_ink_host_frame_utils_unittest.cc b/ash/fast_ink/fast_ink_host_frame_utils_unittest.cc
index 17bcb76..2b809f4 100644
--- a/ash/fast_ink/fast_ink_host_frame_utils_unittest.cc
+++ b/ash/fast_ink/fast_ink_host_frame_utils_unittest.cc
@@ -18,7 +18,6 @@
 #include "components/viz/common/quads/compositor_frame.h"
 #include "components/viz/common/quads/texture_draw_quad.h"
 #include "components/viz/common/resources/resource_format.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/resource_id.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/ash/fast_ink/fast_ink_host_unittest.cc b/ash/fast_ink/fast_ink_host_unittest.cc
index 36b9243..242763de 100644
--- a/ash/fast_ink/fast_ink_host_unittest.cc
+++ b/ash/fast_ink/fast_ink_host_unittest.cc
@@ -21,7 +21,6 @@
 #include "components/viz/common/quads/compositor_frame.h"
 #include "components/viz/common/quads/compositor_render_pass.h"
 #include "components/viz/common/quads/texture_draw_quad.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/resource_id.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/aura/window.h"
diff --git a/ash/fast_ink/view_tree_host_root_view_frame_factory.cc b/ash/fast_ink/view_tree_host_root_view_frame_factory.cc
index f15b0a9..c5577c96 100644
--- a/ash/fast_ink/view_tree_host_root_view_frame_factory.cc
+++ b/ash/fast_ink/view_tree_host_root_view_frame_factory.cc
@@ -13,7 +13,6 @@
 #include "components/viz/common/gpu/context_provider.h"
 #include "components/viz/common/quads/compositor_frame.h"
 #include "components/viz/common/quads/texture_draw_quad.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/resource_id.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
diff --git a/ash/login/README.md b/ash/login/README.md
new file mode 100644
index 0000000..fce4aac
--- /dev/null
+++ b/ash/login/README.md
@@ -0,0 +1,38 @@
+# Entities used on the login/lock screen
+
+The main entities used to show the login/lock screen UI.
+
+- `//ash/public/cpp/`:
+  - This folder contains inferfaces that are implemented in ash or chrome and
+are used to communicate between ash and chrome services.
+  - [`LoginScreenClient`](/ash/public/cpp/login_screen_client.h) - handles
+method calls sent from ash to chrome & handles messages from chrome to ash.
+Forwards some of the calls to the `Delegate`.
+
+- `//chrome/browser/ash/login/ui/`:
+  - This folder contains implementations of login and OOBE UIs.
+  - [`LoginDisplayHostMojo`](/chrome/browser/ash/login/ui/
+login_display_host_mojo.h) - a `LoginDisplayHost` instance that implements
+`LoginScreenClient` and sends requests to the views-based sign in. Handles calls
+like `HandleAuthenticateUserWith...()`. Owned by
+`ChromeBrowserMainExtraPartsAsh`.
+
+- `//ash/login/`:
+  - This folder contains the implementation of login UI views (buttons, inputs,
+etc), and additional classes that handle notifications and update the UI. Also
+see [ash/login/ui/README.md](/ash/login/ui/README.md)
+  - [`LoginScreenController`](/ash/login/login_screen_controller.h) - mostly
+forwards requests to `LoginScreenClient` or calls `Shelf` APIs directly. Owned
+by `Shell`.
+  - [`LoginDataDispatcher`](/ash/login/ui/login_data_dispatcher.h) - provides
+access to data notification events needed by the lock/login screen (via the
+observer). Owned by `LoginScreenController`.
+  - [`LockContentsView`](/ash/login/ui/lock_contents_view.h) - hosts the root
+view for the login/lock screen. Receives notifications from the
+`LoginDataDispatcher` and updates the UI. Owned by `LockScreen`.
+
+- `//chrome/browser/ash/login/lock/`:
+  - This folder contains the lock screen - specific logic for the login UIs.
+  - [`ViewsScreenLocker`](/chrome/browser/ash/login/lock/views_screen_locker.h)
+handles calls between ash and chrome on the lock screen by implementing
+Delegate interfaces.
diff --git a/ash/rounded_display/rounded_display_frame_factory.cc b/ash/rounded_display/rounded_display_frame_factory.cc
index 0b3940b..020e093 100644
--- a/ash/rounded_display/rounded_display_frame_factory.cc
+++ b/ash/rounded_display/rounded_display_frame_factory.cc
@@ -18,7 +18,6 @@
 #include "components/viz/common/quads/compositor_frame.h"
 #include "components/viz/common/quads/texture_draw_quad.h"
 #include "components/viz/common/resources/resource_format.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/resource_id.h"
 #include "components/viz/common/resources/shared_image_format.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
diff --git a/ash/webui/camera_app_ui/camera_app_ui.cc b/ash/webui/camera_app_ui/camera_app_ui.cc
index 025870e4..22c7dff5f 100644
--- a/ash/webui/camera_app_ui/camera_app_ui.cc
+++ b/ash/webui/camera_app_ui/camera_app_ui.cc
@@ -19,7 +19,6 @@
 #include "components/arc/intent_helper/arc_intent_helper_bridge.h"
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "components/media_device_salt/media_device_salt_service.h"
-#include "components/media_device_salt/media_device_salt_service_factory.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/devtools_agent_host.h"
@@ -140,14 +139,19 @@
 // Translates the renderer-side source ID to video device id.
 void TranslateVideoDeviceId(
     content::BrowserContext* browser_context,
+    media_device_salt::MediaDeviceSaltService* salt_service,
     const url::Origin& origin,
     const std::string& source_id,
     base::OnceCallback<void(const absl::optional<std::string>&)> callback) {
-  media_device_salt::MediaDeviceSaltService* salt_service =
-      media_device_salt::MediaDeviceSaltServiceFactory::GetInstance()
-          ->GetForBrowserContext(browser_context);
-  salt_service->GetSalt(
-      base::BindOnce(&GotSalt, origin, source_id, std::move(callback)));
+  if (salt_service) {
+    salt_service->GetSalt(
+        base::BindOnce(&GotSalt, origin, source_id, std::move(callback)));
+  } else {
+    // If the embedder does not provide a salt service, use the browser
+    // context's unique ID as salt.
+    GotSalt(origin, source_id, std::move(callback),
+            browser_context->UniqueId());
+  }
 }
 
 void HandleCameraResult(
@@ -171,8 +175,10 @@
 }
 
 std::unique_ptr<media::CameraAppDeviceProviderImpl>
-CreateCameraAppDeviceProvider(const url::Origin& security_origin,
-                              content::BrowserContext* context) {
+CreateCameraAppDeviceProvider(
+    content::BrowserContext* browser_context,
+    media_device_salt::MediaDeviceSaltService* salt_service,
+    const url::Origin& security_origin) {
   mojo::PendingRemote<cros::mojom::CameraAppDeviceBridge> device_bridge;
   auto device_bridge_receiver = device_bridge.InitWithNewPipeAndPassReceiver();
 
@@ -180,8 +186,9 @@
   content::GetVideoCaptureService().ConnectToCameraAppDeviceBridge(
       std::move(device_bridge_receiver));
 
-  auto mapping_callback = base::BindRepeating(&TranslateVideoDeviceId, context,
-                                              std::move(security_origin));
+  auto mapping_callback =
+      base::BindRepeating(&TranslateVideoDeviceId, browser_context,
+                          salt_service, std::move(security_origin));
 
   return std::make_unique<media::CameraAppDeviceProviderImpl>(
       std::move(device_bridge), std::move(mapping_callback));
@@ -275,9 +282,11 @@
 
 void CameraAppUI::BindInterface(
     mojo::PendingReceiver<cros::mojom::CameraAppDeviceProvider> receiver) {
+  content::BrowserContext* browser_context =
+      web_ui()->GetWebContents()->GetBrowserContext();
   provider_ = CreateCameraAppDeviceProvider(
-      url::Origin::Create(GURL(kChromeUICameraAppURL)),
-      web_ui()->GetWebContents()->GetBrowserContext());
+      browser_context, delegate_->GetMediaDeviceSaltService(browser_context),
+      url::Origin::Create(GURL(kChromeUICameraAppURL)));
   provider_->Bind(std::move(receiver));
 }
 
diff --git a/ash/webui/camera_app_ui/camera_app_ui_delegate.h b/ash/webui/camera_app_ui/camera_app_ui_delegate.h
index 29e9b06..4ac18c7 100644
--- a/ash/webui/camera_app_ui/camera_app_ui_delegate.h
+++ b/ash/webui/camera_app_ui/camera_app_ui_delegate.h
@@ -11,10 +11,15 @@
 #include "base/functional/callback.h"
 
 namespace content {
+class BrowserContext;
 class WebContents;
 class WebUIDataSource;
 }  // namespace content
 
+namespace media_device_salt {
+class MediaDeviceSaltService;
+}  // namespace media_device_salt
+
 namespace ash {
 class HoldingSpaceClient;
 
@@ -102,6 +107,11 @@
 
   // Gets the file path by given file |name|.
   virtual base::FilePath GetFilePathByName(const std::string& name) = 0;
+
+  // Returns a service that provides persistent salts for generating media
+  // device IDs. Can be null if the embedder does not support persistent salts.
+  virtual media_device_salt::MediaDeviceSaltService* GetMediaDeviceSaltService(
+      content::BrowserContext* context) = 0;
 };
 
 }  // namespace ash
diff --git a/ash/webui/camera_app_ui/resources/js/device/camera3_device_info.ts b/ash/webui/camera_app_ui/resources/js/device/camera3_device_info.ts
index c913106d..ca9ce57b 100644
--- a/ash/webui/camera_app_ui/resources/js/device/camera3_device_info.ts
+++ b/ash/webui/camera_app_ui/resources/js/device/camera3_device_info.ts
@@ -66,8 +66,12 @@
       readonly supportPTZ: boolean,
   ) {
     this.deviceId = deviceInfo.deviceId;
+    // If all fps supported by the camera is lower than 24, use the maximum
+    // supported fps.
+    const maxSupportedFps =
+        Math.max(...videoResolutionFpses.map(({maxFps}) => maxFps));
     for (const {width, height, maxFps} of videoResolutionFpses) {
-      if (maxFps < 24) {
+      if (maxFps < 24 && maxFps !== maxSupportedFps) {
         continue;
       }
       const r = new Resolution(width, height);
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 3d1ee55..359818f 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -229,7 +229,11 @@
     defines = [ "BASE_IMPLEMENTATION" ]
     configs += [ "//build/config/compiler:enable_arc" ]
     deps = [
-      "//base:base_static",
+      ":base_static",
+      ":debugging_buildflags",
+      ":logging_buildflags",
+      ":tracing_buildflags",
+      "//base/allocator/partition_allocator:buildflags",
       "//base/numerics:base_numerics",
       "//build:blink_buildflags",
       "//third_party/abseil-cpp:absl",
diff --git a/base/allocator/partition_allocator/pointers/raw_ptr.h b/base/allocator/partition_allocator/pointers/raw_ptr.h
index b035bfcdf..ece9b9b 100644
--- a/base/allocator/partition_allocator/pointers/raw_ptr.h
+++ b/base/allocator/partition_allocator/pointers/raw_ptr.h
@@ -1176,6 +1176,12 @@
 // This is not meant to be added manually. You can ignore this flag.
 constexpr auto FlakyDanglingUntriaged = base::RawPtrTraits::kMayDangle;
 
+// Dangling raw_ptr that is more likely to cause UAF: its memory was freed in
+// one task, and the raw_ptr was released in a different one.
+//
+// This is not meant to be added manually. You can ignore this flag.
+constexpr auto DanglingAcrossTasks = base::RawPtrTraits::kMayDangle;
+
 // The use of pointer arithmetic with raw_ptr is strongly discouraged and
 // disabled by default. Usually a container like span<> should be used
 // instead of the raw_ptr.
diff --git a/base/files/file_descriptor_watcher_posix.h b/base/files/file_descriptor_watcher_posix.h
index a252651d..ef4c26a 100644
--- a/base/files/file_descriptor_watcher_posix.h
+++ b/base/files/file_descriptor_watcher_posix.h
@@ -76,7 +76,7 @@
     // Controller is deleted, ownership of |watcher_| is transfered to a delete
     // task posted to the MessageLoopForIO. This ensures that |watcher_| isn't
     // deleted while it is being used by the MessageLoopForIO.
-    raw_ptr<Watcher, DanglingUntriaged> watcher_;
+    raw_ptr<Watcher, DanglingAcrossTasks> watcher_;
 
     // An event for the watcher to notify controller that it's destroyed.
     // As the |watcher_| is owned by Controller, always outlives the Watcher.
diff --git a/base/message_loop/message_pump_libevent.h b/base/message_loop/message_pump_libevent.h
index 0389de96..fc5881a1 100644
--- a/base/message_loop/message_pump_libevent.h
+++ b/base/message_loop/message_pump_libevent.h
@@ -93,7 +93,7 @@
     friend class RefCounted<EpollInterest>;
     ~EpollInterest();
 
-    const raw_ptr<FdWatchController, DanglingUntriaged> controller_;
+    const raw_ptr<FdWatchController, DanglingAcrossTasks> controller_;
     const EpollInterestParams params_;
     bool active_ = true;
     bool was_controller_destroyed_ = false;
diff --git a/base/observer_list_internal.h b/base/observer_list_internal.h
index fb903e8f..e17c311 100644
--- a/base/observer_list_internal.h
+++ b/base/observer_list_internal.h
@@ -54,7 +54,7 @@
 #endif  // DCHECK_IS_ON()
 
  private:
-  raw_ptr<void, DanglingUntriaged> ptr_;
+  raw_ptr<void, DanglingAcrossTasks> ptr_;
 #if DCHECK_IS_ON()
   base::debug::StackTrace stack_;
 #endif  // DCHECK_IS_ON()
diff --git a/base/synchronization/waitable_event_watcher.h b/base/synchronization/waitable_event_watcher.h
index 78617c5..d23f8850 100644
--- a/base/synchronization/waitable_event_watcher.h
+++ b/base/synchronization/waitable_event_watcher.h
@@ -144,7 +144,7 @@
   scoped_refptr<Flag> cancel_flag_;
 
   // Enqueued in the wait list of the watched WaitableEvent.
-  raw_ptr<AsyncWaiter, DanglingUntriaged> waiter_ = nullptr;
+  raw_ptr<AsyncWaiter, DanglingAcrossTasks> waiter_ = nullptr;
 
   // Kernel of the watched WaitableEvent.
   scoped_refptr<WaitableEvent::WaitableEventKernel> kernel_;
diff --git a/base/test/test_trace_processor.cc b/base/test/test_trace_processor.cc
index 0df3a536a..a9c64df3 100644
--- a/base/test/test_trace_processor.cc
+++ b/base/test/test_trace_processor.cc
@@ -8,32 +8,58 @@
 
 #if BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
 
+TraceConfig DefaultTraceConfig(const StringPiece& category_filter_string,
+                               bool privacy_filtering) {
+  TraceConfig trace_config;
+  auto* buffer_config = trace_config.add_buffers();
+  buffer_config->set_size_kb(4 * 1024);
+
+  auto* data_source = trace_config.add_data_sources();
+  auto* source_config = data_source->mutable_config();
+  source_config->set_name("track_event");
+  source_config->set_target_buffer(0);
+
+  perfetto::protos::gen::TrackEventConfig track_event_config;
+  base::trace_event::TraceConfigCategoryFilter category_filter;
+  category_filter.InitializeFromString(category_filter_string);
+
+  // If no categories are explicitly enabled, enable the default ones.
+  // Otherwise only matching categories are enabled.
+  if (!category_filter.included_categories().empty()) {
+    track_event_config.add_disabled_categories("*");
+  }
+  for (const auto& included_category : category_filter.included_categories()) {
+    track_event_config.add_enabled_categories(included_category);
+  }
+  for (const auto& disabled_category : category_filter.disabled_categories()) {
+    track_event_config.add_enabled_categories(disabled_category);
+  }
+  for (const auto& excluded_category : category_filter.excluded_categories()) {
+    track_event_config.add_disabled_categories(excluded_category);
+  }
+
+  source_config->set_track_event_config_raw(
+      track_event_config.SerializeAsString());
+
+  if (privacy_filtering) {
+    track_event_config.set_filter_debug_annotations(true);
+    track_event_config.set_filter_dynamic_event_names(true);
+  }
+
+  return trace_config;
+}
+
 TestTraceProcessor::TestTraceProcessor() = default;
 TestTraceProcessor::~TestTraceProcessor() = default;
 
-void TestTraceProcessor::StartTrace(const StringPiece& category_filter_string) {
-  session_ = perfetto::Tracing::NewTrace();
-  perfetto::protos::gen::TraceConfig config =
-      TracingEnvironment::GetDefaultTraceConfig();
-  for (auto& data_source : *config.mutable_data_sources()) {
-    perfetto::protos::gen::TrackEventConfig track_event_config;
-    base::trace_event::TraceConfigCategoryFilter category_filter;
-    category_filter.InitializeFromString(category_filter_string);
-    for (const auto& included_category :
-         category_filter.included_categories()) {
-      track_event_config.add_enabled_categories(included_category);
-    }
-    for (const auto& disabled_category :
-         category_filter.disabled_categories()) {
-      track_event_config.add_enabled_categories(disabled_category);
-    }
-    for (const auto& excluded_category :
-         category_filter.excluded_categories()) {
-      track_event_config.add_disabled_categories(excluded_category);
-    }
-    data_source.mutable_config()->set_track_event_config_raw(
-        track_event_config.SerializeAsString());
-  }
+void TestTraceProcessor::StartTrace(const StringPiece& category_filter_string,
+                                    bool privacy_filtering) {
+  StartTrace(DefaultTraceConfig(category_filter_string, privacy_filtering));
+}
+
+void TestTraceProcessor::StartTrace(const TraceConfig& config,
+                                    perfetto::BackendType backend) {
+  session_ = perfetto::Tracing::NewTrace(backend);
   session_->Setup(config);
   // Some tests run the tracing service on the main thread and StartBlocking()
   // can deadlock so use a RunLoop instead.
diff --git a/base/test/test_trace_processor.h b/base/test/test_trace_processor.h
index 343d607..88d7920 100644
--- a/base/test/test_trace_processor.h
+++ b/base/test/test_trace_processor.h
@@ -15,12 +15,15 @@
 #include "base/test/trace_test_utils.h"
 #include "base/types/expected.h"
 
-// TODO(rasikan): Put these functions in a class.
-
 namespace base::test {
 
 #if BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
 
+using perfetto::protos::gen::TraceConfig;
+
+TraceConfig DefaultTraceConfig(const StringPiece& category_filter_string,
+                               bool privacy_filtering);
+
 // Use TestTraceProcessor to record Perfetto traces in unit and browser tests.
 // This API can be used to start and stop traces, run SQL queries on the trace
 // and write expectations against the query result.
@@ -48,7 +51,11 @@
   TestTraceProcessor();
   ~TestTraceProcessor();
 
-  void StartTrace(const StringPiece& category_filter_string);
+  void StartTrace(const StringPiece& category_filter_string,
+                  bool privacy_filtering = false);
+  void StartTrace(
+      const TraceConfig& config,
+      perfetto::BackendType backend = perfetto::kUnspecifiedBackend);
 
   absl::Status StopAndParseTrace();
 
diff --git a/base/threading/sequence_bound_internal.h b/base/threading/sequence_bound_internal.h
index 0e4b37c..72f9aba5 100644
--- a/base/threading/sequence_bound_internal.h
+++ b/base/threading/sequence_bound_internal.h
@@ -150,7 +150,7 @@
   // Storage originally allocated by `AlignedAlloc()`. Maintained separately
   // from  `ptr_` since the original, unadjusted pointer needs to be passed to
   // `AlignedFree()`.
-  raw_ptr<void, DanglingUntriaged> alloc_ = nullptr;
+  raw_ptr<void, DanglingAcrossTasks> alloc_ = nullptr;
 };
 
 template <typename T, typename CrossThreadTraits>
diff --git a/base/values.cc b/base/values.cc
index 5f68e4a9..28c6f40 100644
--- a/base/values.cc
+++ b/base/values.cc
@@ -909,28 +909,20 @@
                         base::to_address(storage_.cend()));
 }
 
-// TODO(crbug.com/1446739): Implement reverse iterators in
-// CheckedContiguousIterator and use them here.
-std::vector<Value>::reverse_iterator Value::List::rend() {
-  return storage_.rend();
+Value::List::reverse_iterator Value::List::rend() {
+  return reverse_iterator(begin());
 }
 
-// TODO(crbug.com/1446739): Implement reverse iterators in
-// CheckedContiguousIterator and use them here.
-std::vector<Value>::const_reverse_iterator Value::List::rend() const {
-  return storage_.rend();
+Value::List::const_reverse_iterator Value::List::rend() const {
+  return const_reverse_iterator(begin());
 }
 
-// TODO(crbug.com/1446739): Implement reverse iterators in
-// CheckedContiguousIterator and use them here.
-std::vector<Value>::reverse_iterator Value::List::rbegin() {
-  return storage_.rbegin();
+Value::List::reverse_iterator Value::List::rbegin() {
+  return reverse_iterator(end());
 }
 
-// TODO(crbug.com/1446739): Implement reverse iterators in
-// CheckedContiguousIterator and use them here.
-std::vector<Value>::const_reverse_iterator Value::List::rbegin() const {
-  return storage_.rbegin();
+Value::List::const_reverse_iterator Value::List::rbegin() const {
+  return const_reverse_iterator(end());
 }
 
 const Value& Value::List::front() const {
diff --git a/base/values.h b/base/values.h
index 3f8087fe..46014594 100644
--- a/base/values.h
+++ b/base/values.h
@@ -137,11 +137,10 @@
 //
 // Lists support:
 // - `empty()`, `size()`, `begin()`, `end()`, `cbegin()`, `cend()`,
-//       `front()`, `back()`, `reserve()`, `operator[]`, `clear()`, `erase()`:
-//       Identical to the STL container equivalents, with additional safety
-//       checks, e.g. `operator[]` will `CHECK()` if the index is out of range.
-// - `rbegin()` and `rend()` are also supported, but there are no safety checks
-// (see crbug.com/1446739).
+//       `rbegin()`, `rend()`, `front()`, `back()`, `reserve()`, `operator[]`,
+//       `clear()`, `erase()`: Identical to the STL container equivalents, with
+//       additional safety checks, e.g. `operator[]` will `CHECK()` if the index
+//       is out of range.
 // - `Clone()`: Create a deep copy.
 // - `Append()`: Append a value to the end of the list. Accepts `Value` or any
 //       of the subtypes that `Value` can hold.
@@ -588,6 +587,8 @@
    public:
     using iterator = CheckedContiguousIterator<Value>;
     using const_iterator = CheckedContiguousConstIterator<Value>;
+    using reverse_iterator = std::reverse_iterator<iterator>;
+    using const_reverse_iterator = std::reverse_iterator<const_iterator>;
     using value_type = Value;
 
     // Creates a list with the given capacity reserved.
@@ -628,12 +629,12 @@
 
     // Returns a reverse iterator preceding the first value in this list. May
     // not be dereferenced.
-    std::vector<Value>::reverse_iterator rend();
-    std::vector<Value>::const_reverse_iterator rend() const;
+    reverse_iterator rend();
+    const_reverse_iterator rend() const;
 
     // Returns a reverse iterator to the last value in this list.
-    std::vector<Value>::reverse_iterator rbegin();
-    std::vector<Value>::const_reverse_iterator rbegin() const;
+    reverse_iterator rbegin();
+    const_reverse_iterator rbegin() const;
 
     // Returns a reference to the first value in the container. Fails with
     // `CHECK()` if the list is empty.
diff --git a/build/config/clang/clang.gni b/build/config/clang/clang.gni
index 69883e6a..3cb0553 100644
--- a/build/config/clang/clang.gni
+++ b/build/config/clang/clang.gni
@@ -18,7 +18,7 @@
   enable_check_raw_ptr_fields =
       build_with_chromium && !is_official_build &&
       ((is_linux && !is_castos) || (is_android && !is_cast_android) || is_mac ||
-       is_win || is_chromeos_lacros || is_chromeos_ash)
+       is_win || is_chromeos_lacros)
 
   clang_base_path = default_clang_base_path
 
diff --git a/build/config/rust.gni b/build/config/rust.gni
index 25fc7aa..617b6b0 100644
--- a/build/config/rust.gni
+++ b/build/config/rust.gni
@@ -90,8 +90,8 @@
   enable_rust_json = enable_all_rust_features
 
   # Support for chrome://crash-rust to check crash dump collection works.
-  enable_rust_crash = is_linux || is_android || is_fuchsia || is_chromeos ||
-                      enable_all_rust_features
+  enable_rust_crash =
+      is_linux || is_android || is_fuchsia || enable_all_rust_features
 
   # Support for QR code generation - see https://crbug.com/1431991.
   enable_rust_qr = is_linux || is_android || enable_all_rust_features
diff --git a/cc/layers/heads_up_display_layer_impl.cc b/cc/layers/heads_up_display_layer_impl.cc
index 57b5c9b..60e3b06 100644
--- a/cc/layers/heads_up_display_layer_impl.cc
+++ b/cc/layers/heads_up_display_layer_impl.cc
@@ -43,7 +43,6 @@
 #include "components/viz/common/quads/texture_draw_quad.h"
 #include "components/viz/common/resources/bitmap_allocation.h"
 #include "components/viz/common/resources/platform_color.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/shared_image_format.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "gpu/command_buffer/client/context_support.h"
diff --git a/cc/raster/raster_buffer_provider_perftest.cc b/cc/raster/raster_buffer_provider_perftest.cc
index ad15e0ba..42a5f4bb 100644
--- a/cc/raster/raster_buffer_provider_perftest.cc
+++ b/cc/raster/raster_buffer_provider_perftest.cc
@@ -25,7 +25,6 @@
 #include "components/viz/common/gpu/context_cache_controller.h"
 #include "components/viz/common/gpu/raster_context_provider.h"
 #include "components/viz/common/resources/platform_color.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
 #include "components/viz/test/test_context_provider.h"
 #include "components/viz/test/test_context_support.h"
diff --git a/cc/raster/task.h b/cc/raster/task.h
index f650e8d3..67572d95 100644
--- a/cc/raster/task.h
+++ b/cc/raster/task.h
@@ -138,8 +138,8 @@
     Edge(const Task* task, Task* dependent)
         : task(task), dependent(dependent) {}
 
-    raw_ptr<const Task, DanglingUntriaged> task;
-    raw_ptr<Task, DanglingUntriaged> dependent;
+    raw_ptr<const Task, DanglingAcrossTasks> task;
+    raw_ptr<Task, DanglingAcrossTasks> dependent;
   };
 
   TaskGraph();
diff --git a/cc/resources/resource_pool.cc b/cc/resources/resource_pool.cc
index 55977af..b778fd6b 100644
--- a/cc/resources/resource_pool.cc
+++ b/cc/resources/resource_pool.cc
@@ -26,7 +26,6 @@
 #include "cc/base/container_util.h"
 #include "components/viz/client/client_resource_provider.h"
 #include "components/viz/common/gpu/raster_context_provider.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
 #include "gpu/command_buffer/client/context_support.h"
 #include "gpu/command_buffer/common/capabilities.h"
diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h
index 7afa104..48ba8f0 100644
--- a/cc/scheduler/scheduler.h
+++ b/cc/scheduler/scheduler.h
@@ -296,7 +296,7 @@
 
   // Owned by LayerTreeHostImpl and is destroyed when LayerTreeHostImpl is
   // destroyed.
-  raw_ptr<CompositorFrameReportingController, DanglingUntriaged>
+  raw_ptr<CompositorFrameReportingController, DanglingAcrossTasks>
       compositor_frame_reporting_controller_;
 
   // What the latest deadline was, and when it was scheduled.
diff --git a/cc/slim/frame_sink_impl.cc b/cc/slim/frame_sink_impl.cc
index 5d2c812..c74744e 100644
--- a/cc/slim/frame_sink_impl.cc
+++ b/cc/slim/frame_sink_impl.cc
@@ -20,7 +20,6 @@
 #include "components/viz/common/features.h"
 #include "components/viz/common/quads/compositor_frame.h"
 #include "components/viz/common/resources/platform_color.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/resource_id.h"
 #include "components/viz/common/resources/shared_image_format.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
diff --git a/cc/tiles/tile_manager.cc b/cc/tiles/tile_manager.cc
index 91a5f42..238b378 100644
--- a/cc/tiles/tile_manager.cc
+++ b/cc/tiles/tile_manager.cc
@@ -179,7 +179,7 @@
   TileResolution tile_resolution_;
   int layer_id_;
   uint64_t source_prepare_tiles_id_;
-  raw_ptr<void, DanglingUntriaged> tile_tracing_id_;
+  raw_ptr<void, DanglingAcrossTasks> tile_tracing_id_;
   uint64_t new_content_id_;
   int source_frame_number_;
   std::unique_ptr<RasterBuffer> raster_buffer_;
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 256f599..394d0a39 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -111,7 +111,6 @@
 #include "components/viz/common/quads/solid_color_draw_quad.h"
 #include "components/viz/common/resources/bitmap_allocation.h"
 #include "components/viz/common/resources/platform_color.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/shared_image_format.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
 #include "components/viz/common/traced_value.h"
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 47da404..65dae60 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -76,6 +76,7 @@
   "java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkActivity.java",
   "java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkAddEditFolderActivity.java",
   "java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkEditActivity.java",
+  "java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkFolderPickerActivity.java",
   "java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkFolderSelectActivity.java",
   "java/src/org/chromium/chrome/browser/app/creator/CreatorActionDelegateImpl.java",
   "java/src/org/chromium/chrome/browser/app/creator/CreatorActivity.java",
@@ -157,6 +158,10 @@
   "java/src/org/chromium/chrome/browser/bookmarks/BookmarkBridge.java",
   "java/src/org/chromium/chrome/browser/bookmarks/BookmarkDelegate.java",
   "java/src/org/chromium/chrome/browser/bookmarks/BookmarkFeatures.java",
+  "java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerCoordinator.java",
+  "java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerMediator.java",
+  "java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerProperties.java",
+  "java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerViewBinder.java",
   "java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderRow.java",
   "java/src/org/chromium/chrome/browser/bookmarks/BookmarkImageFetcher.java",
   "java/src/org/chromium/chrome/browser/bookmarks/BookmarkItemRow.java",
diff --git a/chrome/android/expectations/monochrome_public_bundle__chrome.AndroidManifest.expected b/chrome/android/expectations/monochrome_public_bundle__chrome.AndroidManifest.expected
index c46158a9..bcf510e0 100644
--- a/chrome/android/expectations/monochrome_public_bundle__chrome.AndroidManifest.expected
+++ b/chrome/android/expectations/monochrome_public_bundle__chrome.AndroidManifest.expected
@@ -105,6 +105,14 @@
         android:theme="@style/Theme.Chromium.DialogWhenLarge"
         android:windowSoftInputMode="stateHidden">
     </activity>  # DIFF-ANCHOR: 766e66bd
+    <activity  # DIFF-ANCHOR: 002f9e99
+        android:name="org.chromium.chrome.browser.app.bookmarks.BookmarkFolderPickerActivity"
+        android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
+        android:exported="false"
+        android:label="@string/bookmark_choose_folder"
+        android:theme="@style/Theme.Chromium.DialogWhenLarge"
+        android:windowSoftInputMode="stateAlwaysHidden">
+    </activity>  # DIFF-ANCHOR: 002f9e99
     <activity  # DIFF-ANCHOR: 8f8d0c81
         android:name="org.chromium.chrome.browser.app.bookmarks.BookmarkFolderSelectActivity"
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index 6f3722c..aa421c8 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -667,6 +667,13 @@
             android:exported="false"
             android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize">
         </activity>
+        <activity android:name="org.chromium.chrome.browser.app.bookmarks.BookmarkFolderPickerActivity"
+            android:theme="@style/Theme.Chromium.DialogWhenLarge"
+            android:windowSoftInputMode="stateAlwaysHidden"
+            android:label="@string/bookmark_choose_folder"
+            android:exported="false"
+            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize">
+        </activity>
 
         <!-- Activities for downloads. -->
         <activity-alias android:name="org.chromium.chrome.browser.download.DownloadActivity"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkFolderPickerActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkFolderPickerActivity.java
new file mode 100644
index 0000000..492b67f3
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkFolderPickerActivity.java
@@ -0,0 +1,14 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.app.bookmarks;
+
+import org.chromium.chrome.browser.SynchronousInitializationActivity;
+
+/**
+ * The activity that enables the user to pick the parent folder for the given {@link BookmarkId}.
+ * Used for the improved android bookmarks manager.
+ */
+// TODO(crbug.com/1448933): Implement new folder picker activity.
+public class BookmarkFolderPickerActivity extends SynchronousInitializationActivity {}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerCoordinator.java
new file mode 100644
index 0000000..5f0e58db
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerCoordinator.java
@@ -0,0 +1,9 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.bookmarks;
+
+/** Mediator for the folder select activity. */
+// TODO(crbug.com/1448933): Implement new folder picker activity.
+public class BookmarkFolderPickerCoordinator {}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerMediator.java
new file mode 100644
index 0000000..b12ec3c
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerMediator.java
@@ -0,0 +1,9 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.bookmarks;
+
+/** Mediator for the folder picker activity. */
+// TODO(crbug.com/1448933): Implement new folder picker activity.
+class BookmarkFolderPickerMediator {}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerProperties.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerProperties.java
new file mode 100644
index 0000000..d196bf1b
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerProperties.java
@@ -0,0 +1,9 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.bookmarks;
+
+/** Properties for the folder picker activity. */
+// TODO(crbug.com/1448933): Implement new folder picker activity.
+class BookmarkFolderPickerProperties {}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerViewBinder.java
new file mode 100644
index 0000000..3daee71
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerViewBinder.java
@@ -0,0 +1,9 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.bookmarks;
+
+/** View binder for the folder picker activity. */
+// TODO(crbug.com/1448933): Implement new folder picker activity.
+class BookmarkFolderPickerViewBinder {}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkFolderSelectActivityCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkFolderSelectActivityCoordinator.java
new file mode 100644
index 0000000..cac2b4f
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkFolderSelectActivityCoordinator.java
@@ -0,0 +1,9 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.bookmarks;
+
+/** Coordinator for the folder select activity. */
+// TODO(crbug.com/1448933): Implement new folder select activity.
+public class BookmarkFolderPickerCoordinator {}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkFolderSelectActivityMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkFolderSelectActivityMediator.java
new file mode 100644
index 0000000..001c80a1
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkFolderSelectActivityMediator.java
@@ -0,0 +1,9 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.bookmarks;
+
+/** Mediator for the folder select activity. */
+// TODO(crbug.com/1448933): Implement new folder select activity.
+class BookmarkFolderPickerMediator {}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkFolderSelectActivityProperties.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkFolderSelectActivityProperties.java
new file mode 100644
index 0000000..971dd867
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkFolderSelectActivityProperties.java
@@ -0,0 +1,9 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.bookmarks;
+
+/** Properties for the folder select activity. */
+// TODO(crbug.com/1448933): Implement new folder select activity.
+class BookmarkFolderPickerProperties {}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkFolderSelectActivityViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkFolderSelectActivityViewBinder.java
new file mode 100644
index 0000000..29260d2
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkFolderSelectActivityViewBinder.java
@@ -0,0 +1,9 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.bookmarks;
+
+/** View binder for the folder select activity. */
+// TODO(crbug.com/1448933): Implement new folder select activity.
+class BookmarkFolderPickerViewBinder {}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordMigrationWarningBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordMigrationWarningBridge.java
index b690b21e3..354a017 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordMigrationWarningBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordMigrationWarningBridge.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.password_manager;
 
+import android.app.Activity;
 import android.content.Context;
 
 import org.chromium.base.ContextUtils;
@@ -31,6 +32,17 @@
         if (context == null) return;
         // The export flow won't work unless the sheet is started with an Activity as a Context.
         if (ContextUtils.activityFromContext(context) == null) return;
+        showWarningInternal(context, bottomSheetController, profile);
+    }
+
+    @CalledByNative
+    static void showWarningWithActivity(
+            Activity activity, BottomSheetController bottomSheetController, Profile profile) {
+        showWarningInternal(activity, bottomSheetController, profile);
+    }
+
+    private static void showWarningInternal(
+            Context context, BottomSheetController bottomSheetController, Profile profile) {
         PasswordMigrationWarningCoordinator passwordMigrationWarningCoordinator =
                 new PasswordMigrationWarningCoordinator(context, profile, bottomSheetController,
                         SyncConsentActivityLauncherImpl.get(), new SettingsLauncherImpl(),
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordManagerHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordManagerHandler.java
index a133f05..ff7e04e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordManagerHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordManagerHandler.java
@@ -4,12 +4,14 @@
 
 package org.chromium.chrome.browser.password_manager.settings;
 
+import android.app.Activity;
 import android.content.Context;
 
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.Callback;
 import org.chromium.base.IntStringCallback;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.components.browser_ui.settings.SettingsLauncher;
 
 /**
@@ -82,8 +84,12 @@
             boolean isBlockedCredential);
 
     /**
-     * Checks whether the all the conditions for the migraiton warning to be shown are met.
-     * This includes the flag check, whether there was another warning shown in the past month, etc.
+     * Calls C++ to trigger the migration warning. The C++ util centralizes the showing logic such
+     * that it can ensure that all appropriate checks are done an that the timestamp for showing
+     * the warning is uniformly recorded.
+     *
+     * @param activity the activity used to show the warning and potentially the export flow.
+     * @param bottomSheetController the controller displaying the warning bottom sheet.
      */
-    boolean shouldShowMigrationWarning();
+    void showMigrationWarning(Activity activity, BottomSheetController bottomSheetController);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettings.java b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettings.java
index a545759..f3f4ee59 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettings.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettings.java
@@ -39,13 +39,10 @@
 import org.chromium.chrome.browser.password_manager.PasswordManagerHelper;
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.pwd_migration.PasswordMigrationWarningCoordinator;
 import org.chromium.chrome.browser.settings.ChromeManagedPreferenceDelegate;
 import org.chromium.chrome.browser.settings.ProfileDependentSetting;
 import org.chromium.chrome.browser.settings.SettingsLauncherImpl;
-import org.chromium.chrome.browser.signin.SyncConsentActivityLauncherImpl;
 import org.chromium.chrome.browser.sync.SyncServiceFactory;
-import org.chromium.chrome.browser.sync.settings.ManageSyncSettings;
 import org.chromium.chrome.browser.sync.settings.SyncSettingsUtils;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.components.browser_ui.settings.ChromeBasePreference;
@@ -403,18 +400,10 @@
             }
         }
 
-        if (!mNoPasswords
-                && PasswordManagerHandlerProvider.getInstance()
-                           .getPasswordManagerHandler()
-                           .shouldShowMigrationWarning()) {
-            PasswordMigrationWarningCoordinator passwordMigrationWarningCoordinator =
-                    new PasswordMigrationWarningCoordinator(getContext(), mProfile,
-                            mBottomSheetController, SyncConsentActivityLauncherImpl.get(),
-                            new SettingsLauncherImpl(), ManageSyncSettings.class, new ExportFlow(),
-                            (PasswordListObserver observer)
-                                    -> PasswordManagerHandlerProvider.getInstance().addObserver(
-                                            observer));
-            passwordMigrationWarningCoordinator.showWarning();
+        if (!mNoPasswords) {
+            PasswordManagerHandlerProvider.getInstance()
+                    .getPasswordManagerHandler()
+                    .showMigrationWarning(getActivity(), mBottomSheetController);
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordUIView.java b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordUIView.java
index 90cd277..9e764aa 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordUIView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordUIView.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.password_manager.settings;
 
+import android.app.Activity;
 import android.content.Context;
 
 import androidx.annotation.VisibleForTesting;
@@ -12,6 +13,7 @@
 import org.chromium.base.IntStringCallback;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.NativeMethods;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.components.browser_ui.settings.SettingsLauncher;
 
 /**
@@ -111,8 +113,11 @@
     }
 
     @Override
-    public boolean shouldShowMigrationWarning() {
-        return PasswordUIViewJni.get().shouldShowMigrationWarning();
+    public void showMigrationWarning(
+            Activity activity, BottomSheetController bottomSheetController) {
+        if (mNativePasswordUIViewAndroid == 0) return;
+        PasswordUIViewJni.get().showMigrationWarning(
+                mNativePasswordUIViewAndroid, activity, bottomSheetController);
     }
 
     /**
@@ -173,6 +178,7 @@
                 SettingsLauncher launcher, int index, PasswordUIView caller);
         void handleShowBlockedCredentialView(long nativePasswordUIViewAndroid, Context context,
                 SettingsLauncher launcher, int index, PasswordUIView caller);
-        boolean shouldShowMigrationWarning();
+        void showMigrationWarning(long nativePasswordUIViewAndroid, Activity activity,
+                BottomSheetController bottomSheetController);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AddressEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AddressEditor.java
index a40fff5..7407a5b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AddressEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AddressEditor.java
@@ -13,6 +13,7 @@
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.DropdownFieldProperties.DROPDOWN_KEY_VALUE_LIST;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.EDITOR_FIELDS;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.EDITOR_TITLE;
+import static org.chromium.chrome.browser.autofill.editors.EditorProperties.FORM_VALID;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.FieldProperties.CUSTOM_ERROR_MESSAGE;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.FieldProperties.INVALID_ERROR_MESSAGE;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.FieldProperties.IS_FULL_LINE;
@@ -24,11 +25,9 @@
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.ItemType.DROPDOWN;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.ItemType.TEXT_INPUT;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.SHOW_REQUIRED_INDICATOR;
-import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.LENGTH_COUNTER_LIMIT_NONE;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.TEXT_ALL_KEYS;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.TEXT_FORMATTER;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.TEXT_INPUT_TYPE;
-import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.TEXT_LENGTH_COUNTER_LIMIT;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.TEXT_SUGGESTIONS;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextInputType.ALPHA_NUMERIC_INPUT;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextInputType.PERSON_NAME_INPUT;
@@ -37,6 +36,7 @@
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextInputType.REGION_INPUT;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextInputType.STREET_ADDRESS_INPUT;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.VISIBLE;
+import static org.chromium.chrome.browser.autofill.editors.EditorProperties.isFormValid;
 
 import android.app.ProgressDialog;
 import android.text.TextUtils;
@@ -57,6 +57,7 @@
 import org.chromium.chrome.browser.autofill.editors.EditorBase;
 import org.chromium.chrome.browser.autofill.editors.EditorDialogViewBinder;
 import org.chromium.chrome.browser.autofill.editors.EditorProperties.EditorFieldValidator;
+import org.chromium.chrome.browser.autofill.editors.EditorProperties.ItemType;
 import org.chromium.payments.mojom.AddressErrors;
 import org.chromium.ui.modelutil.ListModel;
 import org.chromium.ui.modelutil.MVCListAdapter.ListItem;
@@ -81,7 +82,7 @@
 @Deprecated
 public class AddressEditor
         extends EditorBase<AutofillAddress> implements GetSubKeysRequestDelegate {
-    private final Map<Integer, ListItem> mAddressFields = new HashMap<>();
+    private final Map<Integer, PropertyModel> mAddressFields = new HashMap<>();
     private final Set<String> mPhoneNumbers = new HashSet<>();
     private final boolean mSaveToDisk;
     private final PhoneNumberUtil.CountryAwareFormatTextWatcher mPhoneFormatter;
@@ -93,9 +94,16 @@
     @Nullable
     private PropertyModel mPhoneField;
     @Nullable
+    private PropertyModel mAdminAreaField;
+    private @ItemType int mAdminAreaFieldType;
+    @Nullable
     private List<AddressUiComponent> mAddressUiComponents;
     private boolean mAdminAreasLoaded;
     private String mRecentlySelectedCountry;
+    private Callback<AutofillAddress> mDoneCallback;
+    private Callback<AutofillAddress> mCancelCallback;
+    private boolean mAddressNew;
+    private AutofillAddress mAddress;
     private AutofillProfile mProfile;
     private ProgressDialog mProgressDialog;
     @Nullable
@@ -184,22 +192,23 @@
             final Callback<AutofillAddress> doneCallback,
             final Callback<AutofillAddress> cancelCallback) {
         super.edit(toEdit, doneCallback, cancelCallback);
-
         if (mAutofillProfileBridge == null) mAutofillProfileBridge = new AutofillProfileBridge();
+        mDoneCallback = doneCallback;
+        mCancelCallback = cancelCallback;
 
         // If |toEdit| is null, we're creating a new autofill profile with the country code of the
         // default locale on this device.
         final String editTitle;
-        final AutofillAddress address;
-        if (toEdit == null) {
-            address = new AutofillAddress(mContext, AutofillProfile.builder().build());
+        mAddressNew = toEdit == null;
+        if (mAddressNew) {
+            mAddress = new AutofillAddress(mContext, AutofillProfile.builder().build());
             editTitle = mContext.getString(R.string.autofill_create_profile);
         } else {
-            address = toEdit;
+            mAddress = toEdit;
             editTitle = toEdit.getEditTitle();
         }
 
-        mProfile = address.getProfile();
+        mProfile = mAddress.getProfile();
 
         // When edit is called, a new form is started, so the country on the
         // dropdown list is not changed. => mRecentlySelectedCountry should be null.
@@ -247,47 +256,40 @@
         if (mAddressFields.isEmpty()) {
             // City, dependent locality, and organization don't have any special formatting hints.
             mAddressFields.put(AddressField.LOCALITY,
-                    new ListItem(TEXT_INPUT,
-                            new PropertyModel.Builder(TEXT_ALL_KEYS)
-                                    .with(TEXT_INPUT_TYPE, PLAIN_TEXT_INPUT)
-                                    .build()));
+                    new PropertyModel.Builder(TEXT_ALL_KEYS)
+                            .with(TEXT_INPUT_TYPE, PLAIN_TEXT_INPUT)
+                            .build());
             mAddressFields.put(AddressField.DEPENDENT_LOCALITY,
-                    new ListItem(TEXT_INPUT,
-                            new PropertyModel.Builder(TEXT_ALL_KEYS)
-                                    .with(TEXT_INPUT_TYPE, PLAIN_TEXT_INPUT)
-                                    .build()));
+                    new PropertyModel.Builder(TEXT_ALL_KEYS)
+                            .with(TEXT_INPUT_TYPE, PLAIN_TEXT_INPUT)
+                            .build());
             mAddressFields.put(AddressField.ORGANIZATION,
-                    new ListItem(TEXT_INPUT,
-                            new PropertyModel.Builder(TEXT_ALL_KEYS)
-                                    .with(TEXT_INPUT_TYPE, PLAIN_TEXT_INPUT)
-                                    .build()));
+                    new PropertyModel.Builder(TEXT_ALL_KEYS)
+                            .with(TEXT_INPUT_TYPE, PLAIN_TEXT_INPUT)
+                            .build());
 
             // Sorting code and postal code (a.k.a. ZIP code) should show both letters and digits on
             // the keyboard, if possible.
             mAddressFields.put(AddressField.SORTING_CODE,
-                    new ListItem(TEXT_INPUT,
-                            new PropertyModel.Builder(TEXT_ALL_KEYS)
-                                    .with(TEXT_INPUT_TYPE, ALPHA_NUMERIC_INPUT)
-                                    .build()));
+                    new PropertyModel.Builder(TEXT_ALL_KEYS)
+                            .with(TEXT_INPUT_TYPE, ALPHA_NUMERIC_INPUT)
+                            .build());
             mAddressFields.put(AddressField.POSTAL_CODE,
-                    new ListItem(TEXT_INPUT,
-                            new PropertyModel.Builder(TEXT_ALL_KEYS)
-                                    .with(TEXT_INPUT_TYPE, ALPHA_NUMERIC_INPUT)
-                                    .build()));
+                    new PropertyModel.Builder(TEXT_ALL_KEYS)
+                            .with(TEXT_INPUT_TYPE, ALPHA_NUMERIC_INPUT)
+                            .build());
 
             // Street line field can contain \n to indicate line breaks.
             mAddressFields.put(AddressField.STREET_ADDRESS,
-                    new ListItem(TEXT_INPUT,
-                            new PropertyModel.Builder(TEXT_ALL_KEYS)
-                                    .with(TEXT_INPUT_TYPE, STREET_ADDRESS_INPUT)
-                                    .build()));
+                    new PropertyModel.Builder(TEXT_ALL_KEYS)
+                            .with(TEXT_INPUT_TYPE, STREET_ADDRESS_INPUT)
+                            .build());
 
             // Android has special formatting rules for names.
             mAddressFields.put(AddressField.RECIPIENT,
-                    new ListItem(TEXT_INPUT,
-                            new PropertyModel.Builder(TEXT_ALL_KEYS)
-                                    .with(TEXT_INPUT_TYPE, PERSON_NAME_INPUT)
-                                    .build()));
+                    new PropertyModel.Builder(TEXT_ALL_KEYS)
+                            .with(TEXT_INPUT_TYPE, PERSON_NAME_INPUT)
+                            .build());
         }
 
         // Phone number is present for all countries.
@@ -309,7 +311,6 @@
                                     mContext.getString(
                                             R.string.payments_phone_invalid_validation_message))
                             .with(IS_FULL_LINE, true)
-                            .with(TEXT_LENGTH_COUNTER_LIMIT, LENGTH_COUNTER_LIMIT_NONE)
                             .build();
         }
 
@@ -317,44 +318,59 @@
         // that's being edited.
         mPhoneField.set(VALUE, mProfile.getPhoneNumber());
 
-        // If the user clicks [Cancel], send |toEdit| address back to the caller, which was the
-        // original state (could be null, a complete address, a partial address).
-        Runnable onCancel = () -> {
-            // This makes sure that onSubKeysReceived returns early if it's
-            // ever called when Cancel has already occurred.
-            mAdminAreasLoaded = true;
-            PersonalDataManager.getInstance().cancelPendingGetSubKeys();
-            cancelCallback.onResult(toEdit);
-
-            // Clean up the state of this editor.
-            reset();
-        };
-
-        // If the user clicks [Done], save changes on disk, mark the address "complete" if possible,
-        // and send it back to the caller.
-        Runnable onDone = () -> {
-            mAdminAreasLoaded = true;
-            PersonalDataManager.getInstance().cancelPendingGetSubKeys();
-            commitChanges(mProfile);
-            address.completeAddress(mProfile);
-            doneCallback.onResult(address);
-
-            // Clean up the state of this editor.
-            reset();
-        };
-
         mEditorModel = new PropertyModel.Builder(ALL_KEYS)
                                .with(EDITOR_TITLE, editTitle)
                                .with(SHOW_REQUIRED_INDICATOR, true)
                                .with(EDITOR_FIELDS, new ListModel())
-                               .with(DONE_RUNNABLE, onDone)
-                               .with(CANCEL_RUNNABLE, onCancel)
+                               .with(DONE_RUNNABLE, this::onDone)
+                               .with(CANCEL_RUNNABLE, this::onCancel)
+                               .with(FORM_VALID, true)
                                .build();
         mEditorMCP = PropertyModelChangeProcessor.create(
                 mEditorModel, mEditorDialog, EditorDialogViewBinder::bindEditorDialogView);
 
         loadAdminAreasForCountry(mCountryField.get(VALUE));
-        if (mAddressErrors != null) mEditorDialog.validateForm();
+        mEditorModel.set(FORM_VALID, mAddressErrors == null || isFormValid(mEditorModel));
+    }
+
+    private void onDone() {
+        if (!isFormValid(mEditorModel)) {
+            // Note: triggering editor error messages and focused field update using temporary
+            // property.
+            // TODO(crbug.com/1435314): remove this temporary logic.
+            mEditorModel.set(FORM_VALID, true);
+            mEditorModel.set(FORM_VALID, false);
+            return;
+        }
+        mEditorModel.set(VISIBLE, false);
+
+        // This makes sure that onSubKeysReceived returns early if it's
+        // ever called when Done has already occurred.
+        mAdminAreasLoaded = true;
+        PersonalDataManager.getInstance().cancelPendingGetSubKeys();
+
+        // Commit changes to the address and send modified address to the caller.
+        commitChanges(mProfile);
+        mAddress.completeAddress(mProfile);
+        mDoneCallback.onResult(mAddress);
+
+        // Clean up the state of this editor.
+        reset();
+    }
+
+    private void onCancel() {
+        mEditorModel.set(VISIBLE, false);
+
+        // This makes sure that onSubKeysReceived returns early if it's
+        // ever called when Cancel has already occurred.
+        mAdminAreasLoaded = true;
+        PersonalDataManager.getInstance().cancelPendingGetSubKeys();
+
+        // Send unchanged address to the caller.
+        mCancelCallback.onResult(mAddressNew ? null : mAddress);
+
+        // Clean up the state of this editor.
+        reset();
     }
 
     private void showProgressDialog() {
@@ -385,15 +401,17 @@
         for (int i = 0; i < mAddressUiComponents.size(); i++) {
             AddressUiComponent component = mAddressUiComponents.get(i);
             visibleFields.add(component.id);
+            PropertyModel fieldModel = component.id == AddressField.ADMIN_AREA
+                    ? mAdminAreaField
+                    : mAddressFields.get(component.id);
             if (component.id != AddressField.COUNTRY) {
-                setProfileField(
-                        profile, component.id, mAddressFields.get(component.id).model.get(VALUE));
+                setProfileField(profile, component.id, fieldModel.get(VALUE));
             }
         }
 
         // Clear the fields that are hidden from the user interface, so
         // AutofillAddress.toPaymentAddress() will send them to the renderer as empty strings.
-        for (Map.Entry<Integer, ListItem> entry : mAddressFields.entrySet()) {
+        for (Map.Entry<Integer, PropertyModel> entry : mAddressFields.entrySet()) {
             if (!visibleFields.contains(entry.getKey())) {
                 setProfileField(profile, entry.getKey(), "");
             }
@@ -459,10 +477,11 @@
     private void setAddressFieldValuesFromCache() {
         // Address fields are cached, so their values need to be updated for every new profile
         // that's being edited.
-        for (Map.Entry<Integer, ListItem> entry : mAddressFields.entrySet()) {
-            entry.getValue().model.set(
-                    VALUE, AutofillAddress.getProfileField(mProfile, entry.getKey()));
+        for (Map.Entry<Integer, PropertyModel> entry : mAddressFields.entrySet()) {
+            entry.getValue().set(VALUE, AutofillAddress.getProfileField(mProfile, entry.getKey()));
         }
+        mAdminAreaField.set(
+                VALUE, AutofillAddress.getProfileField(mProfile, AddressField.ADMIN_AREA));
     }
 
     @Override
@@ -475,22 +494,7 @@
         // subkeys.
         if (mEditorDialog.isDismissed()) return;
 
-        // When there is a timeout in the subkey request process, the admin area codes/names will be
-        // null.
-        mAddressFields.put(AddressField.ADMIN_AREA,
-                (adminAreaCodes != null && adminAreaNames != null && adminAreaCodes.length != 0
-                        && adminAreaCodes.length == adminAreaNames.length)
-                        ? new ListItem(DROPDOWN,
-                                new PropertyModel.Builder(DROPDOWN_ALL_KEYS)
-                                        .with(DROPDOWN_KEY_VALUE_LIST,
-                                                AutofillProfileBridge.getAdminAreaDropdownList(
-                                                        adminAreaCodes, adminAreaNames))
-                                        .with(DROPDOWN_HINT, mContext.getString(R.string.select))
-                                        .build())
-                        : new ListItem(TEXT_INPUT,
-                                new PropertyModel.Builder(TEXT_ALL_KEYS)
-                                        .with(TEXT_INPUT_TYPE, REGION_INPUT)
-                                        .build()));
+        initializeAdminAreaField(adminAreaCodes, adminAreaNames);
 
         // Admin areas need to be fetched in two cases:
         // 1. Initial loading of the form.
@@ -512,13 +516,25 @@
         }
     }
 
-    private static boolean contains(String[] haystack, String needle) {
-        if (haystack == null || haystack.length == 0) return false;
-        if (TextUtils.isEmpty(needle)) return true;
-        for (int i = 0; i < haystack.length; ++i) {
-            if (TextUtils.equals(haystack[i], needle)) return true;
+    private void initializeAdminAreaField(
+            @Nullable String[] adminAreaCodes, @Nullable String[] adminAreaNames) {
+        // When there is a timeout in the subkey request process, the admin area codes/names will be
+        // null.
+        if (adminAreaCodes == null || adminAreaNames == null || adminAreaCodes.length == 0
+                || adminAreaCodes.length != adminAreaNames.length) {
+            mAdminAreaField = new PropertyModel.Builder(TEXT_ALL_KEYS)
+                                      .with(TEXT_INPUT_TYPE, REGION_INPUT)
+                                      .build();
+            mAdminAreaFieldType = TEXT_INPUT;
+            return;
         }
-        return false;
+        mAdminAreaField = new PropertyModel.Builder(DROPDOWN_ALL_KEYS)
+                                  .with(DROPDOWN_KEY_VALUE_LIST,
+                                          AutofillProfileBridge.getAdminAreaDropdownList(
+                                                  adminAreaCodes, adminAreaNames))
+                                  .with(DROPDOWN_HINT, mContext.getString(R.string.select))
+                                  .build();
+        mAdminAreaFieldType = DROPDOWN;
     }
 
     /** Requests the list of admin areas. */
@@ -554,8 +570,15 @@
         for (int i = 0; i < mAddressUiComponents.size(); i++) {
             AddressUiComponent component = mAddressUiComponents.get(i);
 
-            ListItem fieldItem = mAddressFields.get(component.id);
-            PropertyModel field = fieldItem.model;
+            final PropertyModel field;
+            final @ItemType int fieldType;
+            if (component.id == AddressField.ADMIN_AREA) {
+                field = mAdminAreaField;
+                fieldType = mAdminAreaFieldType;
+            } else {
+                field = mAddressFields.get(component.id);
+                fieldType = TEXT_INPUT;
+            }
 
             // Labels depend on country, e.g., state is called province in some countries. These are
             // already localized.
@@ -574,7 +597,7 @@
             }
 
             field.set(CUSTOM_ERROR_MESSAGE, getAddressError(component.id));
-            editorFields.add(fieldItem);
+            editorFields.add(new ListItem(fieldType, field));
         }
         // Phone number (and email if applicable) are the last fields of the address.
         mPhoneField.set(CUSTOM_ERROR_MESSAGE, mAddressErrors != null ? mAddressErrors.phone : null);
@@ -610,10 +633,5 @@
             return !TextUtils.isEmpty(value)
                     && PhoneNumberUtil.isPossibleNumber(value, mCountryCode);
         }
-
-        @Override
-        public boolean isLengthMaximum(@Nullable String value) {
-            return false;
-        }
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ContactEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ContactEditor.java
index d2daad9..41103bd4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ContactEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ContactEditor.java
@@ -9,6 +9,7 @@
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.DONE_RUNNABLE;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.EDITOR_FIELDS;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.EDITOR_TITLE;
+import static org.chromium.chrome.browser.autofill.editors.EditorProperties.FORM_VALID;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.FieldProperties.CUSTOM_ERROR_MESSAGE;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.FieldProperties.INVALID_ERROR_MESSAGE;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.FieldProperties.IS_FULL_LINE;
@@ -19,16 +20,15 @@
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.FieldProperties.VALUE;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.ItemType.TEXT_INPUT;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.SHOW_REQUIRED_INDICATOR;
-import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.LENGTH_COUNTER_LIMIT_NONE;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.TEXT_ALL_KEYS;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.TEXT_FORMATTER;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.TEXT_INPUT_TYPE;
-import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.TEXT_LENGTH_COUNTER_LIMIT;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.TEXT_SUGGESTIONS;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextInputType.EMAIL_ADDRESS_INPUT;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextInputType.PERSON_NAME_INPUT;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextInputType.PHONE_NUMBER_INPUT;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.VISIBLE;
+import static org.chromium.chrome.browser.autofill.editors.EditorProperties.isFormValid;
 
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
@@ -85,6 +85,13 @@
     private EditorFieldValidator mPhoneValidator;
     @Nullable
     private EditorFieldValidator mEmailValidator;
+    private boolean mContactNew;
+    private AutofillContact mContact;
+    private Optional<PropertyModel> mNameField;
+    private Optional<PropertyModel> mPhoneField;
+    private Optional<PropertyModel> mEmailField;
+    private Callback<AutofillContact> mDoneCallback;
+    private Callback<AutofillContact> mCancelCallback;
 
     /**
      * Builds a contact information editor.
@@ -204,15 +211,17 @@
             final Callback<AutofillContact> doneCallback,
             final Callback<AutofillContact> cancelCallback) {
         super.edit(toEdit, doneCallback, cancelCallback);
+        mDoneCallback = doneCallback;
+        mCancelCallback = cancelCallback;
 
-        final AutofillContact contact = toEdit == null
-                ? new AutofillContact(mContext, AutofillProfile.builder().build(), null, null, null,
-                        INVALID_NAME | INVALID_PHONE_NUMBER | INVALID_EMAIL, mRequestPayerName,
-                        mRequestPayerPhone, mRequestPayerEmail)
-                : toEdit;
+        mContactNew = toEdit == null;
+        mContact = mContactNew ? new AutofillContact(mContext, AutofillProfile.builder().build(),
+                           null, null, null, INVALID_NAME | INVALID_PHONE_NUMBER | INVALID_EMAIL,
+                           mRequestPayerName, mRequestPayerPhone, mRequestPayerEmail)
+                               : toEdit;
 
         final String nameCustomErrorMessage = mPayerErrors != null ? mPayerErrors.name : null;
-        final Optional<PropertyModel> nameField = Optional.ofNullable(mRequestPayerName
+        mNameField = Optional.ofNullable(mRequestPayerName
                         ? new PropertyModel.Builder(TEXT_ALL_KEYS)
                                   .with(TEXT_INPUT_TYPE, PERSON_NAME_INPUT)
                                   .with(LABEL,
@@ -225,13 +234,12 @@
                                                   R.string.pref_edit_dialog_field_required_validation_message))
                                   .with(CUSTOM_ERROR_MESSAGE, nameCustomErrorMessage)
                                   .with(IS_FULL_LINE, true)
-                                  .with(TEXT_LENGTH_COUNTER_LIMIT, LENGTH_COUNTER_LIMIT_NONE)
-                                  .with(VALUE, contact.getPayerName())
+                                  .with(VALUE, mContact.getPayerName())
                                   .build()
                         : null);
 
         final String phoneCustomErrorMessage = mPayerErrors != null ? mPayerErrors.phone : null;
-        final Optional<PropertyModel> phoneField = Optional.ofNullable(mRequestPayerPhone
+        mPhoneField = Optional.ofNullable(mRequestPayerPhone
                         ? new PropertyModel.Builder(TEXT_ALL_KEYS)
                                   .with(TEXT_INPUT_TYPE, PHONE_NUMBER_INPUT)
                                   .with(LABEL,
@@ -250,13 +258,12 @@
                                                   R.string.payments_phone_invalid_validation_message))
                                   .with(CUSTOM_ERROR_MESSAGE, phoneCustomErrorMessage)
                                   .with(IS_FULL_LINE, true)
-                                  .with(TEXT_LENGTH_COUNTER_LIMIT, LENGTH_COUNTER_LIMIT_NONE)
-                                  .with(VALUE, contact.getPayerPhone())
+                                  .with(VALUE, mContact.getPayerPhone())
                                   .build()
                         : null);
 
         final String emailCustomErrorMessage = mPayerErrors != null ? mPayerErrors.email : null;
-        final Optional<PropertyModel> emailField = Optional.ofNullable(mRequestPayerEmail
+        mEmailField = Optional.ofNullable(mRequestPayerEmail
                         ? new PropertyModel.Builder(TEXT_ALL_KEYS)
                                   .with(TEXT_INPUT_TYPE, EMAIL_ADDRESS_INPUT)
                                   .with(LABEL,
@@ -273,8 +280,7 @@
                                                   R.string.payments_email_invalid_validation_message))
                                   .with(CUSTOM_ERROR_MESSAGE, emailCustomErrorMessage)
                                   .with(IS_FULL_LINE, true)
-                                  .with(TEXT_LENGTH_COUNTER_LIMIT, LENGTH_COUNTER_LIMIT_NONE)
-                                  .with(VALUE, contact.getPayerEmail())
+                                  .with(VALUE, mContact.getPayerEmail())
                                   .build()
                         : null);
 
@@ -283,77 +289,88 @@
                 : toEdit.getEditTitle();
 
         ListModel<ListItem> editorFields = new ListModel<>();
-        if (nameField.isPresent()) {
-            editorFields.add(new ListItem(TEXT_INPUT, nameField.get()));
+        if (mNameField.isPresent()) {
+            editorFields.add(new ListItem(TEXT_INPUT, mNameField.get()));
         }
-        if (phoneField.isPresent()) {
-            editorFields.add(new ListItem(TEXT_INPUT, phoneField.get()));
+        if (mPhoneField.isPresent()) {
+            editorFields.add(new ListItem(TEXT_INPUT, mPhoneField.get()));
         }
-        if (emailField.isPresent()) {
-            editorFields.add(new ListItem(TEXT_INPUT, emailField.get()));
+        if (mEmailField.isPresent()) {
+            editorFields.add(new ListItem(TEXT_INPUT, mEmailField.get()));
         }
 
-        // If the user clicks [Cancel], send |toEdit| contact back to the caller, which was the
-        // original state (could be null, a complete contact, a partial contact).
-        Runnable onCancel = () -> {
-            cancelCallback.onResult(toEdit);
-
-            // Clean up the state of this editor.
-            reset();
-        };
-
-        Runnable onDone = () -> {
-            String name = null;
-            String phone = null;
-            String email = null;
-            AutofillProfile profile = contact.getProfile();
-
-            if (nameField.isPresent()) {
-                name = nameField.get().get(VALUE);
-                profile.setFullName(name);
-            }
-
-            if (phoneField.isPresent()) {
-                phone = phoneField.get().get(VALUE);
-                profile.setPhoneNumber(phone);
-            }
-
-            if (emailField.isPresent()) {
-                email = emailField.get().get(VALUE);
-                profile.setEmailAddress(email);
-            }
-
-            if (mSaveToDisk) {
-                profile.setGUID(PersonalDataManager.getInstance().setProfileToLocal(profile));
-            }
-
-            if (profile.getGUID().isEmpty()) {
-                assert !mSaveToDisk;
-
-                // Set a fake guid for a new temp AutofillProfile.
-                profile.setGUID(UUID.randomUUID().toString());
-            }
-
-            profile.setIsLocal(true);
-            contact.completeContact(profile.getGUID(), name, phone, email);
-            doneCallback.onResult(contact);
-
-            // Clean up the state of this editor.
-            reset();
-        };
-
         mEditorModel = new PropertyModel.Builder(ALL_KEYS)
                                .with(EDITOR_TITLE, editorTitle)
                                .with(SHOW_REQUIRED_INDICATOR, true)
                                .with(EDITOR_FIELDS, editorFields)
-                               .with(DONE_RUNNABLE, onDone)
-                               .with(CANCEL_RUNNABLE, onCancel)
+                               .with(DONE_RUNNABLE, this::onDone)
+                               .with(CANCEL_RUNNABLE, this::onCancel)
+                               .with(FORM_VALID, true)
                                .build();
 
         mEditorMCP = PropertyModelChangeProcessor.create(
                 mEditorModel, mEditorDialog, EditorDialogViewBinder::bindEditorDialogView);
         mEditorModel.set(VISIBLE, true);
-        if (mPayerErrors != null) mEditorDialog.validateForm();
+        mEditorModel.set(FORM_VALID, mPayerErrors == null || isFormValid(mEditorModel));
+    }
+
+    private void onDone() {
+        if (!isFormValid(mEditorModel)) {
+            // Note: triggering editor error messages and focused field update using temporary
+            // property.
+            // TODO(crbug.com/1435314): remove this temporary logic.
+            mEditorModel.set(FORM_VALID, true);
+            mEditorModel.set(FORM_VALID, false);
+            return;
+        }
+        mEditorModel.set(VISIBLE, false);
+
+        String name = null;
+        String phone = null;
+        String email = null;
+        AutofillProfile profile = mContact.getProfile();
+
+        if (mNameField.isPresent()) {
+            name = mNameField.get().get(VALUE);
+            profile.setFullName(name);
+        }
+
+        if (mPhoneField.isPresent()) {
+            phone = mPhoneField.get().get(VALUE);
+            profile.setPhoneNumber(phone);
+        }
+
+        if (mEmailField.isPresent()) {
+            email = mEmailField.get().get(VALUE);
+            profile.setEmailAddress(email);
+        }
+
+        if (mSaveToDisk) {
+            profile.setGUID(PersonalDataManager.getInstance().setProfileToLocal(profile));
+        }
+
+        if (profile.getGUID().isEmpty()) {
+            assert !mSaveToDisk;
+
+            // Set a fake guid for a new temp AutofillProfile.
+            profile.setGUID(UUID.randomUUID().toString());
+        }
+
+        profile.setIsLocal(true);
+        mContact.completeContact(profile.getGUID(), name, phone, email);
+        mDoneCallback.onResult(mContact);
+
+        // Clean up the state of this editor.
+        reset();
+    }
+
+    private void onCancel() {
+        mEditorModel.set(VISIBLE, false);
+
+        mCancelCallback.onResult(mContactNew ? null : mContact);
+
+        // Clean up the state of this editor.
+        reset();
     }
 
     private EditorFieldValidator getPhoneValidator() {
@@ -369,11 +386,6 @@
                                         PhoneNumberUtils.stripSeparators(value));
                     }
                 }
-
-                @Override
-                public boolean isLengthMaximum(@Nullable String value) {
-                    return false;
-                }
             };
         }
         return mPhoneValidator;
@@ -386,11 +398,6 @@
                 public boolean isValid(@Nullable String value) {
                     return value != null && Patterns.EMAIL_ADDRESS.matcher(value).matches();
                 }
-
-                @Override
-                public boolean isLengthMaximum(@Nullable String value) {
-                    return false;
-                }
             };
         }
         return mEmailValidator;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsActivity.java
index 747ed23..78c5a22 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsActivity.java
@@ -75,6 +75,7 @@
 import org.chromium.components.browser_ui.accessibility.AccessibilitySettings;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetControllerFactory;
+import org.chromium.components.browser_ui.bottomsheet.ManagedBottomSheetController;
 import org.chromium.components.browser_ui.modaldialog.AppModalPresenter;
 import org.chromium.components.browser_ui.settings.CustomDividerFragment;
 import org.chromium.components.browser_ui.settings.FragmentSettingsLauncher;
@@ -122,7 +123,7 @@
 
     private ScrimCoordinator mScrim;
 
-    private BottomSheetController mBottomSheetController;
+    private ManagedBottomSheetController mBottomSheetController;
 
     private OneshotSupplierImpl<BottomSheetController> mBottomSheetControllerSupplier =
             new OneshotSupplierImpl<>();
@@ -403,6 +404,14 @@
     }
 
     private void initBackPressHandler() {
+        // Handlers registered last will be called first.
+        registerMainFragmentBackPressHandler();
+        if (ChromeFeatureList.sPrivacyGuidePostMVP.isEnabled()) {
+            registerBottomSheetBackPressHandler();
+        }
+    }
+
+    private void registerMainFragmentBackPressHandler() {
         Fragment activeFragment = getMainFragment();
         if (BackPressManager.isSecondaryActivityEnabled()) {
             if (activeFragment instanceof BackPressHandler) {
@@ -418,6 +427,22 @@
         }
     }
 
+    private void registerBottomSheetBackPressHandler() {
+        if (mBottomSheetController == null) return;
+
+        BackPressHandler bottomSheetBackPressHandler =
+                mBottomSheetController.getBottomSheetBackPressHandler();
+        if (bottomSheetBackPressHandler != null) {
+            if (BackPressManager.isSecondaryActivityEnabled()) {
+                BackPressHelper.create(this, getOnBackPressedDispatcher(),
+                        bottomSheetBackPressHandler, SecondaryActivity.SETTINGS);
+            } else {
+                BackPressHelper.create(this, getOnBackPressedDispatcher(),
+                        mBottomSheetController::handleBackPress, SecondaryActivity.SETTINGS);
+            }
+        }
+    }
+
     @Override
     public void onAttachFragment(Fragment fragment) {
         if (fragment instanceof ProfileDependentSetting) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/FakePasswordManagerHandler.java b/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/FakePasswordManagerHandler.java
index 5ea4ab7c..d527978e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/FakePasswordManagerHandler.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/FakePasswordManagerHandler.java
@@ -4,12 +4,14 @@
 
 package org.chromium.chrome.browser.password_manager.settings;
 
+import android.app.Activity;
 import android.content.Context;
 
 import androidx.annotation.Nullable;
 
 import org.chromium.base.Callback;
 import org.chromium.base.IntStringCallback;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.components.browser_ui.settings.SettingsLauncher;
 
 import java.util.ArrayList;
@@ -38,7 +40,7 @@
     @Nullable
     private String mExportTargetPath;
 
-    private boolean mShouldShowWarning;
+    private boolean mShowWarningWasCalled;
 
     private int mSerializationInvocationCount;
 
@@ -49,11 +51,6 @@
     void setSavedPasswordExceptions(ArrayList<String> savedPasswordExceptions) {
         mSavedPasswordExeptions = savedPasswordExceptions;
     }
-
-    void setShouldShowWarning(boolean shouldShowWarning) {
-        mShouldShowWarning = shouldShowWarning;
-    }
-
     IntStringCallback getExportSuccessCallback() {
         return mExportSuccessCallback;
     }
@@ -66,6 +63,10 @@
         return mExportTargetPath;
     }
 
+    boolean wasShowWarningCalled() {
+        return mShowWarningWasCalled;
+    }
+
     /**
      * Constructor.
      * @param observer The only observer.
@@ -122,10 +123,10 @@
             Context context, SettingsLauncher launcher, int index, boolean isBlockedCredential) {
         assert false : "Define this method before starting to use it in tests.";
     }
-
     @Override
-    public boolean shouldShowMigrationWarning() {
-        return mShouldShowWarning;
+    public void showMigrationWarning(
+            Activity activity, BottomSheetController bottomSheetController) {
+        mShowWarningWasCalled = true;
     }
 
     public int getSerializationInvocationCount() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettingsTest.java
index 73aacff..a42751a5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettingsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettingsTest.java
@@ -4,13 +4,13 @@
 
 package org.chromium.chrome.browser.password_manager.settings;
 
-import static androidx.test.espresso.matcher.ViewMatchers.withId;
 import static androidx.test.espresso.matcher.ViewMatchers.withText;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.when;
 
 import static org.chromium.ui.test.util.ViewUtils.onViewWaiting;
-import static org.chromium.ui.test.util.ViewUtils.waitForView;
 
 import androidx.test.filters.MediumTest;
 import androidx.test.filters.SmallTest;
@@ -47,7 +47,6 @@
 import org.chromium.components.sync.SyncService;
 import org.chromium.components.user_prefs.UserPrefs;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
-import org.chromium.ui.test.util.ViewUtils;
 
 /**
  * Tests for the "Passwords" settings screen. These tests are not batchable (without significant
@@ -139,16 +138,16 @@
             ChromeSwitchPreference onOffSwitch =
                     (ChromeSwitchPreference) savedPasswordPrefs.findPreference(
                             PasswordSettings.PREF_SAVE_PASSWORDS_SWITCH);
-            Assert.assertTrue(onOffSwitch.isChecked());
+            assertTrue(onOffSwitch.isChecked());
 
             onOffSwitch.performClick();
-            Assert.assertFalse(getPrefService().getBoolean(Pref.CREDENTIALS_ENABLE_SERVICE));
+            assertFalse(getPrefService().getBoolean(Pref.CREDENTIALS_ENABLE_SERVICE));
             Assert.assertEquals(1,
                     RecordHistogram.getHistogramValueCountForTesting(
                             OFFER_TO_SAVE_PASSWORDS_HISTOGRAM, 0));
 
             onOffSwitch.performClick();
-            Assert.assertTrue(getPrefService().getBoolean(Pref.CREDENTIALS_ENABLE_SERVICE));
+            assertTrue(getPrefService().getBoolean(Pref.CREDENTIALS_ENABLE_SERVICE));
             Assert.assertEquals(1,
                     RecordHistogram.getHistogramValueCountForTesting(
                             OFFER_TO_SAVE_PASSWORDS_HISTOGRAM, 1));
@@ -165,7 +164,7 @@
             ChromeSwitchPreference onOffSwitch =
                     (ChromeSwitchPreference) savedPasswordPrefs.findPreference(
                             PasswordSettings.PREF_SAVE_PASSWORDS_SWITCH);
-            Assert.assertFalse(onOffSwitch.isChecked());
+            assertFalse(onOffSwitch.isChecked());
         });
     }
 
@@ -269,15 +268,15 @@
             ChromeSwitchPreference onOffSwitch =
                     (ChromeSwitchPreference) passwordPrefs.findPreference(
                             PasswordSettings.PREF_AUTOSIGNIN_SWITCH);
-            Assert.assertTrue(onOffSwitch.isChecked());
+            assertTrue(onOffSwitch.isChecked());
 
             onOffSwitch.performClick();
-            Assert.assertFalse(getPrefService().getBoolean(Pref.CREDENTIALS_ENABLE_AUTOSIGNIN));
+            assertFalse(getPrefService().getBoolean(Pref.CREDENTIALS_ENABLE_AUTOSIGNIN));
             Assert.assertEquals(
                     1, RecordHistogram.getHistogramValueCountForTesting(AUTO_SIGNIN_HISTOGRAM, 0));
 
             onOffSwitch.performClick();
-            Assert.assertTrue(getPrefService().getBoolean(Pref.CREDENTIALS_ENABLE_AUTOSIGNIN));
+            assertTrue(getPrefService().getBoolean(Pref.CREDENTIALS_ENABLE_AUTOSIGNIN));
             Assert.assertEquals(
                     1, RecordHistogram.getHistogramValueCountForTesting(AUTO_SIGNIN_HISTOGRAM, 1));
 
@@ -292,7 +291,7 @@
             ChromeSwitchPreference onOffSwitch =
                     (ChromeSwitchPreference) passwordPrefs.findPreference(
                             PasswordSettings.PREF_AUTOSIGNIN_SWITCH);
-            Assert.assertFalse(onOffSwitch.isChecked());
+            assertFalse(onOffSwitch.isChecked());
         });
     }
 
@@ -342,12 +341,10 @@
     @Feature({"Preferences"})
     public void testLocalPasswordsMigrationSheetTriggeredWhenShouldShow() {
         mTestHelper.setPasswordSourceWithMultipleEntries(PasswordSettingsTestHelper.GREEK_GODS);
+        assertFalse(mTestHelper.getHandler().wasShowWarningCalled());
         SettingsActivity activity = mTestHelper.startPasswordSettingsFromMainSettings(
                 mPasswordSettingsActivityTestRule);
-        mTestHelper.getHandler().setShouldShowWarning(true);
-        waitForView(
-                withId(org.chromium.chrome.browser.pwd_migration.R.id.pwd_migration_warning_sheet),
-                ViewUtils.VIEW_VISIBLE);
+        assertTrue(mTestHelper.getHandler().wasShowWarningCalled());
     }
 
     private static PrefService getPrefService() {
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/payments/AddressEditorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/payments/AddressEditorTest.java
index 2c6fb3c..120562b 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/payments/AddressEditorTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/payments/AddressEditorTest.java
@@ -30,9 +30,7 @@
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.ItemType.DROPDOWN;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.ItemType.TEXT_INPUT;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.SHOW_REQUIRED_INDICATOR;
-import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.LENGTH_COUNTER_LIMIT_NONE;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.TEXT_INPUT_TYPE;
-import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.TEXT_LENGTH_COUNTER_LIMIT;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.setDropdownKey;
 
 import android.app.Activity;
@@ -63,6 +61,8 @@
 import org.chromium.chrome.browser.autofill.AutofillProfileBridgeJni;
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
+import org.chromium.chrome.browser.autofill.PhoneNumberUtil;
+import org.chromium.chrome.browser.autofill.PhoneNumberUtilJni;
 import org.chromium.chrome.browser.autofill.editors.EditorDialogView;
 import org.chromium.chrome.browser.autofill.editors.EditorProperties.DropdownKeyValue;
 import org.chromium.chrome.browser.autofill.editors.EditorProperties.TextInputType;
@@ -124,6 +124,8 @@
 
     @Mock
     private AutofillProfileBridge.Natives mAutofillProfileBridgeJni;
+    @Mock
+    private PhoneNumberUtil.Natives mPhoneNumberUtilJni;
 
     @Mock
     private EditorDialogView mEditorDialog;
@@ -160,6 +162,8 @@
         })
                 .when(mAutofillProfileBridgeJni)
                 .getRequiredFields(anyString(), anyList());
+        mJniMocker.mock(PhoneNumberUtilJni.TEST_HOOKS, mPhoneNumberUtilJni);
+        when(mPhoneNumberUtilJni.isPossibleNumber(anyString(), anyString())).thenReturn(true);
 
         mActivity = Robolectric.setupActivity(TestActivity.class);
 
@@ -215,8 +219,8 @@
     }
 
     private static void validateTextField(ListItem fieldItem, String value,
-            @TextInputType int textInputType, String label, boolean isRequired, boolean isFullLine,
-            int lengthCounter) {
+            @TextInputType int textInputType, String label, boolean isRequired,
+            boolean isFullLine) {
         assertEquals(TEXT_INPUT, fieldItem.type);
 
         PropertyModel field = fieldItem.model;
@@ -225,7 +229,6 @@
         assertEquals(label, field.get(LABEL));
         assertEquals(isRequired, field.get(IS_REQUIRED));
         assertEquals(isFullLine, field.get(IS_FULL_LINE));
-        assertEquals(lengthCounter, field.get(TEXT_LENGTH_COUNTER_LIMIT));
     }
 
     private void validateShownFields(PropertyModel editorModel, AutofillProfile profile) {
@@ -247,15 +250,15 @@
         validateTextField(editorFields.get(1), profile.getFullName(),
                 TextInputType.PERSON_NAME_INPUT,
                 /*label=*/"full name label",
-                /*isRequired=*/true, /*isFullLine=*/true, LENGTH_COUNTER_LIMIT_NONE);
+                /*isRequired=*/true, /*isFullLine=*/true);
         validateTextField(editorFields.get(2), profile.getRegion(), TextInputType.REGION_INPUT,
                 /*label=*/"admin area label",
-                /*isRequired=*/true, /*isFullLine=*/true, LENGTH_COUNTER_LIMIT_NONE);
+                /*isRequired=*/true, /*isFullLine=*/true);
         // Locality field is forced to occupy full line.
         validateTextField(editorFields.get(3), profile.getLocality(),
                 TextInputType.PLAIN_TEXT_INPUT,
                 /*label=*/"locality label",
-                /*isRequired=*/true, /*isFullLine=*/true, LENGTH_COUNTER_LIMIT_NONE);
+                /*isRequired=*/true, /*isFullLine=*/true);
 
         // Note: dependent locality is a required field for address profiles stored in Google
         // account, but it's still marked as optional by the editor when the corresponding field in
@@ -263,26 +266,26 @@
         // profiles.
         validateTextField(editorFields.get(4), profile.getDependentLocality(),
                 TextInputType.PLAIN_TEXT_INPUT, /*label=*/"dependent locality label",
-                /*isRequired=*/true, /*isFullLine=*/true, LENGTH_COUNTER_LIMIT_NONE);
+                /*isRequired=*/true, /*isFullLine=*/true);
 
         validateTextField(editorFields.get(5), profile.getCompanyName(),
                 TextInputType.PLAIN_TEXT_INPUT,
                 /*label=*/"organization label",
-                /*isRequired=*/false, /*isFullLine=*/true, LENGTH_COUNTER_LIMIT_NONE);
+                /*isRequired=*/false, /*isFullLine=*/true);
 
         validateTextField(editorFields.get(6), profile.getSortingCode(),
                 TextInputType.ALPHA_NUMERIC_INPUT, /*label=*/"sorting code label",
-                /*isRequired=*/false, /*isFullLine=*/false, LENGTH_COUNTER_LIMIT_NONE);
+                /*isRequired=*/false, /*isFullLine=*/false);
         validateTextField(editorFields.get(7), profile.getPostalCode(),
                 TextInputType.ALPHA_NUMERIC_INPUT, /*label=*/"postal code label",
-                /*isRequired=*/true, /*isFullLine=*/false, LENGTH_COUNTER_LIMIT_NONE);
+                /*isRequired=*/true, /*isFullLine=*/false);
         validateTextField(editorFields.get(8), profile.getStreetAddress(),
                 TextInputType.STREET_ADDRESS_INPUT, /*label=*/"street address label",
-                /*isRequired=*/true, /*isFullLine=*/true, LENGTH_COUNTER_LIMIT_NONE);
+                /*isRequired=*/true, /*isFullLine=*/true);
         validateTextField(editorFields.get(9), profile.getPhoneNumber(),
                 TextInputType.PHONE_NUMBER_INPUT,
                 mActivity.getString(R.string.autofill_profile_editor_phone_number),
-                /*isRequired=*/true, /*isFullLine=*/true, LENGTH_COUNTER_LIMIT_NONE);
+                /*isRequired=*/true, /*isFullLine=*/true);
     }
 
     @Test
@@ -344,7 +347,7 @@
         validateTextField(editorFields.get(1), sProfile.getPhoneNumber(),
                 TextInputType.PHONE_NUMBER_INPUT,
                 mActivity.getString(R.string.autofill_profile_editor_phone_number),
-                /*isRequired=*/true, /*isFullLine=*/true, LENGTH_COUNTER_LIMIT_NONE);
+                /*isRequired=*/true, /*isFullLine=*/true);
     }
 
     @Test
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/payments/ContactEditorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/payments/ContactEditorTest.java
index a1a3f83..0d20f5f 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/payments/ContactEditorTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/payments/ContactEditorTest.java
@@ -19,9 +19,7 @@
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.FieldProperties.VALUE;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.ItemType.TEXT_INPUT;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.SHOW_REQUIRED_INDICATOR;
-import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.LENGTH_COUNTER_LIMIT_NONE;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.TEXT_INPUT_TYPE;
-import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.TEXT_LENGTH_COUNTER_LIMIT;
 
 import android.app.Activity;
 
@@ -97,7 +95,6 @@
         assertEquals(label, field.get(LABEL));
         assertTrue(field.get(IS_REQUIRED));
         assertTrue(field.get(IS_FULL_LINE));
-        assertEquals(LENGTH_COUNTER_LIMIT_NONE, field.get(TEXT_LENGTH_COUNTER_LIMIT));
     }
 
     @Test
@@ -395,7 +392,7 @@
                 /*saveToDisk=*/false);
         editor.setEditorDialog(mEditorDialog);
         AutofillContact contact = new AutofillContact(mActivity, new AutofillProfile(sProfile),
-                null, "Payer phone", null, ContactEditor.COMPLETE, false, true, false);
+                null, "+4900000000000", null, ContactEditor.COMPLETE, false, true, false);
         editor.edit(contact, unused -> {});
 
         PropertyModel editorModel = editor.getEditorModelForTesting();
@@ -403,13 +400,13 @@
 
         ListModel<ListItem> editorFields = editorModel.get(EDITOR_FIELDS);
         assertEquals(1, editorFields.size());
-        editorFields.get(0).model.set(VALUE, "Modified phone");
+        editorFields.get(0).model.set(VALUE, "+490111111111");
         editorModel.get(DONE_RUNNABLE).run();
 
         assertNull(contact.getPayerName());
-        assertEquals("Modified phone", contact.getPayerPhone());
+        assertEquals("+490111111111", contact.getPayerPhone());
         assertNull(contact.getPayerEmail());
-        assertEquals("Modified phone", contact.getProfile().getPhoneNumber());
+        assertEquals("+490111111111", contact.getProfile().getPhoneNumber());
     }
 
     @Test
@@ -421,7 +418,7 @@
                 /*saveToDisk=*/false);
         editor.setEditorDialog(mEditorDialog);
         AutofillContact contact = new AutofillContact(mActivity, new AutofillProfile(sProfile),
-                null, null, "Payer email", ContactEditor.COMPLETE, false, false, true);
+                null, null, "example@gmail.com", ContactEditor.COMPLETE, false, false, true);
         editor.edit(contact, unused -> {});
 
         PropertyModel editorModel = editor.getEditorModelForTesting();
@@ -429,13 +426,13 @@
 
         ListModel<ListItem> editorFields = editorModel.get(EDITOR_FIELDS);
         assertEquals(1, editorFields.size());
-        editorFields.get(0).model.set(VALUE, "Modified email");
+        editorFields.get(0).model.set(VALUE, "modified@gmail.com");
         editorModel.get(DONE_RUNNABLE).run();
 
         assertNull(contact.getPayerName());
         assertNull(contact.getPayerPhone());
-        assertEquals("Modified email", contact.getPayerEmail());
-        assertEquals("Modified email", contact.getProfile().getEmailAddress());
+        assertEquals("modified@gmail.com", contact.getPayerEmail());
+        assertEquals("modified@gmail.com", contact.getProfile().getEmailAddress());
     }
 
     @Test
@@ -446,9 +443,9 @@
                 /*requestPayerEmail=*/true,
                 /*saveToDisk=*/false);
         editor.setEditorDialog(mEditorDialog);
-        AutofillContact contact =
-                new AutofillContact(mActivity, new AutofillProfile(sProfile), "Payer name",
-                        "Payer phone", "Payer email", ContactEditor.COMPLETE, true, true, true);
+        AutofillContact contact = new AutofillContact(mActivity, new AutofillProfile(sProfile),
+                "Payer name", "+4900000000000", "example@gmail.com", ContactEditor.COMPLETE, true,
+                true, true);
         editor.edit(contact, unused -> {});
 
         PropertyModel editorModel = editor.getEditorModelForTesting();
@@ -457,15 +454,15 @@
         ListModel<ListItem> editorFields = editorModel.get(EDITOR_FIELDS);
         assertEquals(3, editorFields.size());
         editorFields.get(0).model.set(VALUE, "Modified name");
-        editorFields.get(1).model.set(VALUE, "Modified phone");
-        editorFields.get(2).model.set(VALUE, "Modified email");
+        editorFields.get(1).model.set(VALUE, "+490111111111");
+        editorFields.get(2).model.set(VALUE, "modified@gmail.com");
         editorModel.get(DONE_RUNNABLE).run();
 
         assertEquals("Modified name", contact.getPayerName());
-        assertEquals("Modified phone", contact.getPayerPhone());
-        assertEquals("Modified email", contact.getPayerEmail());
+        assertEquals("+490111111111", contact.getPayerPhone());
+        assertEquals("modified@gmail.com", contact.getPayerEmail());
         assertEquals("Modified name", contact.getProfile().getFullName());
-        assertEquals("Modified phone", contact.getProfile().getPhoneNumber());
-        assertEquals("Modified email", contact.getProfile().getEmailAddress());
+        assertEquals("+490111111111", contact.getProfile().getPhoneNumber());
+        assertEquals("modified@gmail.com", contact.getProfile().getEmailAddress());
     }
 }
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index f077884..c1339efe 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -9327,6 +9327,14 @@
         (Chrome error pages)
       </message>
 
+      <!-- TODO(crbug.com/1433644): Add final string. -->
+      <message name="IDS_STORAGE_ACCESS_MANAGE_TEXT" translateable="false" desc="The text on the button to manage the StorageAcccess permission. The StorageAccess API is called 'Embedded content' in user visible UIs">
+        Embedded content settings
+      </message>
+      <message name="IDS_STORAGE_ACCESS_MANAGE_TOOLTIP"  translateable="false" desc="The tooltip on the button to manage the StorageAcccess permission. The StorageAccess API is called 'Embedded content' in user visible UIs">
+        Go to embedded content settings
+      </message>
+
       <!-- Automatic updates -->
       <if expr="is_macosx">
         <message name="IDS_PROMOTE_INFOBAR_TEXT" desc="The text to show in the automatic update setup infobar.  Mac-only.">
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 2c25378..51777c8 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -321,6 +321,8 @@
     "component_updater/desktop_sharing_hub_component_remover.h",
     "component_updater/first_party_sets_component_installer.cc",
     "component_updater/first_party_sets_component_installer.h",
+    "component_updater/masked_domain_list_component_installer.cc",
+    "component_updater/masked_domain_list_component_installer.h",
     "component_updater/mei_preload_component_installer.cc",
     "component_updater/mei_preload_component_installer.h",
     "component_updater/pki_metadata_component_installer.cc",
@@ -742,6 +744,8 @@
     "media/webrtc/desktop_media_picker_manager.h",
     "media/webrtc/media_capture_devices_dispatcher.cc",
     "media/webrtc/media_capture_devices_dispatcher.h",
+    "media/webrtc/media_device_salt_service_factory.cc",
+    "media/webrtc/media_device_salt_service_factory.h",
     "media/webrtc/media_stream_capture_indicator.cc",
     "media/webrtc/media_stream_capture_indicator.h",
     "media/webrtc/media_stream_device_permission_context.cc",
diff --git a/chrome/browser/ash/login/oobe_quick_start/second_device_auth_broker.cc b/chrome/browser/ash/login/oobe_quick_start/second_device_auth_broker.cc
index 9edc916..5f10d9d461 100644
--- a/chrome/browser/ash/login/oobe_quick_start/second_device_auth_broker.cc
+++ b/chrome/browser/ash/login/oobe_quick_start/second_device_auth_broker.cc
@@ -80,14 +80,8 @@
 constexpr char kHttpMethod[] = "POST";
 constexpr char kHttpContentType[] = "application/json";
 
-constexpr char kGetChallengeDataRequest[] = R"(
-    {
-      "target_device_type": "CHROME_OS",
-      "target_droidguard_data": {
-        "target_droidguard_response": "1",
-        "device_id": "1",
-        "timestamp": "1"
-      }
+constexpr char kGetChallengeDataRequest[] = R"({
+      "target_device_type": "CHROME_OS"
     })";
 
 constexpr auto kRejectionReasonErrorMap = base::MakeFixedFlatMap<
diff --git a/chrome/browser/ash/login/screens/gaia_screen.cc b/chrome/browser/ash/login/screens/gaia_screen.cc
index d41a9bd4..3d67028 100644
--- a/chrome/browser/ash/login/screens/gaia_screen.cc
+++ b/chrome/browser/ash/login/screens/gaia_screen.cc
@@ -13,7 +13,11 @@
 #include "base/values.h"
 #include "chrome/browser/ash/login/ui/login_display_host.h"
 #include "chrome/browser/ash/login/wizard_context.h"
+#include "chrome/browser/ash/policy/core/browser_policy_connector_ash.h"
+#include "chrome/browser/ash/settings/cros_settings.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
+#include "chrome/browser/enterprise/util/managed_browser_utils.h"
 #include "chrome/browser/ui/webui/ash/login/gaia_screen_handler.h"
 #include "components/account_id/account_id.h"
 #include "components/user_manager/known_user.h"
@@ -28,6 +32,7 @@
 constexpr char kUserActionStartEnrollment[] = "startEnrollment";
 constexpr char kUserActionReloadDefault[] = "reloadDefault";
 constexpr char kUserActionRetry[] = "retry";
+constexpr char kUserActionEnterIdentifier[] = "identifierEntered";
 
 bool ShouldPrepareForRecovery(const AccountId& account_id) {
   if (!features::IsCryptohomeRecoveryEnabled() || !account_id.is_valid()) {
@@ -198,6 +203,10 @@
     LoadOnline(EmptyAccountId());
   } else if (action_id == kUserActionRetry) {
     LoadOnline(EmptyAccountId());
+  } else if (action_id == kUserActionEnterIdentifier) {
+    CHECK_EQ(2u, args.size());
+    const std::string& email = args[1].GetString();
+    HandleIdentifierEntered(email);
   } else {
     BaseScreen::OnUserAction(args);
   }
@@ -222,6 +231,16 @@
   exit_callback_.Run(Result::CANCEL);
 }
 
+void GaiaScreen::HandleIdentifierEntered(const std::string& user_email) {
+  if (MaybeTriggerEnrollmentNudge(user_email)) {
+    return;
+  }
+
+  if (view_) {
+    view_->CheckIfAllowlisted(user_email);
+  }
+}
+
 void GaiaScreen::OnGetAuthFactorsConfiguration(
     std::unique_ptr<UserContext> user_context,
     absl::optional<AuthenticationError> error) {
@@ -260,4 +279,43 @@
   view_->LoadGaiaAsync(account);
 }
 
+bool GaiaScreen::MaybeTriggerEnrollmentNudge(const std::string& user_email) {
+  const bool is_enterprise_managed = g_browser_process->platform_part()
+                                         ->browser_policy_connector_ash()
+                                         ->IsDeviceEnterpriseManaged();
+  if (is_enterprise_managed) {
+    // Device either already went through enterprise enrollment flow or goes
+    // through it right now. No need for nudging.
+    return false;
+  }
+  const bool is_first_user =
+      user_manager::UserManager::Get()->GetUsers().empty();
+  if (!is_first_user) {
+    // Enrollment nudge targets only initial OOBE flow on unowned devices.
+    // Current user is not a first user which means that device is already
+    // owned.
+    return false;
+  }
+  const std::string email_domain =
+      chrome::enterprise_util::GetDomainFromEmail(user_email);
+  if (chrome::enterprise_util::IsKnownConsumerDomain(email_domain)) {
+    // User doesn't belong to a managed domain, so enrollment nudging can't
+    // apply.
+    return false;
+  }
+
+  // TODO(b/271104781): replace this check with a policy fetch through a special
+  // DM server API when it is available.
+  if (!ash::features::IsEnrollmentNudgingForTestingEnabled()) {
+    return false;
+  }
+
+  if (!view_) {
+    return false;
+  }
+
+  view_->ShowEnrollmentNudge(email_domain);
+  return true;
+}
+
 }  // namespace ash
diff --git a/chrome/browser/ash/login/screens/gaia_screen.h b/chrome/browser/ash/login/screens/gaia_screen.h
index 76821476..3f03bf4 100644
--- a/chrome/browser/ash/login/screens/gaia_screen.h
+++ b/chrome/browser/ash/login/screens/gaia_screen.h
@@ -75,6 +75,7 @@
   void HideImpl() override;
   void OnUserAction(const base::Value::List& args) override;
   bool HandleAccelerator(LoginAcceleratorAction action) override;
+  void HandleIdentifierEntered(const std::string& account_identifier);
 
   void OnGetAuthFactorsConfiguration(std::unique_ptr<UserContext> user_context,
                                      absl::optional<AuthenticationError> error);
@@ -83,6 +84,10 @@
   void OnGaiaReauthTokenFetched(const AccountId& account,
                                 const std::string& token);
 
+  // Triggers the enrollment nudge flow and returns true if all requirements are
+  // met, otherwise does nothing and returns false.
+  bool MaybeTriggerEnrollmentNudge(const std::string& user_email);
+
   AuthFactorEditor auth_factor_editor_;
   std::unique_ptr<GaiaReauthTokenFetcher> gaia_reauth_token_fetcher_;
 
diff --git a/chrome/browser/ash/policy/dlp/files_policy_notification_manager_browsertest.cc b/chrome/browser/ash/policy/dlp/files_policy_notification_manager_browsertest.cc
index 3f5ec021..e59e4510 100644
--- a/chrome/browser/ash/policy/dlp/files_policy_notification_manager_browsertest.cc
+++ b/chrome/browser/ash/policy/dlp/files_policy_notification_manager_browsertest.cc
@@ -640,11 +640,20 @@
   std::unique_ptr<policy::MockDlpFilesControllerAsh> files_controller_;
 };
 
+// TODO(crbug.com/1458326): Re-enable this test
+#if defined(MEMORY_SANITIZER)
+#define MAYBE_MultiFileOKShowsDialogOverFilesApp \
+  DISABLED_MultiFileOKShowsDialogOverFilesApp
+#else
+#define MAYBE_MultiFileOKShowsDialogOverFilesApp \
+  MultiFileOKShowsDialogOverFilesApp
+#endif
+
 // Tests that clicking the OK button on a warning notification shown for copy or
 // move IO task with multiple warning files shows a dialog instead of continuing
 // the action, and opens the Files App only if there's not one opened already.
 IN_PROC_BROWSER_TEST_P(OnIONotificationClickedTest,
-                       MultiFileOKShowsDialogOverFilesApp) {
+                       MAYBE_MultiFileOKShowsDialogOverFilesApp) {
   policy::GetIOTaskController(browser()->profile())->AddObserver(&observer_);
 
   auto [type, action] = GetParam();
diff --git a/chrome/browser/ash/system_web_apps/apps/camera_app/chrome_camera_app_ui_delegate.cc b/chrome/browser/ash/system_web_apps/apps/camera_app/chrome_camera_app_ui_delegate.cc
index 2a0ac63..9318791 100644
--- a/chrome/browser/ash/system_web_apps/apps/camera_app/chrome_camera_app_ui_delegate.cc
+++ b/chrome/browser/ash/system_web_apps/apps/camera_app/chrome_camera_app_ui_delegate.cc
@@ -27,6 +27,7 @@
 #include "chrome/browser/ash/system_web_apps/system_web_app_manager.h"
 #include "chrome/browser/devtools/devtools_window.h"
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
+#include "chrome/browser/media/webrtc/media_device_salt_service_factory.h"
 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/ash/holding_space/holding_space_keyed_service.h"
@@ -521,3 +522,10 @@
   // same sequence.
   storage_monitor_weak_ptr_ = storage_monitor_.get()->GetWeakPtr();
 }
+
+media_device_salt::MediaDeviceSaltService*
+ChromeCameraAppUIDelegate::GetMediaDeviceSaltService(
+    content::BrowserContext* context) {
+  return MediaDeviceSaltServiceFactory::GetInstance()->GetForBrowserContext(
+      context);
+}
diff --git a/chrome/browser/ash/system_web_apps/apps/camera_app/chrome_camera_app_ui_delegate.h b/chrome/browser/ash/system_web_apps/apps/camera_app/chrome_camera_app_ui_delegate.h
index 9b8fce4..033c396 100644
--- a/chrome/browser/ash/system_web_apps/apps/camera_app/chrome_camera_app_ui_delegate.h
+++ b/chrome/browser/ash/system_web_apps/apps/camera_app/chrome_camera_app_ui_delegate.h
@@ -144,6 +144,8 @@
   void StopStorageMonitor() override;
   void OpenStorageManagement() override;
   base::FilePath GetFilePathByName(const std::string& name) override;
+  media_device_salt::MediaDeviceSaltService* GetMediaDeviceSaltService(
+      content::BrowserContext* context) override;
 
  private:
   base::FilePath GetMyFilesFolder();
diff --git a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/AddressEditorCoordinator.java b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/AddressEditorCoordinator.java
index 534187a..6173466 100644
--- a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/AddressEditorCoordinator.java
+++ b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/AddressEditorCoordinator.java
@@ -153,7 +153,7 @@
      * Shows editor dialog to the user.
      */
     public void showEditorDialog() {
-        mEditorModel = mMediator.buildEditorModel();
+        mEditorModel = mMediator.getEditorModel();
         PropertyModelChangeProcessor.create(
                 mEditorModel, mEditorDialog, EditorDialogViewBinder::bindEditorDialogView);
         mEditorModel.set(VISIBLE, true);
diff --git a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/AddressEditorMediator.java b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/AddressEditorMediator.java
index 9237685..da99a626 100644
--- a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/AddressEditorMediator.java
+++ b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/AddressEditorMediator.java
@@ -22,6 +22,7 @@
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.EDITOR_FIELDS;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.EDITOR_TITLE;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.FOOTER_MESSAGE;
+import static org.chromium.chrome.browser.autofill.editors.EditorProperties.FORM_VALID;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.FieldProperties.INVALID_ERROR_MESSAGE;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.FieldProperties.IS_FULL_LINE;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.FieldProperties.IS_REQUIRED;
@@ -32,18 +33,17 @@
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.ItemType.DROPDOWN;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.ItemType.TEXT_INPUT;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.SHOW_REQUIRED_INDICATOR;
-import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TRIGGER_DONE_CALLBACK_BEFORE_CLOSE_ANIMATION;
-import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.LENGTH_COUNTER_LIMIT_NONE;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.TEXT_ALL_KEYS;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.TEXT_FORMATTER;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.TEXT_INPUT_TYPE;
-import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.TEXT_LENGTH_COUNTER_LIMIT;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextInputType.ALPHA_NUMERIC_INPUT;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextInputType.EMAIL_ADDRESS_INPUT;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextInputType.PERSON_NAME_INPUT;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextInputType.PHONE_NUMBER_INPUT;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextInputType.PLAIN_TEXT_INPUT;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextInputType.STREET_ADDRESS_INPUT;
+import static org.chromium.chrome.browser.autofill.editors.EditorProperties.VISIBLE;
+import static org.chromium.chrome.browser.autofill.editors.EditorProperties.isFormValid;
 
 import android.content.Context;
 import android.text.TextUtils;
@@ -114,6 +114,9 @@
     private boolean mAllowDelete;
     private boolean mShouldTriggerDoneCallbackBeforeCloseAnimation;
 
+    @Nullable
+    private PropertyModel mEditorModel;
+
     /**
      * The list of possible address fields for editing is determined statically.
      *
@@ -232,7 +235,6 @@
                                 mContext.getString(
                                         R.string.payments_phone_invalid_validation_message))
                         .with(IS_FULL_LINE, true)
-                        .with(TEXT_LENGTH_COUNTER_LIMIT, LENGTH_COUNTER_LIMIT_NONE)
                         .build();
 
         // Phone number is present for all countries.
@@ -246,7 +248,6 @@
                                 mContext.getString(
                                         R.string.payments_email_invalid_validation_message))
                         .with(IS_FULL_LINE, true)
-                        .with(TEXT_LENGTH_COUNTER_LIMIT, LENGTH_COUNTER_LIMIT_NONE)
                         .build();
 
         // TODO(crbug.com/1445020): Use localized string.
@@ -309,8 +310,12 @@
      * [ email address field ] <----- only present if purpose is Purpose.AUTOFILL_SETTINGS.
      * [ address nickname    ] <----- only present if nickname support is enabled.
      */
-    PropertyModel buildEditorModel() {
-        PropertyModel editorModel =
+    PropertyModel getEditorModel() {
+        if (mEditorModel != null) {
+            return mEditorModel;
+        }
+
+        mEditorModel =
                 new PropertyModel.Builder(ALL_KEYS)
                         .with(EDITOR_TITLE, getEditorTitle())
                         .with(CUSTOM_DONE_BUTTON_TEXT, mCustomDoneButtonText)
@@ -318,8 +323,6 @@
                         .with(DELETE_CONFIRMATION_TITLE, getDeleteConfirmationTitle())
                         .with(DELETE_CONFIRMATION_TEXT, getDeleteConfirmationText())
                         .with(SHOW_REQUIRED_INDICATOR, false)
-                        .with(TRIGGER_DONE_CALLBACK_BEFORE_CLOSE_ANIMATION,
-                                mShouldTriggerDoneCallbackBeforeCloseAnimation)
                         .with(EDITOR_FIELDS,
                                 buildEditorFieldList(AutofillAddress.getCountryCode(mProfileToEdit),
                                         mProfileToEdit.getLanguageCode()))
@@ -327,9 +330,10 @@
                         // If the user clicks [Cancel], send |toEdit| address back to the caller,
                         // which was the original state (could be null, a complete address, a
                         // partial address).
-                        .with(CANCEL_RUNNABLE, mDelegate::onCancel)
+                        .with(CANCEL_RUNNABLE, this::onCancelEditing)
                         .with(ALLOW_DELETE, mAllowDelete)
                         .with(DELETE_RUNNABLE, () -> mDelegate.onDelete(mAddressToEdit))
+                        .with(FORM_VALID, true)
                         .build();
 
         mCountryField.set(DROPDOWN_CALLBACK, new Callback<String>() {
@@ -338,7 +342,7 @@
              */
             @Override
             public void onResult(String countryCode) {
-                editorModel.set(EDITOR_FIELDS,
+                mEditorModel.set(EDITOR_FIELDS,
                         buildEditorFieldList(countryCode, Locale.getDefault().getLanguage()));
 
                 mPhoneFormatter.setCountryCode(countryCode);
@@ -346,7 +350,7 @@
             }
         });
 
-        return editorModel;
+        return mEditorModel;
     }
 
     private boolean shouldDisplayRequiredErrorIfFieldEmpty(AddressUiComponent component) {
@@ -422,11 +426,17 @@
     }
 
     private void onCommitChanges() {
-        // If the user clicks [Done], save changes on disk, mark the address
-        // "complete" if possible,
-        // and send it back to the caller.
-        commitChanges(mProfileToEdit);
+        if (!isFormValid(mEditorModel)) {
+            // Note: triggering editor error messages and focused field update using temporary
+            // property.
+            // TODO(crbug.com/1435314): remove this temporary logic.
+            mEditorModel.set(FORM_VALID, true);
+            mEditorModel.set(FORM_VALID, false);
+            return;
+        }
+        mEditorModel.set(VISIBLE, false);
 
+        commitChanges(mProfileToEdit);
         // The address cannot be marked "complete" because it has not been
         // checked for all required fields.
         mAddressToEdit.updateAddress(mProfileToEdit);
@@ -434,6 +444,12 @@
         mDelegate.onDone(mAddressToEdit);
     }
 
+    private void onCancelEditing() {
+        mEditorModel.set(VISIBLE, false);
+
+        mDelegate.onCancel();
+    }
+
     /** Saves the edited profile on disk. */
     private void commitChanges(AutofillProfile profile) {
         String country = mCountryField.get(VALUE);
@@ -636,10 +652,5 @@
             return TextUtils.isEmpty(value) ? mAllowEmptyValue
                                             : PhoneNumberUtil.isPossibleNumber(value, mCountryCode);
         }
-
-        @Override
-        public boolean isLengthMaximum(@Nullable String value) {
-            return false;
-        }
     }
 }
diff --git a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/EditorDialogView.java b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/EditorDialogView.java
index 134c3f2..4375f6b 100644
--- a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/EditorDialogView.java
+++ b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/EditorDialogView.java
@@ -56,6 +56,8 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
 
 /**
  * The editor dialog. Can be used for editing contact information, shipping address,
@@ -75,6 +77,7 @@
     /** Duration of the animation to hide the UI. */
     private static final int DIALOG_EXIT_ANIMATION_MS = 195;
 
+    @Nullable
     private static EditorObserverForTest sObserverForTest;
 
     private final Activity mActivity;
@@ -90,7 +93,6 @@
     private final ViewGroup mContentView;
     private final View mFooter;
     private Button mDoneButton;
-    private boolean mFormWasValid;
 
     private Animator mDialogInOutAnimator;
     private boolean mIsDismissed;
@@ -104,7 +106,6 @@
     @Nullable
     private String mDeleteConfirmationText;
 
-    private boolean mTriggerDoneCallbackBeforeCloseAnimation;
     private Runnable mDeleteRunnable;
     private Runnable mDoneRunnable;
     private Runnable mCancelRunnable;
@@ -197,11 +198,6 @@
         mDeleteConfirmationText = deleteConfirmationText;
     }
 
-    public void setShouldTriggerDoneCallbackBeforeCloseAnimation(
-            boolean triggerDoneCallbackBeforeCloseAnimation) {
-        mTriggerDoneCallbackBeforeCloseAnimation = triggerDoneCallbackBeforeCloseAnimation;
-    }
-
     public void setShowRequiredIndicator(boolean showRequiredIndicator) {
         for (FieldView view : mFieldViews) {
             view.setShowRequiredIndicator(showRequiredIndicator);
@@ -245,6 +241,31 @@
         }
     }
 
+    public void findAndScrollToInvalidField() {
+        // Iterate over all the fields to update what errors are displayed, which is necessary
+        // to to clear existing errors on any newly valid fields.
+        mFieldViews.forEach(view -> view.updateDisplayedError(!view.isValid()));
+
+        // Make sure that focus is on an invalid field.
+        @Nullable
+        FieldView focusedField = getTextFieldView(getCurrentFocus());
+        if (focusedField != null && !focusedField.isValid()) {
+            // The focused field is invalid, but it may be scrolled off screen. Scroll to it.
+            focusedField.scrollToAndFocus();
+        } else {
+            // Some fields are invalid, but none of the are focused. Scroll to the first invalid
+            // field and focus it.
+            Optional<FieldView> invalidField =
+                    mFieldViews.stream().filter(view -> !view.isValid()).findAny();
+            assert invalidField.isPresent();
+            invalidField.get().scrollToAndFocus();
+        }
+
+        if (sObserverForTest != null) {
+            sObserverForTest.onEditorValidationError();
+        }
+    }
+
     public void setEditorFields(
             ListModel<ListItem> editorFields, boolean shouldShowRequiredIndicator) {
         prepareEditor(editorFields, shouldShowRequiredIndicator);
@@ -289,12 +310,7 @@
         // Cancel editing when the user hits the back arrow.
         toolbar.setNavigationContentDescription(R.string.cancel);
         toolbar.setNavigationIcon(getTintedBackIcon());
-        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                animateOutDialog();
-            }
-        });
+        toolbar.setNavigationOnClickListener(view -> mCancelRunnable.run());
 
         // The top shadow is handled by the toolbar, so hide the one used in the field editor.
         FadingEdgeScrollView scrollView =
@@ -310,43 +326,8 @@
                 SettingsUtils.getShowShadowOnScrollListener(scrollView, shadow));
     }
 
-    /**
-     * Checks if all of the fields in the form are valid and updates the displayed errors. If there
-     * are any invalid fields, makes sure that one of them is focused. Called when user taps [SAVE].
-     *
-     * @return Whether all fields contain valid information.
-     */
-    public boolean validateForm() {
-        final List<FieldView> invalidViews = getViewsWithInvalidInformation(true);
-
-        // Iterate over all the fields to update what errors are displayed, which is necessary to
-        // to clear existing errors on any newly valid fields.
-        for (int i = 0; i < mFieldViews.size(); i++) {
-            FieldView fieldView = mFieldViews.get(i);
-            fieldView.updateDisplayedError(invalidViews.contains(fieldView));
-        }
-
-        if (!invalidViews.isEmpty()) {
-            // Make sure that focus is on an invalid field.
-            FieldView focusedField = getTextFieldView(getCurrentFocus());
-            if (invalidViews.contains(focusedField)) {
-                // The focused field is invalid, but it may be scrolled off screen. Scroll to it.
-                focusedField.scrollToAndFocus();
-            } else {
-                // Some fields are invalid, but none of the are focused. Scroll to the first invalid
-                // field and focus it.
-                invalidViews.get(0).scrollToAndFocus();
-            }
-        }
-
-        if (!invalidViews.isEmpty() && sObserverForTest != null) {
-            sObserverForTest.onEditorValidationError();
-        }
-
-        return invalidViews.isEmpty();
-    }
-
     /** @return The validatable item for the given view. */
+    @Nullable
     private FieldView getTextFieldView(View v) {
         if (v instanceof TextView && v.getParent() != null && v.getParent() instanceof FieldView) {
             return (FieldView) v.getParent();
@@ -363,16 +344,9 @@
         if (mDialogInOutAnimator != null) return;
 
         if (view.getId() == R.id.editor_dialog_done_button) {
-            if (validateForm()) {
-                if (mTriggerDoneCallbackBeforeCloseAnimation) {
-                    mDoneRunnable.run();
-                }
-                mFormWasValid = true;
-                animateOutDialog();
-                return;
-            }
+            mDoneRunnable.run();
         } else if (view.getId() == R.id.payments_edit_cancel_button) {
-            animateOutDialog();
+            mCancelRunnable.run();
         }
     }
 
@@ -415,14 +389,6 @@
     @Override
     public void onDismiss(DialogInterface dialog) {
         mIsDismissed = true;
-        if (mFormWasValid) {
-            if (!mTriggerDoneCallbackBeforeCloseAnimation) {
-                mDoneRunnable.run();
-            }
-            mFormWasValid = false;
-        } else {
-            mCancelRunnable.run();
-        }
         removeTextChangedListeners();
     }
 
@@ -620,7 +586,9 @@
             // because the user would not learn about the elements that are
             // above the focused field.
             if (!ChromeAccessibilityUtil.get().isAccessibilityEnabled()) {
-                List<FieldView> invalidViews = getViewsWithInvalidInformation(false);
+                List<FieldView> invalidViews = mFieldViews.stream()
+                                                       .filter(view -> !view.isValid())
+                                                       .collect(Collectors.toList());
                 if (!invalidViews.isEmpty()) {
                     // Immediately focus the first invalid field to make it faster to edit.
                     invalidViews.get(0).scrollToAndFocus();
@@ -681,18 +649,6 @@
         }
     }
 
-    private List<FieldView> getViewsWithInvalidInformation(boolean findAll) {
-        List<FieldView> invalidViews = new ArrayList<>();
-        for (int i = 0; i < mFieldViews.size(); i++) {
-            FieldView fieldView = mFieldViews.get(i);
-            if (!fieldView.isValid()) {
-                invalidViews.add(fieldView);
-                if (!findAll) break;
-            }
-        }
-        return invalidViews;
-    }
-
     /** @return The View with all fields of this editor. */
     @VisibleForTesting
     public View getContentViewForTest() {
diff --git a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/EditorDialogViewBinder.java b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/EditorDialogViewBinder.java
index 1146371..bbc6e2d 100644
--- a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/EditorDialogViewBinder.java
+++ b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/EditorDialogViewBinder.java
@@ -14,8 +14,8 @@
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.EDITOR_FIELDS;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.EDITOR_TITLE;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.FOOTER_MESSAGE;
+import static org.chromium.chrome.browser.autofill.editors.EditorProperties.FORM_VALID;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.SHOW_REQUIRED_INDICATOR;
-import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TRIGGER_DONE_CALLBACK_BEFORE_CLOSE_ANIMATION;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.VISIBLE;
 
 import org.chromium.ui.modelutil.PropertyKey;
@@ -46,9 +46,6 @@
             view.setDeleteConfirmationText(model.get(DELETE_CONFIRMATION_TEXT));
         } else if (propertyKey == SHOW_REQUIRED_INDICATOR) {
             view.setShowRequiredIndicator(model.get(SHOW_REQUIRED_INDICATOR));
-        } else if (propertyKey == TRIGGER_DONE_CALLBACK_BEFORE_CLOSE_ANIMATION) {
-            view.setShouldTriggerDoneCallbackBeforeCloseAnimation(
-                    model.get(TRIGGER_DONE_CALLBACK_BEFORE_CLOSE_ANIMATION));
         } else if (propertyKey == EDITOR_FIELDS) {
             view.setEditorFields(model.get(EDITOR_FIELDS), model.get(SHOW_REQUIRED_INDICATOR));
         } else if (propertyKey == DONE_RUNNABLE) {
@@ -61,6 +58,10 @@
             view.setDeleteRunnable(model.get(DELETE_RUNNABLE));
         } else if (propertyKey == VISIBLE) {
             view.setVisible(model.get(VISIBLE));
+        } else if (propertyKey == FORM_VALID) {
+            if (!model.get(FORM_VALID)) {
+                view.findAndScrollToInvalidField();
+            }
         } else {
             assert false : "Unhandled update to property:" + propertyKey;
         }
diff --git a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/EditorProperties.java b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/EditorProperties.java
index 0236954..39f0c65 100644
--- a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/EditorProperties.java
+++ b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/EditorProperties.java
@@ -49,15 +49,6 @@
             new PropertyModel.ReadableObjectPropertyKey<>("delete_confirmation_text");
     public static final PropertyModel.ReadableBooleanPropertyKey SHOW_REQUIRED_INDICATOR =
             new PropertyModel.ReadableBooleanPropertyKey("show_required_indicator");
-    /**
-     * If true, done callback is triggered immediately after the user clicked
-     * on the done button. Otherwise, by default, it is triggered only after the dialog is
-     * dismissed with animation.
-     */
-    public static final PropertyModel
-            .ReadableBooleanPropertyKey TRIGGER_DONE_CALLBACK_BEFORE_CLOSE_ANIMATION =
-            new PropertyModel.ReadableBooleanPropertyKey(
-                    "trigger_done_callback_before_close_animation");
 
     public static final PropertyModel.WritableObjectPropertyKey<ListModel<ListItem>> EDITOR_FIELDS =
             new PropertyModel.WritableObjectPropertyKey<>("editor_fields");
@@ -74,11 +65,18 @@
 
     public static final PropertyModel.WritableBooleanPropertyKey VISIBLE =
             new PropertyModel.WritableBooleanPropertyKey("visible");
+    /**
+     * This property is temporary way to trigger field error message update process.
+     * It also triggers field focus update.
+     * TODO(crbug.com/1435314): remove this property once fields are updated through MCP.
+     */
+    public static final PropertyModel.WritableBooleanPropertyKey FORM_VALID =
+            new PropertyModel.WritableBooleanPropertyKey("form_valid");
 
     public static final PropertyKey[] ALL_KEYS = {EDITOR_TITLE, CUSTOM_DONE_BUTTON_TEXT,
             FOOTER_MESSAGE, DELETE_CONFIRMATION_TITLE, DELETE_CONFIRMATION_TEXT,
-            SHOW_REQUIRED_INDICATOR, TRIGGER_DONE_CALLBACK_BEFORE_CLOSE_ANIMATION, EDITOR_FIELDS,
-            DONE_RUNNABLE, CANCEL_RUNNABLE, ALLOW_DELETE, DELETE_RUNNABLE, VISIBLE};
+            SHOW_REQUIRED_INDICATOR, EDITOR_FIELDS, DONE_RUNNABLE, CANCEL_RUNNABLE, ALLOW_DELETE,
+            DELETE_RUNNABLE, VISIBLE, FORM_VALID};
 
     private EditorProperties() {}
 
@@ -132,15 +130,6 @@
          * @return True if the value is valid.
          */
         boolean isValid(@Nullable String value);
-
-        /**
-         * Called to check whether the length of the field value is maximum.
-         *
-         * @param value The value of the field to check.
-         * @return True if the field value length is maximum among all the possible valid values in
-         *         this field.
-         */
-        boolean isLengthMaximum(@Nullable String value);
     }
 
     /**
@@ -222,23 +211,17 @@
      * Properties specific for the text fields.
      */
     public static class TextFieldProperties {
-        /* Indicates that the length counter is disabled. */
-        public static final int LENGTH_COUNTER_LIMIT_NONE = 0;
-
         public static final PropertyModel.ReadableIntPropertyKey TEXT_INPUT_TYPE =
                 new PropertyModel.ReadableIntPropertyKey("text_input_type");
         public static final PropertyModel.WritableObjectPropertyKey<List<String>> TEXT_SUGGESTIONS =
                 new PropertyModel.WritableObjectPropertyKey<>("suggestions");
         public static final PropertyModel.ReadableObjectPropertyKey<TextWatcher> TEXT_FORMATTER =
                 new PropertyModel.ReadableObjectPropertyKey<>("formatter");
-        public static final PropertyModel.ReadableIntPropertyKey TEXT_LENGTH_COUNTER_LIMIT =
-                new PropertyModel.ReadableIntPropertyKey("length_counter_limit");
 
         public static final PropertyKey[] TEXT_SPECIFIC_KEYS = {
                 TEXT_INPUT_TYPE,
                 TEXT_SUGGESTIONS,
                 TEXT_FORMATTER,
-                TEXT_LENGTH_COUNTER_LIMIT,
         };
 
         public static final PropertyKey[] TEXT_ALL_KEYS =
@@ -283,11 +266,6 @@
         }
     }
 
-    public static boolean hasMaximumLength(PropertyModel textField) {
-        EditorFieldValidator validator = textField.get(FieldProperties.VALIDATOR);
-        return validator != null && validator.isLengthMaximum(textField.get(FieldProperties.VALUE));
-    }
-
     public static @Nullable String getValidationErrorMessage(PropertyModel textField) {
         final String customErrorMessage = textField.get(FieldProperties.CUSTOM_ERROR_MESSAGE);
         if (!TextUtils.isEmpty(customErrorMessage)) {
@@ -308,6 +286,15 @@
         return null;
     }
 
+    public static boolean isFormValid(PropertyModel editorModel) {
+        for (ListItem item : editorModel.get(EditorProperties.EDITOR_FIELDS)) {
+            if (!isFieldValid(item.model)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     public static boolean isFieldValid(PropertyModel textField) {
         return getValidationErrorMessage(textField) == null;
     }
diff --git a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/TextFieldView.java b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/TextFieldView.java
index 0eddb91..88c0954e 100644
--- a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/TextFieldView.java
+++ b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/TextFieldView.java
@@ -8,10 +8,8 @@
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.FieldProperties.IS_REQUIRED;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.FieldProperties.LABEL;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.FieldProperties.VALUE;
-import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.LENGTH_COUNTER_LIMIT_NONE;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.TEXT_FORMATTER;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.TEXT_INPUT_TYPE;
-import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.TEXT_LENGTH_COUNTER_LIMIT;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.TEXT_SUGGESTIONS;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextInputType.ALPHA_NUMERIC_INPUT;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextInputType.EMAIL_ADDRESS_INPUT;
@@ -20,19 +18,16 @@
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextInputType.REGION_INPUT;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextInputType.STREET_ADDRESS_INPUT;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.getValidationErrorMessage;
-import static org.chromium.chrome.browser.autofill.editors.EditorProperties.hasMaximumLength;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.isFieldValid;
 
 import android.content.Context;
 import android.text.Editable;
-import android.text.InputFilter;
 import android.text.InputType;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.ArrayAdapter;
 import android.widget.AutoCompleteTextView;
@@ -115,10 +110,6 @@
                     // Show no errors until the user has already tried to edit the field once.
                     updateDisplayedError(!isFieldValid(mEditorFieldModel));
                 }
-
-                if (mEditorFieldModel.get(TEXT_LENGTH_COUNTER_LIMIT) != LENGTH_COUNTER_LIMIT_NONE) {
-                    mInputLayout.setCounterEnabled(hasFocus);
-                }
             }
         });
 
@@ -131,13 +122,6 @@
                 if (sObserverForTest != null) {
                     sObserverForTest.onEditorTextUpdate();
                 }
-                if (!hasMaximumLength(mEditorFieldModel)) return;
-                updateDisplayedError(true);
-                if (isValid()) {
-                    // Simulate editor action to select next selectable field.
-                    mEditorActionListener.onEditorAction(mInput, EditorInfo.IME_ACTION_NEXT,
-                            new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));
-                }
             }
 
             @Override
@@ -157,13 +141,6 @@
             mInput.setThreshold(0);
         }
 
-        final int lengthCounter = mEditorFieldModel.get(TEXT_LENGTH_COUNTER_LIMIT);
-        if (lengthCounter != LENGTH_COUNTER_LIMIT_NONE) {
-            // Limit input length for field and counter.
-            mInput.setFilters(new InputFilter[] {new InputFilter.LengthFilter(lengthCounter)});
-            mInputLayout.setCounterMaxLength(lengthCounter);
-        }
-
         if (mEditorFieldModel.get(TEXT_FORMATTER) != null) {
             mInput.addTextChangedListener(mEditorFieldModel.get(TEXT_FORMATTER));
             mEditorFieldModel.get(TEXT_FORMATTER).afterTextChanged(mInput.getText());
diff --git a/chrome/browser/autofill/android/junit/src/org/chromium/chrome/browser/autofill/editors/AddressEditorTest.java b/chrome/browser/autofill/android/junit/src/org/chromium/chrome/browser/autofill/editors/AddressEditorTest.java
index 218f1ef..e5b5a68e 100644
--- a/chrome/browser/autofill/android/junit/src/org/chromium/chrome/browser/autofill/editors/AddressEditorTest.java
+++ b/chrome/browser/autofill/android/junit/src/org/chromium/chrome/browser/autofill/editors/AddressEditorTest.java
@@ -35,9 +35,7 @@
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.ItemType.DROPDOWN;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.ItemType.TEXT_INPUT;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.SHOW_REQUIRED_INDICATOR;
-import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.LENGTH_COUNTER_LIMIT_NONE;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.TEXT_INPUT_TYPE;
-import static org.chromium.chrome.browser.autofill.editors.EditorProperties.TextFieldProperties.TEXT_LENGTH_COUNTER_LIMIT;
 import static org.chromium.chrome.browser.autofill.editors.EditorProperties.setDropdownKey;
 
 import android.app.Activity;
@@ -69,6 +67,8 @@
 import org.chromium.chrome.browser.autofill.AutofillProfileBridgeJni;
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
+import org.chromium.chrome.browser.autofill.PhoneNumberUtil;
+import org.chromium.chrome.browser.autofill.PhoneNumberUtilJni;
 import org.chromium.chrome.browser.autofill.Source;
 import org.chromium.chrome.browser.autofill.editors.AddressEditorCoordinator.Delegate;
 import org.chromium.chrome.browser.autofill.editors.EditorProperties.DropdownKeyValue;
@@ -157,6 +157,8 @@
 
     @Mock
     private AutofillProfileBridge.Natives mAutofillProfileBridgeJni;
+    @Mock
+    private PhoneNumberUtil.Natives mPhoneNumberUtilJni;
 
     @Mock
     private EditorDialogView mEditorDialog;
@@ -207,6 +209,8 @@
         })
                 .when(mAutofillProfileBridgeJni)
                 .getRequiredFields(anyString(), anyList());
+        mJniMocker.mock(PhoneNumberUtilJni.TEST_HOOKS, mPhoneNumberUtilJni);
+        when(mPhoneNumberUtilJni.isPossibleNumber(anyString(), anyString())).thenReturn(true);
 
         IdentityServicesProvider.setInstanceForTests(mIdentityServicesProvider);
         when(mIdentityServicesProvider.getIdentityManager(mProfile)).thenReturn(mIdentityManager);
@@ -273,8 +277,8 @@
     }
 
     private static void validateTextField(ListItem fieldItem, String value,
-            @TextInputType int textInputType, String label, boolean isRequired, boolean isFullLine,
-            int lengthCounter) {
+            @TextInputType int textInputType, String label, boolean isRequired,
+            boolean isFullLine) {
         Assert.assertEquals(TEXT_INPUT, fieldItem.type);
 
         PropertyModel field = fieldItem.model;
@@ -283,7 +287,6 @@
         Assert.assertEquals(label, field.get(LABEL));
         Assert.assertEquals(isRequired, field.get(IS_REQUIRED));
         Assert.assertEquals(isFullLine, field.get(IS_FULL_LINE));
-        Assert.assertEquals(lengthCounter, field.get(TEXT_LENGTH_COUNTER_LIMIT));
     }
 
     private static void checkModelHasExpectedValues(PropertyModel editorModel,
@@ -327,17 +330,15 @@
         // Note: honorific prefix always comes before the full name field.
         validateTextField(editorFields.get(1), profile.getHonorificPrefix(),
                 TextInputType.PLAIN_TEXT_INPUT,
-                mActivity.getString(R.string.autofill_profile_editor_honorific_prefix), false, true,
-                LENGTH_COUNTER_LIMIT_NONE);
+                mActivity.getString(R.string.autofill_profile_editor_honorific_prefix), false,
+                true);
         validateTextField(editorFields.get(2), profile.getFullName(),
-                TextInputType.PERSON_NAME_INPUT, "full name label", shouldMarkFieldsRequired, true,
-                LENGTH_COUNTER_LIMIT_NONE);
+                TextInputType.PERSON_NAME_INPUT, "full name label", shouldMarkFieldsRequired, true);
         validateTextField(editorFields.get(3), profile.getRegion(), TextInputType.PLAIN_TEXT_INPUT,
-                "admin area label", false, true, LENGTH_COUNTER_LIMIT_NONE);
+                "admin area label", false, true);
         // Locality field is forced to occupy full line.
         validateTextField(editorFields.get(4), profile.getLocality(),
-                TextInputType.PLAIN_TEXT_INPUT, "locality label", shouldMarkFieldsRequired, true,
-                LENGTH_COUNTER_LIMIT_NONE);
+                TextInputType.PLAIN_TEXT_INPUT, "locality label", shouldMarkFieldsRequired, true);
 
         // Note: dependent locality is a required field for address profiles stored in Google
         // account, but it's still marked as optional by the editor when the corresponding field in
@@ -345,21 +346,19 @@
         // profiles.
         validateTextField(editorFields.get(5), profile.getDependentLocality(),
                 TextInputType.PLAIN_TEXT_INPUT, "dependent locality label",
-                shouldMarkFieldsRequiredWhenAddressFieldEmpty, true, LENGTH_COUNTER_LIMIT_NONE);
+                shouldMarkFieldsRequiredWhenAddressFieldEmpty, true);
 
         validateTextField(editorFields.get(6), profile.getCompanyName(),
-                TextInputType.PLAIN_TEXT_INPUT, "organization label", false, true,
-                LENGTH_COUNTER_LIMIT_NONE);
+                TextInputType.PLAIN_TEXT_INPUT, "organization label", false, true);
 
         validateTextField(editorFields.get(7), profile.getSortingCode(),
-                TextInputType.ALPHA_NUMERIC_INPUT, "sorting code label", false, false,
-                LENGTH_COUNTER_LIMIT_NONE);
+                TextInputType.ALPHA_NUMERIC_INPUT, "sorting code label", false, false);
         validateTextField(editorFields.get(8), profile.getPostalCode(),
                 TextInputType.ALPHA_NUMERIC_INPUT, "postal code label", shouldMarkFieldsRequired,
-                false, LENGTH_COUNTER_LIMIT_NONE);
+                false);
         validateTextField(editorFields.get(9), profile.getStreetAddress(),
                 TextInputType.STREET_ADDRESS_INPUT, "street address label",
-                shouldMarkFieldsRequired, true, LENGTH_COUNTER_LIMIT_NONE);
+                shouldMarkFieldsRequired, true);
     }
 
     @Test
@@ -649,12 +648,10 @@
 
         validateTextField(editorFields.get(1), sLocalProfile.getPhoneNumber(),
                 TextInputType.PHONE_NUMBER_INPUT,
-                mActivity.getString(R.string.autofill_profile_editor_phone_number), false, true,
-                LENGTH_COUNTER_LIMIT_NONE);
+                mActivity.getString(R.string.autofill_profile_editor_phone_number), false, true);
         validateTextField(editorFields.get(2), sLocalProfile.getEmailAddress(),
                 TextInputType.EMAIL_ADDRESS_INPUT,
-                mActivity.getString(R.string.autofill_profile_editor_email_address), false, true,
-                LENGTH_COUNTER_LIMIT_NONE);
+                mActivity.getString(R.string.autofill_profile_editor_email_address), false, true);
     }
 
     @Test
@@ -678,8 +675,8 @@
         // editorFields[3] - nickname field.
         Assert.assertEquals(4, editorFields.size());
 
-        validateTextField(editorFields.get(3), null, TextInputType.PLAIN_TEXT_INPUT, "Label", false,
-                true, LENGTH_COUNTER_LIMIT_NONE);
+        validateTextField(
+                editorFields.get(3), null, TextInputType.PLAIN_TEXT_INPUT, "Label", false, true);
     }
 
     @Test
diff --git a/chrome/browser/background/background_mode_manager.h b/chrome/browser/background/background_mode_manager.h
index 7ea25b0..84eb3b55 100644
--- a/chrome/browser/background/background_mode_manager.h
+++ b/chrome/browser/background/background_mode_manager.h
@@ -413,7 +413,7 @@
 
   // Reference to the ProfileAttributesStorage. It is used to update the
   // background app status of profiles when they open/close background apps.
-  raw_ptr<ProfileAttributesStorage, DanglingUntriaged> profile_storage_;
+  raw_ptr<ProfileAttributesStorage, DanglingAcrossTasks> profile_storage_;
 
   // Registrars for managing our change observers.
   base::CallbackListSubscription on_app_terminating_subscription_;
diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h
index c495d31..15405463 100644
--- a/chrome/browser/browser_process_impl.h
+++ b/chrome/browser/browser_process_impl.h
@@ -269,7 +269,7 @@
   const std::unique_ptr<PrefService> local_state_;
 
   // |metrics_services_manager_| owns this.
-  raw_ptr<ChromeMetricsServicesManagerClient, DanglingUntriaged>
+  raw_ptr<ChromeMetricsServicesManagerClient, DanglingAcrossTasks>
       metrics_services_manager_client_ = nullptr;
 
   // Must be destroyed before |local_state_|.
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
index 2c94cc6..ff6138f 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -52,6 +52,7 @@
 #include "chrome/browser/media/history/media_history_keyed_service.h"
 #include "chrome/browser/media/history/media_history_keyed_service_factory.h"
 #include "chrome/browser/media/media_engagement_service.h"
+#include "chrome/browser/media/webrtc/media_device_salt_service_factory.h"
 #include "chrome/browser/media/webrtc/webrtc_event_log_manager.h"
 #include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
 #include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
@@ -102,7 +103,6 @@
 #include "components/keyed_service/core/service_access_type.h"
 #include "components/language/core/browser/url_language_histogram.h"
 #include "components/media_device_salt/media_device_salt_service.h"
-#include "components/media_device_salt/media_device_salt_service_factory.h"
 #include "components/nacl/browser/nacl_browser.h"
 #include "components/nacl/browser/pnacl_host.h"
 #include "components/no_state_prefetch/browser/no_state_prefetch_manager.h"
@@ -642,8 +642,8 @@
         privacy_sandbox_settings->OnCookiesCleared();
 
       auto* media_device_salt_service =
-          media_device_salt::MediaDeviceSaltServiceFactory::GetInstance()
-              ->GetForBrowserContext(profile_);
+          MediaDeviceSaltServiceFactory::GetInstance()->GetForBrowserContext(
+              profile_);
       if (media_device_salt_service) {
         media_device_salt_service->ResetSalt();
       }
diff --git a/chrome/browser/captive_portal/captive_portal_browsertest.cc b/chrome/browser/captive_portal/captive_portal_browsertest.cc
index eb6a13e..ba9ba6c 100644
--- a/chrome/browser/captive_portal/captive_portal_browsertest.cc
+++ b/chrome/browser/captive_portal/captive_portal_browsertest.cc
@@ -2037,9 +2037,8 @@
   EXPECT_EQ(1, login_tab_index);
   content::WebContentsDestroyedWatcher destroyed_watcher(
       tab_strip_model->GetActiveWebContents());
-  EXPECT_EQ(2, tab_strip_model->count());
-  tab_strip_model->CloseWebContentsAt(tab_strip_model->active_index(), 0);
-  EXPECT_EQ(1, tab_strip_model->count());
+  EXPECT_TRUE(
+      tab_strip_model->CloseWebContentsAt(tab_strip_model->active_index(), 0));
   destroyed_watcher.Wait();
   MultiNavigationObserver navigation_observer;
   content::ExecuteScriptAsync(rfh, kClickConnectButtonJS);
diff --git a/chrome/browser/chrome_browser_field_trials.h b/chrome/browser/chrome_browser_field_trials.h
index 15457d1..cccb243 100644
--- a/chrome/browser/chrome_browser_field_trials.h
+++ b/chrome/browser/chrome_browser_field_trials.h
@@ -37,7 +37,7 @@
 
  private:
   // Weak pointer to the local state prefs store.
-  const raw_ptr<PrefService, DanglingUntriaged> local_state_;
+  const raw_ptr<PrefService, DanglingAcrossTasks> local_state_;
 
 #if BUILDFLAG(IS_ANDROID)
   // VariationID to be used for FREMobileIdentityConsistencyFieldTrial.
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index d772f6c3b..6114a4f4 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -85,6 +85,7 @@
 #include "chrome/browser/media/webrtc/capture_policy_utils.h"
 #include "chrome/browser/media/webrtc/chrome_screen_enumerator.h"
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
+#include "chrome/browser/media/webrtc/media_device_salt_service_factory.h"
 #include "chrome/browser/media/webrtc/webrtc_logging_controller.h"
 #include "chrome/browser/memory/chrome_browser_main_extra_parts_memory.h"
 #include "chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.h"
@@ -226,7 +227,6 @@
 #include "components/lens/buildflags.h"
 #include "components/live_caption/caption_util.h"
 #include "components/media_device_salt/media_device_salt_service.h"
-#include "components/media_device_salt/media_device_salt_service_factory.h"
 #include "components/media_router/browser/presentation/presentation_service_delegate_impl.h"
 #include "components/media_router/browser/presentation/receiver_presentation_service_delegate_impl.h"
 #include "components/media_router/browser/presentation/web_contents_presentation_manager.h"
@@ -7204,8 +7204,8 @@
       url, site_for_cookies, top_frame_origin,
       cookie_settings->SettingOverridesForStorage());
   media_device_salt::MediaDeviceSaltService* salt_service =
-      media_device_salt::MediaDeviceSaltServiceFactory::GetInstance()
-          ->GetForBrowserContext(browser_context);
+      MediaDeviceSaltServiceFactory::GetInstance()->GetForBrowserContext(
+          browser_context);
   if (!salt_service) {
     std::move(callback).Run(allowed, browser_context->UniqueId());
     return;
diff --git a/chrome/browser/chrome_multiprofile_startup_browsertest.cc b/chrome/browser/chrome_multiprofile_startup_browsertest.cc
index 7bd71a0..38e91c1e 100644
--- a/chrome/browser/chrome_multiprofile_startup_browsertest.cc
+++ b/chrome/browser/chrome_multiprofile_startup_browsertest.cc
@@ -159,7 +159,7 @@
     }
   }
 
-  raw_ptr<MockMainExtraParts, DanglingUntriaged> mock_part_;
+  raw_ptr<MockMainExtraParts, DanglingAcrossTasks> mock_part_;
 };
 
 IN_PROC_BROWSER_TEST_P(ChromeMultiProfileStartupBrowserTestBase,
diff --git a/chrome/browser/chromeos/extensions/echo_private/echo_private_apitest.cc b/chrome/browser/chromeos/extensions/echo_private/echo_private_apitest.cc
index f8e2da8d..ed3edb6 100644
--- a/chrome/browser/chromeos/extensions/echo_private/echo_private_apitest.cc
+++ b/chrome/browser/chromeos/extensions/echo_private/echo_private_apitest.cc
@@ -121,9 +121,7 @@
       return false;
     }
 
-    int previous_tab_count = tab_strip->count();
-    tab_strip->CloseWebContentsAt(tab_index, 0);
-    return (previous_tab_count - 1) == tab_strip->count();
+    return tab_strip->CloseWebContentsAt(tab_index, 0);
   }
 
  protected:
diff --git a/chrome/browser/commerce/coupons/coupon_db.h b/chrome/browser/commerce/coupons/coupon_db.h
index 99b1e7e..e2d3e18 100644
--- a/chrome/browser/commerce/coupons/coupon_db.h
+++ b/chrome/browser/commerce/coupons/coupon_db.h
@@ -59,7 +59,7 @@
   void OnOperationFinished(bool success);
 
  private:
-  raw_ptr<SessionProtoDB<coupon_db::CouponContentProto>, DanglingUntriaged>
+  raw_ptr<SessionProtoDB<coupon_db::CouponContentProto>, DanglingAcrossTasks>
       proto_db_;
   base::WeakPtrFactory<CouponDB> weak_ptr_factory_{this};
 };
diff --git a/chrome/browser/component_updater/masked_domain_list_component_installer.cc b/chrome/browser/component_updater/masked_domain_list_component_installer.cc
new file mode 100644
index 0000000..22232f8
--- /dev/null
+++ b/chrome/browser/component_updater/masked_domain_list_component_installer.cc
@@ -0,0 +1,31 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/component_updater/masked_domain_list_component_installer.h"
+
+#include "base/logging.h"
+#include "components/component_updater/installer_policies/masked_domain_list_component_installer_policy.h"
+#include "content/public/browser/network_service_instance.h"
+#include "services/network/public/mojom/network_service.mojom.h"
+
+namespace component_updater {
+
+void RegisterMaskedDomainListComponent(ComponentUpdateService* cus) {
+  if (!MaskedDomainListComponentInstallerPolicy::IsEnabled()) {
+    return;
+  }
+
+  VLOG(1) << "Registering Masked Domain List component.";
+
+  auto policy = std::make_unique<MaskedDomainListComponentInstallerPolicy>(
+      /*on_list_ready=*/base::BindRepeating(
+          [](base::Version version, std::string raw_mdl) {
+            VLOG(1) << "Received Masked Domain List";
+            content::GetNetworkService()->UpdateMaskedDomainList(raw_mdl);
+          }));
+
+  base::MakeRefCounted<ComponentInstaller>(std::move(policy))
+      ->Register(cus, base::OnceClosure(), base::TaskPriority::USER_BLOCKING);
+}
+}  // namespace component_updater
diff --git a/chrome/browser/component_updater/masked_domain_list_component_installer.h b/chrome/browser/component_updater/masked_domain_list_component_installer.h
new file mode 100644
index 0000000..3680232
--- /dev/null
+++ b/chrome/browser/component_updater/masked_domain_list_component_installer.h
@@ -0,0 +1,16 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_COMPONENT_UPDATER_MASKED_DOMAIN_LIST_COMPONENT_INSTALLER_H_
+#define CHROME_BROWSER_COMPONENT_UPDATER_MASKED_DOMAIN_LIST_COMPONENT_INSTALLER_H_
+
+#include "components/component_updater/component_installer.h"
+
+namespace component_updater {
+
+void RegisterMaskedDomainListComponent(ComponentUpdateService* cus);
+
+}
+
+#endif  // CHROME_BROWSER_COMPONENT_UPDATER_MASKED_DOMAIN_LIST_COMPONENT_INSTALLER_H_
diff --git a/chrome/browser/component_updater/masked_domain_list_component_installer_unittest.cc b/chrome/browser/component_updater/masked_domain_list_component_installer_unittest.cc
new file mode 100644
index 0000000..58fceb4
--- /dev/null
+++ b/chrome/browser/component_updater/masked_domain_list_component_installer_unittest.cc
@@ -0,0 +1,69 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/component_updater/masked_domain_list_component_installer.h"
+
+#include "base/check.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/component_updater/mock_component_updater_service.h"
+#include "content/public/browser/network_service_instance.h"
+#include "content/public/test/browser_task_environment.h"
+#include "services/network/network_service.h"
+#include "services/network/public/cpp/features.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace component_updater {
+
+namespace {
+using ::testing::_;
+
+}  // namespace
+
+class MaskedDomainListComponentInstallerPolicyTest : public ::testing::Test {
+ public:
+  MaskedDomainListComponentInstallerPolicyTest() {
+    CHECK(component_install_dir_.CreateUniqueTempDir());
+    content::GetNetworkService();  // Initializes Network Service.
+  }
+
+ protected:
+  content::BrowserTaskEnvironment env_;
+  base::test::ScopedFeatureList scoped_feature_list_;
+
+  base::ScopedTempDir component_install_dir_;
+};
+
+TEST_F(MaskedDomainListComponentInstallerPolicyTest, FeatureDisabled) {
+  scoped_feature_list_.InitAndDisableFeature(
+      network::features::kMaskedDomainList);
+  auto service =
+      std::make_unique<component_updater::MockComponentUpdateService>();
+  EXPECT_CALL(*service, RegisterComponent(_)).Times(0);
+  RegisterMaskedDomainListComponent(service.get());
+
+  env_.RunUntilIdle();
+}
+
+TEST_F(MaskedDomainListComponentInstallerPolicyTest,
+       FeatureEnabled_NoFileExists) {
+  scoped_feature_list_.InitWithFeatures(
+      {network::features::kMaskedDomainList,
+       net::features::kEnableIpProtectionProxy},
+      {});
+  auto service =
+      std::make_unique<component_updater::MockComponentUpdateService>();
+
+  EXPECT_CALL(*service, RegisterComponent(_)).Times(1);
+  RegisterMaskedDomainListComponent(service.get());
+  env_.RunUntilIdle();
+
+  // If no file has been passed, the allow list is not enabled.
+  EXPECT_FALSE(network::NetworkService::GetNetworkServiceForTesting()
+                   ->network_service_proxy_allow_list()
+                   ->IsEnabled());
+}
+
+}  // namespace component_updater
diff --git a/chrome/browser/component_updater/registration.cc b/chrome/browser/component_updater/registration.cc
index cd040d38..00f049e 100644
--- a/chrome/browser/component_updater/registration.cc
+++ b/chrome/browser/component_updater/registration.cc
@@ -27,6 +27,7 @@
 #include "chrome/browser/component_updater/file_type_policies_component_installer.h"
 #include "chrome/browser/component_updater/first_party_sets_component_installer.h"
 #include "chrome/browser/component_updater/hyphenation_component_installer.h"
+#include "chrome/browser/component_updater/masked_domain_list_component_installer.h"
 #include "chrome/browser/component_updater/mei_preload_component_installer.h"
 #include "chrome/browser/component_updater/pki_metadata_component_installer.h"
 #include "chrome/browser/component_updater/privacy_sandbox_attestations_component_installer.h"
@@ -37,7 +38,6 @@
 #include "chrome/common/chrome_paths.h"
 #include "components/component_updater/component_updater_service.h"
 #include "components/component_updater/installer_policies/autofill_states_component_installer.h"
-#include "components/component_updater/installer_policies/masked_domain_list_component_installer.h"
 #include "components/component_updater/installer_policies/on_device_head_suggest_component_installer.h"
 #include "components/component_updater/installer_policies/optimization_hints_component_installer.h"
 #include "components/component_updater/installer_policies/safety_tips_component_installer.h"
diff --git a/chrome/browser/download/bubble/download_bubble_ui_controller.h b/chrome/browser/download/bubble/download_bubble_ui_controller.h
index 452539e5..f293b467 100644
--- a/chrome/browser/download/bubble/download_bubble_ui_controller.h
+++ b/chrome/browser/download/bubble/download_bubble_ui_controller.h
@@ -125,7 +125,7 @@
   // DownloadDisplayController and DownloadBubbleUIController have the same
   // lifetime. Both are owned, constructed together, and destructed together by
   // DownloadToolbarButtonView. If one is valid, so is the other.
-  raw_ptr<DownloadDisplayController, DanglingUntriaged> display_controller_;
+  raw_ptr<DownloadDisplayController, DanglingAcrossTasks> display_controller_;
 
   absl::optional<base::Time> last_partial_view_shown_time_ = absl::nullopt;
 
diff --git a/chrome/browser/download/download_query.cc b/chrome/browser/download/download_query.cc
index 69872aa0..8c18b81 100644
--- a/chrome/browser/download/download_query.cc
+++ b/chrome/browser/download/download_query.cc
@@ -279,7 +279,7 @@
         break;  // break the switch but not the loop
     }
   }
-  CHECK_NE(left->GetId(), right->GetId());
+  CHECK(left == right || left->GetId() != right->GetId());
   return left->GetId() < right->GetId();
 }
 
diff --git a/chrome/browser/enterprise/connectors/reporting/extension_install_event_router.h b/chrome/browser/enterprise/connectors/reporting/extension_install_event_router.h
index af815ab..7226b67bc 100644
--- a/chrome/browser/enterprise/connectors/reporting/extension_install_event_router.h
+++ b/chrome/browser/enterprise/connectors/reporting/extension_install_event_router.h
@@ -38,7 +38,7 @@
   void StartObserving();
 
  private:
-  raw_ptr<RealtimeReportingClient, DanglingUntriaged> reporting_client_ =
+  raw_ptr<RealtimeReportingClient, DanglingAcrossTasks> reporting_client_ =
       nullptr;
   raw_ptr<extensions::ExtensionRegistry, DanglingUntriaged>
       extension_registry_ = nullptr;
diff --git a/chrome/browser/enterprise/idle/idle_service_interactive_uitest.cc b/chrome/browser/enterprise/idle/idle_service_interactive_uitest.cc
index 5bd371b..5254ba3 100644
--- a/chrome/browser/enterprise/idle/idle_service_interactive_uitest.cc
+++ b/chrome/browser/enterprise/idle/idle_service_interactive_uitest.cc
@@ -218,7 +218,7 @@
  private:
   testing::NiceMock<policy::MockConfigurationPolicyProvider>
       policy_providers_[2];
-  raw_ptr<MockIdleTimeProvider, DanglingUntriaged> idle_time_provider_;
+  raw_ptr<MockIdleTimeProvider, DanglingAcrossTasks> idle_time_provider_;
   scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
   std::unique_ptr<ui::test::ScopedIdleProviderForTest> scoped_idle_provider_;
   std::unique_ptr<ScopedKeepAlive> keep_alive_;
diff --git a/chrome/browser/extensions/api/debugger/debugger_apitest.cc b/chrome/browser/extensions/api/debugger/debugger_apitest.cc
index 46b52a82..e0062b9 100644
--- a/chrome/browser/extensions/api/debugger/debugger_apitest.cc
+++ b/chrome/browser/extensions/api/debugger/debugger_apitest.cc
@@ -402,9 +402,7 @@
   EXPECT_EQ(1u, manager3->infobar_count());
 
   // Closing tab should not affect anything.
-  EXPECT_EQ(2, another_browser->tab_strip_model()->count());
-  another_browser->tab_strip_model()->CloseWebContentsAt(1, 0);
-  EXPECT_EQ(1, another_browser->tab_strip_model()->count());
+  ASSERT_TRUE(another_browser->tab_strip_model()->CloseWebContentsAt(1, 0));
   manager3 = nullptr;
   EXPECT_EQ(1u, manager1->infobar_count());
   EXPECT_EQ(1u, manager2->infobar_count());
diff --git a/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.cc b/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.cc
index fe334e2..2a3548fc 100644
--- a/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.cc
+++ b/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.cc
@@ -12,8 +12,8 @@
 #include "base/lazy_instance.h"
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
+#include "chrome/browser/media/webrtc/media_device_salt_service_factory.h"
 #include "components/media_device_salt/media_device_salt_service.h"
-#include "components/media_device_salt/media_device_salt_service_factory.h"
 #include "content/public/browser/audio_service.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
@@ -127,8 +127,8 @@
     base::OnceCallback<void(media::AudioDeviceDescriptions)>
         device_descriptions_callback) {
   media_device_salt::MediaDeviceSaltService* salt_service =
-      media_device_salt::MediaDeviceSaltServiceFactory::GetInstance()
-          ->GetForBrowserContext(browser_context());
+      MediaDeviceSaltServiceFactory::GetInstance()->GetForBrowserContext(
+          browser_context());
   if (!salt_service) {
     GotSalt(is_input_devices, std::move(device_descriptions_callback),
             browser_context()->UniqueId());
diff --git a/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc b/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc
index 50d8c12d..ca8e5d9 100644
--- a/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc
+++ b/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/extensions/component_loader.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
+#include "chrome/browser/media/webrtc/media_device_salt_service_factory.h"
 #include "chrome/browser/media/webrtc/webrtc_log_uploader.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/recently_audible_helper.h"
@@ -31,7 +32,6 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/media_device_salt/media_device_salt_service.h"
-#include "components/media_device_salt/media_device_salt_service_factory.h"
 #include "components/network_session_configurator/common/network_switches.h"
 #include "content/public/browser/audio_service.h"
 #include "content/public/browser/browser_thread.h"
@@ -127,8 +127,8 @@
 
   std::string GetMediaDeviceIDSalt() {
     media_device_salt::MediaDeviceSaltService* salt_service =
-        media_device_salt::MediaDeviceSaltServiceFactory::GetInstance()
-            ->GetForBrowserContext(profile());
+        MediaDeviceSaltServiceFactory::GetInstance()->GetForBrowserContext(
+            profile());
     base::test::TestFuture<const std::string&> future;
     salt_service->GetSalt(future.GetCallback());
     return future.Get();
diff --git a/chrome/browser/extensions/chrome_app_sorting.h b/chrome/browser/extensions/chrome_app_sorting.h
index ebb6b61e..77180ed0 100644
--- a/chrome/browser/extensions/chrome_app_sorting.h
+++ b/chrome/browser/extensions/chrome_app_sorting.h
@@ -184,9 +184,9 @@
 
   const raw_ptr<content::BrowserContext, DanglingUntriaged> browser_context_ =
       nullptr;
-  raw_ptr<const web_app::WebAppRegistrar, DanglingUntriaged>
+  raw_ptr<const web_app::WebAppRegistrar, DanglingAcrossTasks>
       web_app_registrar_ = nullptr;
-  raw_ptr<web_app::WebAppSyncBridge, DanglingUntriaged> web_app_sync_bridge_ =
+  raw_ptr<web_app::WebAppSyncBridge, DanglingAcrossTasks> web_app_sync_bridge_ =
       nullptr;
   base::ScopedObservation<web_app::WebAppRegistrar,
                           web_app::WebAppRegistrarObserver>
diff --git a/chrome/browser/extensions/chrome_content_verifier_delegate.h b/chrome/browser/extensions/chrome_content_verifier_delegate.h
index c9d5c13c0..504291a 100644
--- a/chrome/browser/extensions/chrome_content_verifier_delegate.h
+++ b/chrome/browser/extensions/chrome_content_verifier_delegate.h
@@ -92,7 +92,7 @@
   // Returns information needed for content verification of |extension|.
   VerifyInfo GetVerifyInfo(const Extension& extension) const;
 
-  raw_ptr<content::BrowserContext, DanglingUntriaged> context_;
+  raw_ptr<content::BrowserContext, DanglingAcrossTasks> context_;
   VerifyInfo::Mode default_mode_;
 
   // This maps an extension id to a backoff entry for slowing down
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.cc b/chrome/browser/extensions/chrome_extensions_browser_client.cc
index 3b63061..356f9c4d 100644
--- a/chrome/browser/extensions/chrome_extensions_browser_client.cc
+++ b/chrome/browser/extensions/chrome_extensions_browser_client.cc
@@ -44,6 +44,7 @@
 #include "chrome/browser/extensions/menu_manager.h"
 #include "chrome/browser/extensions/updater/chrome_update_client_config.h"
 #include "chrome/browser/external_protocol/external_protocol_handler.h"
+#include "chrome/browser/media/webrtc/media_device_salt_service_factory.h"
 #include "chrome/browser/net/system_network_context_manager.h"
 #include "chrome/browser/profiles/keep_alive/profile_keep_alive_types.h"
 #include "chrome/browser/profiles/keep_alive/scoped_profile_keep_alive.h"
@@ -971,4 +972,11 @@
   ChromePasswordReuseDetectionManagerClient::CreateForWebContents(web_contents);
 }
 
+media_device_salt::MediaDeviceSaltService*
+ChromeExtensionsBrowserClient::GetMediaDeviceSaltService(
+    content::BrowserContext* context) {
+  return MediaDeviceSaltServiceFactory::GetInstance()->GetForBrowserContext(
+      context);
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.h b/chrome/browser/extensions/chrome_extensions_browser_client.h
index 0cb8f00b..52eed1e 100644
--- a/chrome/browser/extensions/chrome_extensions_browser_client.h
+++ b/chrome/browser/extensions/chrome_extensions_browser_client.h
@@ -253,6 +253,8 @@
           callback) override;
   void CreatePasswordReuseDetectionManager(
       content::WebContents* web_contents) const override;
+  media_device_salt::MediaDeviceSaltService* GetMediaDeviceSaltService(
+      content::BrowserContext* context) override;
 
  private:
   friend struct base::LazyInstanceTraitsBase<ChromeExtensionsBrowserClient>;
diff --git a/chrome/browser/extensions/component_loader.h b/chrome/browser/extensions/component_loader.h
index 01ce06c9..6f88731 100644
--- a/chrome/browser/extensions/component_loader.h
+++ b/chrome/browser/extensions/component_loader.h
@@ -227,7 +227,7 @@
 
   raw_ptr<Profile> profile_;
 
-  raw_ptr<ExtensionSystem, DanglingUntriaged> extension_system_;
+  raw_ptr<ExtensionSystem, DanglingAcrossTasks> extension_system_;
 
   // List of registered component extensions (see mojom::ManifestLocation).
   typedef std::vector<ComponentExtensionInfo> RegisteredComponentExtensions;
diff --git a/chrome/browser/extensions/content_script_apitest.cc b/chrome/browser/extensions/content_script_apitest.cc
index 4d345336..9b67fd3 100644
--- a/chrome/browser/extensions/content_script_apitest.cc
+++ b/chrome/browser/extensions/content_script_apitest.cc
@@ -902,10 +902,8 @@
   // should never get a chance to run (and we shouldn't crash).
   dialog_wait.Run();
   EXPECT_FALSE(listener.was_satisfied());
-  EXPECT_EQ(2, browser()->tab_strip_model()->count());
-  browser()->tab_strip_model()->CloseWebContentsAt(
-      browser()->tab_strip_model()->active_index(), 0);
-  EXPECT_EQ(1, browser()->tab_strip_model()->count());
+  EXPECT_TRUE(browser()->tab_strip_model()->CloseWebContentsAt(
+      browser()->tab_strip_model()->active_index(), 0));
   EXPECT_FALSE(listener.was_satisfied());
 }
 
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h
index 952ff7b..1e890114 100644
--- a/chrome/browser/extensions/extension_service.h
+++ b/chrome/browser/extensions/extension_service.h
@@ -658,7 +658,7 @@
   raw_ptr<Profile> profile_ = nullptr;
 
   // The ExtensionSystem for the profile above.
-  raw_ptr<ExtensionSystem, DanglingUntriaged> system_ = nullptr;
+  raw_ptr<ExtensionSystem, DanglingAcrossTasks> system_ = nullptr;
 
   // Preferences for the owning profile.
   raw_ptr<ExtensionPrefs, DanglingUntriaged> extension_prefs_ = nullptr;
diff --git a/chrome/browser/extensions/extension_util.cc b/chrome/browser/extensions/extension_util.cc
index bf49364..2d0a7b6c 100644
--- a/chrome/browser/extensions/extension_util.cc
+++ b/chrome/browser/extensions/extension_util.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
 #include "chrome/common/extensions/api/url_handlers/url_handlers_parser.h"
 #include "chrome/common/extensions/sync_helper.h"
+#include "components/prefs/pref_service.h"
 #include "components/variations/variations_associated_data.h"
 #include "content/public/browser/site_instance.h"
 #include "extensions/browser/disable_reason.h"
@@ -26,6 +27,7 @@
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
 #include "extensions/browser/extension_util.h"
+#include "extensions/browser/pref_names.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_icon_set.h"
 #include "extensions/common/extension_urls.h"
@@ -69,13 +71,60 @@
   return ReloadExtension(extension_id, context);
 }
 
+// Returns true if the extension ID is found in the InstallForceList policy. Is
+// checked by HasIsolatedStorage() when the extension is not found in the
+// registry.
+bool IsForceInstalledExtension(const ExtensionId& extension_id,
+                               content::BrowserContext* context) {
+  ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(context);
+  const PrefService::Preference* const pref =
+      extension_prefs->pref_service()->FindPreference(
+          pref_names::kInstallForceList);
+  if (!pref || !pref->IsManaged() ||
+      pref->GetType() != base::Value::Type::DICT) {
+    return false;
+  }
+  for (const auto item : pref->GetValue()->GetDict()) {
+    if (extension_id == item.first) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Returns true if the profile is a sign-in profile and the extension is policy
+// installed. `is_policy_installed` can be passed to the method if its value is
+// known (i.e. the extension was found in the registry and the extension
+// location was checked). If no value is passed for `is_policy_installed`, the
+// force-installed list will be queried for the extension ID.
+bool IsLoginScreenExtension(
+    ExtensionId extension_id,
+    content::BrowserContext* context,
+    absl::optional<bool> is_policy_installed = absl::nullopt) {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  // Verify the force-installed extension list if no value for
+  // `is_policy_installed` was passed.
+  if (is_policy_installed == absl::nullopt) {
+    is_policy_installed = IsForceInstalledExtension(extension_id, context);
+  }
+  Profile* profile = Profile::FromBrowserContext(context);
+  return profile && ash::ProfileHelper::IsSigninProfile(profile) &&
+         is_policy_installed.value();
+#else
+  return false;
+#endif
+}
+
 }  // namespace
 
-bool HasIsolatedStorage(const std::string& extension_id,
+bool HasIsolatedStorage(const ExtensionId& extension_id,
                         content::BrowserContext* context) {
   const Extension* extension =
       ExtensionRegistry::Get(context)->GetInstalledExtension(extension_id);
-  return extension && HasIsolatedStorage(*extension, context);
+  // Extension is null when the extension is cleaned up after it's unloaded and
+  // won't be present in the ExtensionRegistry.
+  return extension ? HasIsolatedStorage(*extension, context)
+                   : IsLoginScreenExtension(extension_id, context);
 }
 
 bool HasIsolatedStorage(const Extension& extension,
@@ -83,9 +132,7 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   const bool is_policy_extension =
       Manifest::IsPolicyLocation(extension.location());
-  Profile* profile = Profile::FromBrowserContext(context);
-  if (profile && ash::ProfileHelper::IsSigninProfile(profile) &&
-      is_policy_extension) {
+  if (IsLoginScreenExtension(extension.id(), context, is_policy_extension)) {
     return true;
   }
 #endif
diff --git a/chrome/browser/extensions/extension_util_unittest.cc b/chrome/browser/extensions/extension_util_unittest.cc
index c0ca42a..c364431 100644
--- a/chrome/browser/extensions/extension_util_unittest.cc
+++ b/chrome/browser/extensions/extension_util_unittest.cc
@@ -4,20 +4,27 @@
 
 #include "chrome/browser/extensions/extension_util.h"
 
+#include "base/memory/raw_ptr.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/strings/strcat.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/extensions/chrome_test_extension_loader.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_service_test_base.h"
+#include "chrome/browser/extensions/external_provider_impl.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
+#include "components/policy/core/common/mock_configuration_policy_provider.h"
+#include "components/policy/core/common/policy_service_impl.h"
 #include "components/sessions/content/session_tab_helper.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "content/public/test/web_contents_tester.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_util.h"
+#include "extensions/browser/pref_names.h"
 #include "extensions/browser/test_extension_registry_observer.h"
 #include "extensions/common/extension_builder.h"
 #include "extensions/common/mojom/manifest.mojom-shared.h"
@@ -27,28 +34,19 @@
 
 namespace extensions {
 
+namespace {
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+constexpr char kExtensionUpdateUrl[] =
+    "https://clients2.google.com/service/update2/crx";  // URL of Chrome Web
+                                                        // Store backend.
+#endif
+
+}  // namespace
+
 class ExtensionUtilUnittest : public ExtensionServiceTestBase {
  public:
-  void SetUp() override {
-    InitializeEmptyExtensionService();
-    testing_profile_manager_ = std::make_unique<TestingProfileManager>(
-        TestingBrowserProcess::GetGlobal(), &testing_local_state_);
-    ASSERT_TRUE(testing_profile_manager_->SetUp());
-    signin_profile_ =
-        testing_profile_manager_->CreateTestingProfile(chrome::kInitialProfile);
-  }
-
-  scoped_refptr<const Extension> BuildPolicyInstalledExtension() {
-    return ExtensionBuilder("foo_ext")
-        .SetLocation(mojom::ManifestLocation::kExternalPolicyDownload)
-        .Build();
-  }
-
- protected:
-  raw_ptr<TestingProfile, DanglingUntriaged> signin_profile_;
-
- private:
-  std::unique_ptr<TestingProfileManager> testing_profile_manager_;
+  void SetUp() override { InitializeEmptyExtensionService(); }
 };
 
 TEST_F(ExtensionUtilUnittest, SetAllowFileAccess) {
@@ -187,26 +185,68 @@
       ExtensionBuilder("foo_ext").Build();
   EXPECT_FALSE(extension->is_platform_app());
   EXPECT_FALSE(util::HasIsolatedStorage(*extension.get(), profile()));
-
-  // Extensions running on the sign-in screen, installed by policy have isolated
-  // storage.
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  scoped_refptr<const Extension> policy_extension =
-      BuildPolicyInstalledExtension();
-  EXPECT_FALSE(policy_extension->is_platform_app());
-  EXPECT_TRUE(
-      util::HasIsolatedStorage(*policy_extension.get(), signin_profile_));
-#endif
 }
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+class ExtensionUtilWithSigninProfileUnittest : public ExtensionUtilUnittest {
+ public:
+  void SetUp() override {
+    ExtensionUtilUnittest::SetUp();
+
+    testing_profile_manager_ = std::make_unique<TestingProfileManager>(
+        TestingBrowserProcess::GetGlobal(), &testing_local_state_);
+    ASSERT_TRUE(testing_profile_manager_->SetUp());
+    auto policy_service = std::make_unique<policy::PolicyServiceImpl>(
+        std::vector<policy::ConfigurationPolicyProvider*>{policy_provider()});
+    signin_profile_ = testing_profile_manager_->CreateTestingProfile(
+        chrome::kInitialProfile, /*prefs=*/nullptr,
+        base::UTF8ToUTF16(chrome::kInitialProfile), 0,
+        TestingProfile::TestingFactories(),
+        /*is_supervised_profile=*/false, /*is_new_profile=*/absl::nullopt,
+        std::move(policy_service));
+    signin_profile_prefs_ = signin_profile_->GetTestingPrefService();
+  }
+
+  void TearDown() override {
+    signin_profile_ = nullptr;
+    signin_profile_prefs_ = nullptr;
+    testing_profile_manager_->DeleteAllTestingProfiles();
+    ExtensionUtilUnittest::TearDown();
+  }
+
+  scoped_refptr<const Extension> BuildPolicyInstalledExtension() {
+    return ExtensionBuilder("foo_ext")
+        .SetLocation(mojom::ManifestLocation::kExternalPolicyDownload)
+        .Build();
+  }
+
+  void SetupForceList(const ExtensionIdList& extension_ids) {
+    base::Value::Dict dict = base::Value::Dict();
+    for (const auto& extension_id : extension_ids) {
+      dict.Set(extension_id,
+               base::Value::Dict().Set(ExternalProviderImpl::kExternalUpdateUrl,
+                                       kExtensionUpdateUrl));
+    }
+    signin_profile_prefs_->SetManagedPref(pref_names::kInstallForceList,
+                                          std::move(dict));
+  }
+
+ protected:
+  raw_ptr<TestingProfile> signin_profile_;
+
+ private:
+  std::unique_ptr<TestingProfileManager> testing_profile_manager_;
+  raw_ptr<sync_preferences::TestingPrefServiceSyncable> signin_profile_prefs_;
+};
+
 // HasIsolatedStorage() will be called when an extension is disabled, more
 // precisely when its service worker is unregistered. At that moment the
 // extension is already added to the disabled list of the extension registry.
 // The method needs to still be able to correctly specify if the extension's
 // storage is isolated or not, even if the extension is disabled.
 // Regression test for b/279763783.
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-TEST_F(ExtensionUtilUnittest, HasIsolatedStorageOnDisabledExtension) {
+TEST_F(ExtensionUtilWithSigninProfileUnittest,
+       HasIsolatedStorageOnDisabledExtension) {
   scoped_refptr<const Extension> policy_extension =
       BuildPolicyInstalledExtension();
   const std::string& policy_extension_id = policy_extension->id();
@@ -228,7 +268,7 @@
   EXPECT_FALSE(util::HasIsolatedStorage(policy_extension_id, signin_profile_));
 }
 
-TEST_F(ExtensionUtilUnittest,
+TEST_F(ExtensionUtilWithSigninProfileUnittest,
        HasIsolatedStorageOnTerminatedOrBlockedExtension) {
   scoped_refptr<const Extension> policy_extension =
       BuildPolicyInstalledExtension();
@@ -260,6 +300,47 @@
   extension_registry->RemoveBlocked(policy_extension_id);
   EXPECT_FALSE(util::HasIsolatedStorage(policy_extension_id, signin_profile_));
 }
+
+// Verifies that the force-installed extension policy is checked in case it
+// was not found in the extension registry. When an extension is unloaded, we
+// clean up state from the extension. For service worker-based extensions,
+// this includes unregistering the worker, which requires access to the
+// storage partition. At this point, since the extension is unloaded, it won't
+// be present in the registry, but we still need to determine if the extension
+// has isolated storage to pinpoint the correct storage partition.
+// Regression test for b/287924795.
+TEST_F(ExtensionUtilWithSigninProfileUnittest,
+       HasIsolatedStorageForForceInstalledExtensions) {
+  scoped_refptr<const Extension> extension1 = BuildPolicyInstalledExtension();
+  scoped_refptr<const Extension> extension2 = BuildPolicyInstalledExtension();
+  ExtensionRegistry* extension_registry =
+      ExtensionRegistry::Get(signin_profile_);
+  extension_registry->AddEnabled(extension1);
+  extension_registry->AddEnabled(extension2);
+
+  // Extensions are found in the registry, are policy-installed and run on the
+  // sign-in screen.
+  EXPECT_TRUE(util::HasIsolatedStorage(extension1->id(), signin_profile_));
+  EXPECT_TRUE(util::HasIsolatedStorage(extension2->id(), signin_profile_));
+
+  extension_registry->RemoveEnabled(extension1->id());
+  extension_registry->RemoveEnabled(extension2->id());
+
+  // Extensions are not found in the registry and are not force-installed.
+  EXPECT_FALSE(util::HasIsolatedStorage(extension1->id(), signin_profile_));
+  EXPECT_FALSE(util::HasIsolatedStorage(extension2->id(), signin_profile_));
+
+  ExtensionIdList extension_ids;
+  extension_ids.push_back(extension1->id());
+  extension_ids.push_back(extension2->id());
+  SetupForceList(extension_ids);
+
+  // Extensions are not found in the registry, but are force-installed and run
+  // on the sign-in screen.
+  EXPECT_TRUE(util::HasIsolatedStorage(extension1->id(), signin_profile_));
+  EXPECT_TRUE(util::HasIsolatedStorage(extension2->id(), signin_profile_));
+}
+
 #endif
 
 }  // namespace extensions
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 000034291..74d4bf6 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -6175,7 +6175,7 @@
   {
     "name": "page-info-about-this-site-improved-bottomsheet",
     "owners": [ "dullweber", "eokoyomon", "zalmashni@google.com" ],
-    "expiry_milestone": 116
+    "expiry_milestone": 118
   },
   {
     "name": "page-info-about-this-site-keep-side-panel-open-on-same-tab-navs",
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index 7c89ebe..ad7a499 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -550,6 +550,8 @@
     public static final CachedFlag sInstanceSwitcher = new CachedFlag(INSTANCE_SWITCHER, true);
     public static final CachedFlag sInstantStart = new CachedFlag(INSTANT_START, false);
     public static final CachedFlag sInterestFeedV2 = new CachedFlag(INTEREST_FEED_V2, true);
+    public static final CachedFlag sPrivacyGuidePostMVP =
+            new CachedFlag(PRIVACY_GUIDE_POST_MVP, false);
     public static final CachedFlag sOmniboxMatchToolbarAndStatusBarColor =
             new CachedFlag(OMNIBOX_MATCH_TOOLBAR_AND_STATUS_BAR_COLOR, false);
     public static final CachedFlag sOmniboxModernizeVisualUpdate =
@@ -645,6 +647,7 @@
         sInstanceSwitcher,
         sInstantStart,
         sInterestFeedV2,
+        sPrivacyGuidePostMVP,
         sOmniboxMatchToolbarAndStatusBarColor,
         sOmniboxModernizeVisualUpdate,
         sOmniboxMostVisitedTilesAddRecycledViewPool,
diff --git a/chrome/browser/font_family_cache.h b/chrome/browser/font_family_cache.h
index 459a2595..6ec531bb 100644
--- a/chrome/browser/font_family_cache.h
+++ b/chrome/browser/font_family_cache.h
@@ -83,7 +83,7 @@
   // Weak reference.
   // Note: The lifetime of this object is tied to the lifetime of the
   // PrefService, so there is no worry about an invalid pointer.
-  raw_ptr<const PrefService, DanglingUntriaged> prefs_;
+  raw_ptr<const PrefService, DanglingAcrossTasks> prefs_;
 
   // Reacts to profile font changes. |font_change_registrar_| will be
   // automatically unregistered when the FontPrefChangeNotifier is destroyed as
diff --git a/chrome/browser/media/media_engagement_browsertest.cc b/chrome/browser/media/media_engagement_browsertest.cc
index 37527c2..27d4ec9 100644
--- a/chrome/browser/media/media_engagement_browsertest.cc
+++ b/chrome/browser/media/media_engagement_browsertest.cc
@@ -243,9 +243,7 @@
   }
 
   void CloseTab() {
-    const int previous_tab_count = browser()->tab_strip_model()->count();
-    browser()->tab_strip_model()->CloseWebContentsAt(0, 0);
-    EXPECT_EQ(previous_tab_count - 1, browser()->tab_strip_model()->count());
+    EXPECT_TRUE(browser()->tab_strip_model()->CloseWebContentsAt(0, 0));
   }
 
   void LoadSubFrame(const GURL& url) {
diff --git a/components/media_device_salt/media_device_salt_service_factory.cc b/chrome/browser/media/webrtc/media_device_salt_service_factory.cc
similarity index 76%
rename from components/media_device_salt/media_device_salt_service_factory.cc
rename to chrome/browser/media/webrtc/media_device_salt_service_factory.cc
index a2fcddbe..1dc95ce52 100644
--- a/components/media_device_salt/media_device_salt_service_factory.cc
+++ b/chrome/browser/media/webrtc/media_device_salt_service_factory.cc
@@ -2,23 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/media_device_salt/media_device_salt_service_factory.h"
+#include "chrome/browser/media/webrtc/media_device_salt_service_factory.h"
 
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/media_device_salt/media_device_salt_service.h"
 #include "components/user_prefs/user_prefs.h"
 #include "content/public/browser/browser_context.h"
 
-namespace media_device_salt {
-
 MediaDeviceSaltServiceFactory* MediaDeviceSaltServiceFactory::GetInstance() {
   static base::NoDestructor<MediaDeviceSaltServiceFactory> factory;
   return factory.get();
 }
 
-MediaDeviceSaltService* MediaDeviceSaltServiceFactory::GetForBrowserContext(
+media_device_salt::MediaDeviceSaltService*
+MediaDeviceSaltServiceFactory::GetForBrowserContext(
     content::BrowserContext* context) {
-  return static_cast<MediaDeviceSaltService*>(
+  return static_cast<media_device_salt::MediaDeviceSaltService*>(
       GetInstance()->GetServiceForBrowserContext(context, true));
 }
 
@@ -30,8 +29,6 @@
 std::unique_ptr<KeyedService>
 MediaDeviceSaltServiceFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
-  return std::make_unique<MediaDeviceSaltService>(
+  return std::make_unique<media_device_salt::MediaDeviceSaltService>(
       user_prefs::UserPrefs::Get(context));
 }
-
-}  // namespace media_device_salt
diff --git a/components/media_device_salt/media_device_salt_service_factory.h b/chrome/browser/media/webrtc/media_device_salt_service_factory.h
similarity index 80%
rename from components/media_device_salt/media_device_salt_service_factory.h
rename to chrome/browser/media/webrtc/media_device_salt_service_factory.h
index 3fa5be5c..882dda9 100644
--- a/components/media_device_salt/media_device_salt_service_factory.h
+++ b/chrome/browser/media/webrtc/media_device_salt_service_factory.h
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_MEDIA_DEVICE_SALT_MEDIA_DEVICE_SALT_SERVICE_FACTORY_H_
-#define COMPONENTS_MEDIA_DEVICE_SALT_MEDIA_DEVICE_SALT_SERVICE_FACTORY_H_
+#ifndef CHROME_BROWSER_MEDIA_WEBRTC_MEDIA_DEVICE_SALT_SERVICE_FACTORY_H_
+#define CHROME_BROWSER_MEDIA_WEBRTC_MEDIA_DEVICE_SALT_SERVICE_FACTORY_H_
 
 #include "base/no_destructor.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 
 namespace media_device_salt {
-
 class MediaDeviceSaltService;
+}  // namespace media_device_salt
 
 class MediaDeviceSaltServiceFactory : public BrowserContextKeyedServiceFactory {
  public:
@@ -22,7 +22,7 @@
   static MediaDeviceSaltServiceFactory* GetInstance();
 
   // Returns the MediaDeviceSaltService associated with |context|.
-  static MediaDeviceSaltService* GetForBrowserContext(
+  static media_device_salt::MediaDeviceSaltService* GetForBrowserContext(
       content::BrowserContext* context);
 
  private:
@@ -36,6 +36,4 @@
       content::BrowserContext* context) const override;
 };
 
-}  // namespace media_device_salt
-
-#endif  // COMPONENTS_MEDIA_DEVICE_SALT_MEDIA_DEVICE_SALT_SERVICE_FACTORY_H_
+#endif  // CHROME_BROWSER_MEDIA_WEBRTC_MEDIA_DEVICE_SALT_SERVICE_FACTORY_H_
diff --git a/chrome/browser/media/webrtc/media_device_salt_service_factory_unittest.cc b/chrome/browser/media/webrtc/media_device_salt_service_factory_unittest.cc
new file mode 100644
index 0000000..4dd0ea3
--- /dev/null
+++ b/chrome/browser/media/webrtc/media_device_salt_service_factory_unittest.cc
@@ -0,0 +1,27 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media/webrtc/media_device_salt_service_factory.h"
+
+#include "base/test/test_future.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/media_device_salt/media_device_salt_service.h"
+#include "content/public/test/browser_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(MediaDeviceSaltServiceFactoryTest, Test) {
+  content::BrowserTaskEnvironment task_environment;
+  TestingProfile profile;
+
+  MediaDeviceSaltServiceFactory* factory =
+      MediaDeviceSaltServiceFactory::GetInstance();
+  ASSERT_TRUE(factory);
+
+  auto* service = factory->GetForBrowserContext(&profile);
+  ASSERT_TRUE(service);
+
+  base::test::TestFuture<const std::string&> future;
+  service->GetSalt(future.GetCallback());
+  EXPECT_FALSE(future.Get().empty());
+}
diff --git a/chrome/browser/media/webrtc/media_stream_devices_controller_browsertest.cc b/chrome/browser/media/webrtc/media_stream_devices_controller_browsertest.cc
index b72efcf..2b60ca4 100644
--- a/chrome/browser/media/webrtc/media_stream_devices_controller_browsertest.cc
+++ b/chrome/browser/media/webrtc/media_stream_devices_controller_browsertest.cc
@@ -978,10 +978,8 @@
   // PermissionRequestManager for the WebContents and uses that reference in its
   // destructor, it has to be destroyed before the tab.
   prompt_factory_.reset();
-  int previous_tab_count = browser()->tab_strip_model()->count();
-  browser()->tab_strip_model()->CloseWebContentsAt(
-      prompt_contents_index, TabCloseTypes::CLOSE_USER_GESTURE);
-  EXPECT_EQ(previous_tab_count - 1, browser()->tab_strip_model()->count());
+  ASSERT_TRUE(browser()->tab_strip_model()->CloseWebContentsAt(
+      prompt_contents_index, TabCloseTypes::CLOSE_USER_GESTURE));
   base::RunLoop().RunUntilIdle();
 
   VerifyResultState(
diff --git a/chrome/browser/metrics/chrome_feature_list_creator.h b/chrome/browser/metrics/chrome_feature_list_creator.h
index 808e056..df5c081 100644
--- a/chrome/browser/metrics/chrome_feature_list_creator.h
+++ b/chrome/browser/metrics/chrome_feature_list_creator.h
@@ -120,7 +120,7 @@
   std::string actual_locale_;
 
   // This is owned by |metrics_services_manager_| but we need to expose it.
-  raw_ptr<ChromeMetricsServicesManagerClient, DanglingUntriaged>
+  raw_ptr<ChromeMetricsServicesManagerClient, DanglingAcrossTasks>
       metrics_services_manager_client_;
 
   std::unique_ptr<metrics_services_manager::MetricsServicesManager>
diff --git a/chrome/browser/metrics/usage_scenario/tab_usage_scenario_tracker_browsertest.cc b/chrome/browser/metrics/usage_scenario/tab_usage_scenario_tracker_browsertest.cc
index e3dad879..e8917be 100644
--- a/chrome/browser/metrics/usage_scenario/tab_usage_scenario_tracker_browsertest.cc
+++ b/chrome/browser/metrics/usage_scenario/tab_usage_scenario_tracker_browsertest.cc
@@ -199,10 +199,8 @@
                                 ->GetActiveWebContents()
                                 ->GetPrimaryMainFrame()
                                 ->GetPageUkmSourceId();
-  int previous_tab_count = browser()->tab_strip_model()->count();
-  browser()->tab_strip_model()->CloseWebContentsAt(
-      0, TabCloseTypes::CLOSE_USER_GESTURE);
-  EXPECT_EQ(previous_tab_count - 1, browser()->tab_strip_model()->count());
+  EXPECT_TRUE(browser()->tab_strip_model()->CloseWebContentsAt(
+      0, TabCloseTypes::CLOSE_USER_GESTURE));
   tick_clock_.Advance(kInterval);
   interval_data = data_store_.ResetIntervalData();
   EXPECT_EQ(2U, interval_data.max_tab_count);
@@ -454,10 +452,8 @@
   tick_clock_.Advance(kInterval * 2);
   auto expected_source_id =
       contents->GetPrimaryMainFrame()->GetPageUkmSourceId();
-  int previous_tab_count = browser()->tab_strip_model()->count();
-  browser()->tab_strip_model()->CloseWebContentsAt(
-      1, TabCloseTypes::CLOSE_USER_GESTURE);
-  EXPECT_EQ(previous_tab_count - 1, browser()->tab_strip_model()->count());
+  EXPECT_TRUE(browser()->tab_strip_model()->CloseWebContentsAt(
+      1, TabCloseTypes::CLOSE_USER_GESTURE));
 
   auto interval_data = data_store_.ResetIntervalData();
   EXPECT_EQ(2U, interval_data.max_tab_count);
@@ -558,13 +554,8 @@
       ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
   Browser* browser2 = BrowserList::GetInstance()->get(1);
 
-  int previous_browser1_tab_count = browser()->tab_strip_model()->count();
-  int previous_browser2_tab_count = browser2->tab_strip_model()->count();
-  browser2->tab_strip_model()->CloseWebContentsAt(
-      0, TabCloseTypes::CLOSE_USER_GESTURE);
-  EXPECT_EQ(previous_browser1_tab_count, browser()->tab_strip_model()->count());
-  EXPECT_EQ(previous_browser2_tab_count - 1,
-            browser2->tab_strip_model()->count());
+  EXPECT_TRUE(browser2->tab_strip_model()->CloseWebContentsAt(
+      0, TabCloseTypes::CLOSE_USER_GESTURE));
 
   tick_clock_.Advance(kInterval);
   auto interval_data = data_store_.ResetIntervalData();
diff --git a/chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_page_load_metrics_observer_browsertest.cc
index ef56d20..088700e 100644
--- a/chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_page_load_metrics_observer_browsertest.cc
+++ b/chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_page_load_metrics_observer_browsertest.cc
@@ -102,9 +102,7 @@
 
     content::WebContentsDestroyedWatcher destroyed_watcher(
         tab_strip_model->GetWebContentsAt(0));
-    int previous_tab_count = tab_strip_model->count();
-    tab_strip_model->CloseWebContentsAt(0, 0);
-    EXPECT_EQ(previous_tab_count - 1, tab_strip_model->count());
+    EXPECT_TRUE(tab_strip_model->CloseWebContentsAt(0, 0));
     destroyed_watcher.Wait();
     EXPECT_EQ(1, tab_strip_model->count());
 
@@ -128,9 +126,7 @@
 
     content::WebContentsDestroyedWatcher destroyed_watcher(
         tab_strip_model->GetWebContentsAt(1));
-    int previous_tab_count = tab_strip_model->count();
-    tab_strip_model->CloseWebContentsAt(1, 0);
-    EXPECT_EQ(previous_tab_count - 1, tab_strip_model->count());
+    EXPECT_TRUE(tab_strip_model->CloseWebContentsAt(1, 0));
     destroyed_watcher.Wait();
     EXPECT_EQ(1, tab_strip_model->count());
   }
@@ -155,9 +151,7 @@
     base::TimeTicks start = base::TimeTicks::Now();
     content::WebContentsDestroyedWatcher destroyed_watcher(
         tab_strip_model->GetWebContentsAt(0));
-    int previous_tab_count = tab_strip_model->count();
-    tab_strip_model->CloseWebContentsAt(0, 0);
-    EXPECT_EQ(previous_tab_count - 1, tab_strip_model->count());
+    EXPECT_TRUE(tab_strip_model->CloseWebContentsAt(0, 0));
     destroyed_watcher.Wait();
 
     // Now the background tab should have moved to the foreground.
@@ -294,9 +288,8 @@
       browser(), https_test_server_->GetURL("/simple.html")));
   content::WebContentsDestroyedWatcher destroyed_watcher(
       tab_strip_model->GetActiveWebContents());
-  int previous_tab_count = tab_strip_model->count();
-  tab_strip_model->CloseWebContentsAt(tab_strip_model->active_index(), 0);
-  EXPECT_EQ(previous_tab_count - 1, tab_strip_model->count());
+  EXPECT_TRUE(
+      tab_strip_model->CloseWebContentsAt(tab_strip_model->active_index(), 0));
   destroyed_watcher.Wait();
   histogram_tester_.ExpectTotalCount(internal::kHttpEngagementHistogram, 0);
   histogram_tester_.ExpectTotalCount(internal::kHttpsEngagementHistogram, 0);
diff --git a/chrome/browser/page_load_metrics/observers/multi_tab_loading_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/multi_tab_loading_page_load_metrics_observer_browsertest.cc
index 05d686f..2250cc8a 100644
--- a/chrome/browser/page_load_metrics/observers/multi_tab_loading_page_load_metrics_observer_browsertest.cc
+++ b/chrome/browser/page_load_metrics/observers/multi_tab_loading_page_load_metrics_observer_browsertest.cc
@@ -101,9 +101,7 @@
   TabStripModel* tab_strip_model = browser()->tab_strip_model();
   content::WebContentsDestroyedWatcher destroyed_watcher(
       tab_strip_model->GetWebContentsAt(0));
-  int previous_tab_count = tab_strip_model->count();
-  tab_strip_model->CloseWebContentsAt(0, 0);
-  EXPECT_EQ(previous_tab_count - 1, tab_strip_model->count());
+  EXPECT_TRUE(tab_strip_model->CloseWebContentsAt(0, 0));
   destroyed_watcher.Wait();
   // Now the background tab should have moved to the foreground.
 
diff --git a/chrome/browser/page_load_metrics/observers/security_state_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/security_state_page_load_metrics_observer_browsertest.cc
index 17d9e62..85e4579 100644
--- a/chrome/browser/page_load_metrics/observers/security_state_page_load_metrics_observer_browsertest.cc
+++ b/chrome/browser/page_load_metrics/observers/security_state_page_load_metrics_observer_browsertest.cc
@@ -294,10 +294,8 @@
     run_loop.Run();
 
     // The UKM isn't recorded until the page is destroyed.
-    int previous_tab_count = browser()->tab_strip_model()->count();
-    browser()->tab_strip_model()->CloseWebContentsAt(1,
-                                                     TabCloseTypes::CLOSE_NONE);
-    ASSERT_EQ(previous_tab_count - 1, browser()->tab_strip_model()->count());
+    ASSERT_TRUE(browser()->tab_strip_model()->CloseWebContentsAt(
+        1, TabCloseTypes::CLOSE_NONE));
 
     histogram_tester.ExpectTotalCount(
         kSiteEngagementHistogramPrefix + (test_case.expect_safety_tip
diff --git a/chrome/browser/password_manager/android/local_passwords_migration_warning_util.cc b/chrome/browser/password_manager/android/local_passwords_migration_warning_util.cc
index ca7309c8..ffda68d 100644
--- a/chrome/browser/password_manager/android/local_passwords_migration_warning_util.cc
+++ b/chrome/browser/password_manager/android/local_passwords_migration_warning_util.cc
@@ -3,13 +3,18 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/password_manager/android/local_passwords_migration_warning_util.h"
+
+#include "base/android/scoped_java_ref.h"
 #include "base/time/time.h"
 #include "chrome/android/chrome_jni_headers/PasswordMigrationWarningBridge_jni.h"
 #include "chrome/browser/profiles/profile_android.h"
+#include "chrome/browser/sync/sync_service_factory.h"
+#include "components/password_manager/core/browser/password_bubble_experiment.h"
 #include "components/password_manager/core/common/password_manager_features.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "ui/android/window_android.h"
+#include "ui/gfx/native_widget_types.h"
 
 using base::android::AttachCurrentThread;
 
@@ -27,24 +32,54 @@
   if (!ShouldShowWarning(profile)) {
     return;
   }
+  SaveWarningShownTimestamp(profile->GetPrefs());
+
   Java_PasswordMigrationWarningBridge_showWarning(
       AttachCurrentThread(), window->GetJavaObject(),
       ProfileAndroid::FromProfile(profile)->GetJavaObject());
+}
+
+void ShowWarningWithActivity(
+    const base::android::JavaParamRef<jobject>& activity,
+    const base::android::JavaParamRef<jobject>& bottom_sheet_controller,
+    Profile* profile) {
+  if (!ShouldShowWarning(profile)) {
+    return;
+  }
   SaveWarningShownTimestamp(profile->GetPrefs());
+
+  Java_PasswordMigrationWarningBridge_showWarningWithActivity(
+      AttachCurrentThread(), activity, bottom_sheet_controller,
+      ProfileAndroid::FromProfile(profile)->GetJavaObject());
 }
 
 bool ShouldShowWarning(Profile* profile) {
+  if (profile->IsOffTheRecord()) {
+    return false;
+  }
+
   if (!base::FeatureList::IsEnabled(
           password_manager::features::
               kUnifiedPasswordManagerLocalPasswordsMigrationWarning)) {
     return false;
   }
 
+  PrefService* pref_service = profile->GetPrefs();
+  bool is_warning_acknowledged = pref_service->GetBoolean(
+      password_manager::prefs::kUserAcknowledgedLocalPasswordsMigrationWarning);
+  if (is_warning_acknowledged) {
+    return false;
+  }
+
+  if (password_bubble_experiment::HasChosenToSyncPasswords(
+          SyncServiceFactory::GetForProfile(profile))) {
+    return false;
+  }
+
   if (password_manager::features::kIgnoreMigrationWarningTimeout.Get()) {
     return true;
   }
 
-  PrefService* pref_service = profile->GetPrefs();
   base::Time last_shown_timestamp = pref_service->GetTime(
       password_manager::prefs::kLocalPasswordsMigrationWarningShownTimestamp);
   base::TimeDelta time_since_last_shown =
@@ -53,8 +88,6 @@
     return false;
   }
 
-  // TODO(crbug.com/1451827): Check whether the user is already syncing
-  // passwords.
   return true;
 }
 
diff --git a/chrome/browser/password_manager/android/local_passwords_migration_warning_util.h b/chrome/browser/password_manager/android/local_passwords_migration_warning_util.h
index 66126b6..e60f8b7 100644
--- a/chrome/browser/password_manager/android/local_passwords_migration_warning_util.h
+++ b/chrome/browser/password_manager/android/local_passwords_migration_warning_util.h
@@ -13,6 +13,13 @@
 // Shows the local password migration warning.
 void ShowWarning(const gfx::NativeWindow window, Profile* profile);
 
+// Shows the local password migration warning. `activity` is provided from
+// java.
+void ShowWarningWithActivity(
+    const base::android::JavaParamRef<jobject>& activity,
+    const base::android::JavaParamRef<jobject>& bottom_sheet_controller,
+    Profile* profile);
+
 // Returns whether the UPM local passwords migration warning should be
 // displayed. `profile` is used to retrieve necessary services for checking
 // the conditions.
diff --git a/chrome/browser/password_manager/android/local_passwords_migration_warning_util_unittest.cc b/chrome/browser/password_manager/android/local_passwords_migration_warning_util_unittest.cc
index fa89ec7..90054b8 100644
--- a/chrome/browser/password_manager/android/local_passwords_migration_warning_util_unittest.cc
+++ b/chrome/browser/password_manager/android/local_passwords_migration_warning_util_unittest.cc
@@ -5,15 +5,24 @@
 #include "chrome/browser/password_manager/android/local_passwords_migration_warning_util.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/time/time.h"
+#include "chrome/browser/sync/sync_service_factory.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/password_manager/core/common/password_manager_features.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/testing_pref_service.h"
+#include "components/sync/test/test_sync_service.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+namespace {
+std::unique_ptr<KeyedService> TestingSyncFactoryFunction(
+    content::BrowserContext* context) {
+  return std::make_unique<syncer::TestSyncService>();
+}
+}  // namespace
+
 class LocalPasswordsMigrationWarningUtilTest : public testing::Test {
  protected:
   LocalPasswordsMigrationWarningUtilTest() = default;
@@ -23,14 +32,23 @@
     return profile_.GetTestingPrefService();
   }
 
-  Profile* profile() { return &profile_; }
+  syncer::TestSyncService* sync_service() { return fake_sync_service_; }
+
+  TestingProfile* profile() { return &profile_; }
 
   base::test::TaskEnvironment* task_env() { return &task_env_; }
 
+  void SetUp() override {
+    fake_sync_service_ = static_cast<syncer::TestSyncService*>(
+        SyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
+            profile(), base::BindRepeating(&TestingSyncFactoryFunction)));
+  }
+
  private:
   content::BrowserTaskEnvironment task_env_{
       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
   TestingProfile profile_;
+  raw_ptr<syncer::TestSyncService> fake_sync_service_;
 };
 
 TEST_F(LocalPasswordsMigrationWarningUtilTest,
@@ -51,6 +69,7 @@
       password_manager::prefs::kLocalPasswordsMigrationWarningShownTimestamp,
       base::Time::Now());
   task_env()->FastForwardBy(base::Days(31));
+  sync_service()->SetHasSyncConsent(false);
   EXPECT_TRUE(local_password_migration::ShouldShowWarning(profile()));
 }
 
@@ -63,5 +82,64 @@
       password_manager::prefs::kLocalPasswordsMigrationWarningShownTimestamp,
       base::Time::Now());
   task_env()->FastForwardBy(base::Days(29));
+  sync_service()->SetHasSyncConsent(false);
   EXPECT_FALSE(local_password_migration::ShouldShowWarning(profile()));
 }
+
+TEST_F(LocalPasswordsMigrationWarningUtilTest,
+       TestShouldNotShowWhenAcknowledged) {
+  base::test::ScopedFeatureList scoped_feature_list(
+      password_manager::features::
+          kUnifiedPasswordManagerLocalPasswordsMigrationWarning);
+  pref_service()->SetBoolean(
+      password_manager::prefs::kUserAcknowledgedLocalPasswordsMigrationWarning,
+      true);
+  EXPECT_FALSE(local_password_migration::ShouldShowWarning(profile()));
+}
+
+TEST_F(LocalPasswordsMigrationWarningUtilTest,
+       TestShouldNotShowWhenSyncingOnlyPasswords) {
+  base::test::ScopedFeatureList scoped_feature_list(
+      password_manager::features::
+          kUnifiedPasswordManagerLocalPasswordsMigrationWarning);
+  sync_service()->SetHasSyncConsent(true);
+  sync_service()->GetUserSettings()->SetSelectedTypes(
+      /* sync_everything = */ false, {syncer::UserSelectableType::kPasswords});
+  EXPECT_FALSE(local_password_migration::ShouldShowWarning(profile()));
+}
+
+TEST_F(LocalPasswordsMigrationWarningUtilTest,
+       TestShouldNotShowWhenSyncingEverything) {
+  base::test::ScopedFeatureList scoped_feature_list(
+      password_manager::features::
+          kUnifiedPasswordManagerLocalPasswordsMigrationWarning);
+  sync_service()->SetHasSyncConsent(true);
+  sync_service()->GetUserSettings()->SetSelectedTypes(
+      /* sync_everything = */ true, {});
+  EXPECT_FALSE(local_password_migration::ShouldShowWarning(profile()));
+}
+
+TEST_F(LocalPasswordsMigrationWarningUtilTest,
+       TestShouldShowWhenNotSyncingPasswords) {
+  base::test::ScopedFeatureList scoped_feature_list(
+      password_manager::features::
+          kUnifiedPasswordManagerLocalPasswordsMigrationWarning);
+  sync_service()->SetHasSyncConsent(true);
+  sync_service()->GetUserSettings()->SetSelectedTypes(
+      /* sync_everything = */ false, {syncer::UserSelectableType::kBookmarks});
+  EXPECT_TRUE(local_password_migration::ShouldShowWarning(profile()));
+}
+
+TEST_F(LocalPasswordsMigrationWarningUtilTest, TestShouldNotShowInIncognito) {
+  base::test::ScopedFeatureList scoped_feature_list(
+      password_manager::features::
+          kUnifiedPasswordManagerLocalPasswordsMigrationWarning);
+  sync_service()->GetUserSettings()->SetSelectedTypes(
+      /* sync_everything = */ false, {});
+  TestingProfile::Builder off_the_record_builder;
+  Profile* off_the_record_profile =
+      off_the_record_builder.BuildIncognito(profile());
+
+  EXPECT_FALSE(
+      local_password_migration::ShouldShowWarning(off_the_record_profile));
+}
diff --git a/chrome/browser/password_manager/android/password_ui_view_android.cc b/chrome/browser/password_manager/android/password_ui_view_android.cc
index a3d18ac39..648b5480 100644
--- a/chrome/browser/password_manager/android/password_ui_view_android.cc
+++ b/chrome/browser/password_manager/android/password_ui_view_android.cc
@@ -279,6 +279,14 @@
       context, settings_launcher);
 }
 
+void PasswordUIViewAndroid::ShowMigrationWarning(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& activity,
+    const base::android::JavaParamRef<jobject>& bottom_sheet_controller) {
+  local_password_migration::ShowWarningWithActivity(
+      activity, bottom_sheet_controller, ProfileManager::GetLastUsedProfile());
+}
+
 void PasswordUIViewAndroid::OnEditUIDismissed() {
   credential_edit_bridge_.reset();
 }
@@ -302,11 +310,6 @@
       identity_manager);
 }
 
-jboolean JNI_PasswordUIView_ShouldShowMigrationWarning(JNIEnv* env) {
-  return local_password_migration::ShouldShowWarning(
-      ProfileManager::GetLastUsedProfile());
-}
-
 // static
 static jlong JNI_PasswordUIView_Init(JNIEnv* env,
                                      const JavaParamRef<jobject>& obj) {
diff --git a/chrome/browser/password_manager/android/password_ui_view_android.h b/chrome/browser/password_manager/android/password_ui_view_android.h
index 840d8ec..d026f5f 100644
--- a/chrome/browser/password_manager/android/password_ui_view_android.h
+++ b/chrome/browser/password_manager/android/password_ui_view_android.h
@@ -94,6 +94,10 @@
       const base::android::JavaRef<jobject>& settings_launcher,
       int index,
       const base::android::JavaParamRef<jobject>& obj);
+  void ShowMigrationWarning(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& activity,
+      const base::android::JavaParamRef<jobject>& controller);
   // Destroy the native implementation.
   void Destroy(JNIEnv*, const base::android::JavaRef<jobject>&);
 
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.h b/chrome/browser/password_manager/chrome_password_manager_client.h
index 287499d..c6b570e 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.h
+++ b/chrome/browser/password_manager/chrome_password_manager_client.h
@@ -400,7 +400,7 @@
 #endif  // BUILDFLAG(IS_ANDROID)
 
   raw_ptr<password_manager::ContentPasswordManagerDriverFactory,
-          DanglingUntriaged>
+          DanglingAcrossTasks>
       driver_factory_;
 
   // As a mojo service, will be registered into service registry
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc
index f919208c..80b56646 100644
--- a/chrome/browser/pdf/pdf_extension_test.cc
+++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -304,10 +304,8 @@
   // the middle of initialization. In https://crbug.com/1295431, the extension
   // process exited here and caused a crash when the second PDF resumed.
   EXPECT_EQ(2U, GetGuestViewManager()->GetCurrentGuestCount());
-  ASSERT_EQ(2, browser()->tab_strip_model()->count());
-  browser()->tab_strip_model()->CloseWebContentsAt(
-      0, TabCloseTypes::CLOSE_USER_GESTURE);
-  ASSERT_EQ(1, browser()->tab_strip_model()->count());
+  ASSERT_TRUE(browser()->tab_strip_model()->CloseWebContentsAt(
+      0, TabCloseTypes::CLOSE_USER_GESTURE));
   // `TestGuestViewManager` manages the guests by the order of creation.
   GetGuestViewManager()->WaitForFirstGuestDeleted();
   EXPECT_EQ(1U, GetGuestViewManager()->GetCurrentGuestCount());
diff --git a/chrome/browser/policy/cloud/cloud_policy_invalidator.h b/chrome/browser/policy/cloud/cloud_policy_invalidator.h
index 23df0ad..13c1af14 100644
--- a/chrome/browser/policy/cloud/cloud_policy_invalidator.h
+++ b/chrome/browser/policy/cloud/cloud_policy_invalidator.h
@@ -201,7 +201,7 @@
   raw_ptr<base::Clock> clock_;
 
   // The invalidation service.
-  raw_ptr<invalidation::InvalidationService, DanglingUntriaged>
+  raw_ptr<invalidation::InvalidationService, DanglingAcrossTasks>
       invalidation_service_;
 
   // Whether the invalidator currently has the ability to receive invalidations.
diff --git a/chrome/browser/privacy_guide/android/BUILD.gn b/chrome/browser/privacy_guide/android/BUILD.gn
index 5c0f54c..1e6ee23a 100644
--- a/chrome/browser/privacy_guide/android/BUILD.gn
+++ b/chrome/browser/privacy_guide/android/BUILD.gn
@@ -26,6 +26,7 @@
   deps = [
     ":java_resources",
     "//base:base_java",
+    "//chrome/browser/back_press/android:java",
     "//chrome/browser/privacy_sandbox/android:java",
     "//chrome/browser/profiles/android:java",
     "//chrome/browser/safe_browsing/android:java",
diff --git a/chrome/browser/privacy_guide/android/java/src/org/chromium/chrome/browser/privacy_guide/PrivacyGuideBottomSheetView.java b/chrome/browser/privacy_guide/android/java/src/org/chromium/chrome/browser/privacy_guide/PrivacyGuideBottomSheetView.java
index 2b4d1b2..f2adc685 100644
--- a/chrome/browser/privacy_guide/android/java/src/org/chromium/chrome/browser/privacy_guide/PrivacyGuideBottomSheetView.java
+++ b/chrome/browser/privacy_guide/android/java/src/org/chromium/chrome/browser/privacy_guide/PrivacyGuideBottomSheetView.java
@@ -8,14 +8,20 @@
 
 import androidx.annotation.Nullable;
 
+import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;
 
 /** Bottom sheet view for displaying privacy guide control explanations */
 public class PrivacyGuideBottomSheetView implements BottomSheetContent {
     private final View mContentView;
+    private final Runnable mCloseBottomSheetCallback;
+    private ObservableSupplierImpl<Boolean> mBackPressStateChangedSupplier =
+            new ObservableSupplierImpl<>();
 
-    PrivacyGuideBottomSheetView(View contentView) {
+    PrivacyGuideBottomSheetView(View contentView, Runnable closeBottomSheetCallback) {
         mContentView = contentView;
+        mCloseBottomSheetCallback = closeBottomSheetCallback;
+        mBackPressStateChangedSupplier.set(true);
     }
 
     @Override
@@ -58,6 +64,22 @@
     }
 
     @Override
+    public boolean handleBackPress() {
+        onBackPressed();
+        return true;
+    }
+
+    @Override
+    public void onBackPressed() {
+        mCloseBottomSheetCallback.run();
+    }
+
+    @Override
+    public ObservableSupplierImpl<Boolean> getBackPressStateChangedSupplier() {
+        return mBackPressStateChangedSupplier;
+    }
+
+    @Override
     public int getSheetContentDescriptionStringId() {
         return R.string.privacy_guide_explanation_content_description;
     }
diff --git a/chrome/browser/privacy_guide/android/java/src/org/chromium/chrome/browser/privacy_guide/SafeBrowsingFragment.java b/chrome/browser/privacy_guide/android/java/src/org/chromium/chrome/browser/privacy_guide/SafeBrowsingFragment.java
index 30946b7..06de44e 100644
--- a/chrome/browser/privacy_guide/android/java/src/org/chromium/chrome/browser/privacy_guide/SafeBrowsingFragment.java
+++ b/chrome/browser/privacy_guide/android/java/src/org/chromium/chrome/browser/privacy_guide/SafeBrowsingFragment.java
@@ -27,6 +27,7 @@
     private RadioButtonWithDescriptionAndAuxButton mStandardProtection;
     private RadioButtonWithDescriptionAndAuxButton mEnhancedProtection;
     private BottomSheetController mBottomSheetController;
+    private PrivacyGuideBottomSheetView mBottomSheetView;
 
     @Override
     public View onCreateView(
@@ -95,10 +96,16 @@
     }
 
     private void displayBottomSheet(View sheetContent) {
-        PrivacyGuideBottomSheetView bottomSheet = new PrivacyGuideBottomSheetView(sheetContent);
+        mBottomSheetView = new PrivacyGuideBottomSheetView(sheetContent, this::closeBottomSheet);
         // TODO(crbug.com/1287979): Re-enable animation once bug is fixed
         if (mBottomSheetController != null) {
-            mBottomSheetController.requestShowContent(bottomSheet, false);
+            mBottomSheetController.requestShowContent(mBottomSheetView, false);
+        }
+    }
+
+    private void closeBottomSheet() {
+        if (mBottomSheetController != null && mBottomSheetView != null) {
+            mBottomSheetController.hideContent(mBottomSheetView, true);
         }
     }
 
diff --git a/chrome/browser/privacy_guide/android/javatests/src/org/chromium/chrome/browser/privacy_guide/PrivacyGuideFragmentTest.java b/chrome/browser/privacy_guide/android/javatests/src/org/chromium/chrome/browser/privacy_guide/PrivacyGuideFragmentTest.java
index 32f615ac..34c544e 100644
--- a/chrome/browser/privacy_guide/android/javatests/src/org/chromium/chrome/browser/privacy_guide/PrivacyGuideFragmentTest.java
+++ b/chrome/browser/privacy_guide/android/javatests/src/org/chromium/chrome/browser/privacy_guide/PrivacyGuideFragmentTest.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.privacy_guide;
 
 import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.Espresso.pressBack;
 import static androidx.test.espresso.action.ViewActions.click;
 import static androidx.test.espresso.action.ViewActions.scrollTo;
 import static androidx.test.espresso.assertion.ViewAssertions.matches;
@@ -928,6 +929,38 @@
     @Test
     @LargeTest
     @Feature({"PrivacyGuide"})
+    @Features.EnableFeatures(ChromeFeatureList.PRIVACY_GUIDE_POST_MVP)
+    public void testSafeBrowsingCard_enhancedBottomSheetBackButtonBehaviour() {
+        launchPrivacyGuide();
+        goToSafeBrowsingCard();
+
+        clickOnArrowNextToRadioButtonWithText(R.string.privacy_guide_safe_browsing_enhanced_title);
+        onViewWaiting(withId(R.id.sb_enhanced_sheet)).check(matches(isDisplayed()));
+
+        pressBack();
+        onViewWaiting(withText(R.string.privacy_guide_safe_browsing_enhanced_title))
+                .check(matches(isDisplayed()));
+    }
+
+    @Test
+    @LargeTest
+    @Feature({"PrivacyGuide"})
+    @Features.EnableFeatures(ChromeFeatureList.PRIVACY_GUIDE_POST_MVP)
+    public void testSafeBrowsingCard_standardBottomSheetBackButtonBehaviour() {
+        launchPrivacyGuide();
+        goToSafeBrowsingCard();
+
+        clickOnArrowNextToRadioButtonWithText(R.string.privacy_guide_safe_browsing_standard_title);
+        onViewWaiting(withId(R.id.sb_standard_sheet)).check(matches(isDisplayed()));
+
+        pressBack();
+        onViewWaiting(withText(R.string.privacy_guide_safe_browsing_standard_title))
+                .check(matches(isDisplayed()));
+    }
+
+    @Test
+    @LargeTest
+    @Feature({"PrivacyGuide"})
     public void testCookiesCard_nextClickCookiesUserAction() {
         launchPrivacyGuide();
         goToCompletionCard();
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
index 4cb1025..44eb09b 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -82,6 +82,7 @@
 #include "chrome/browser/media/media_engagement_service_factory.h"
 #include "chrome/browser/media/router/chrome_media_router_factory.h"
 #include "chrome/browser/media/router/presentation/chrome_local_presentation_manager_factory.h"
+#include "chrome/browser/media/webrtc/media_device_salt_service_factory.h"
 #include "chrome/browser/media/webrtc/webrtc_event_log_manager_keyed_service_factory.h"
 #include "chrome/browser/media_galleries/media_galleries_preferences_factory.h"
 #include "chrome/browser/metrics/variations/google_groups_updater_service_factory.h"
@@ -195,7 +196,6 @@
 #include "components/commerce/core/proto/commerce_subscription_db_content.pb.h"
 #include "components/commerce/core/proto/persisted_state_db_content.pb.h"
 #include "components/enterprise/content/clipboard_restriction_service.h"
-#include "components/media_device_salt/media_device_salt_service_factory.h"
 #include "components/offline_pages/buildflags/buildflags.h"
 #include "components/omnibox/browser/autocomplete_controller_emitter.h"
 #include "components/optimization_guide/core/optimization_guide_switches.h"
@@ -742,7 +742,7 @@
 #if !BUILDFLAG(IS_ANDROID)
   ManagedConfigurationAPIFactory::GetInstance();
 #endif
-  media_device_salt::MediaDeviceSaltServiceFactory::GetInstance();
+  MediaDeviceSaltServiceFactory::GetInstance();
 #if BUILDFLAG(IS_ANDROID)
   MediaDrmOriginIdManagerFactory::GetInstance();
 #endif
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index b6a35bd..5320b19 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -386,8 +386,6 @@
   // Whether a profile is using a default avatar name (eg. Pickles or Person 1).
   registry->RegisterBooleanPref(prefs::kProfileUsingDefaultName, true);
   registry->RegisterStringPref(prefs::kProfileName, std::string());
-
-  registry->RegisterStringPref(prefs::kSupervisedUserId, std::string());
 #if BUILDFLAG(IS_ANDROID)
   uint32_t home_page_flags = PrefRegistry::NO_REGISTRATION_FLAGS;
 #else
diff --git a/chrome/browser/profiles/profile_key.h b/chrome/browser/profiles/profile_key.h
index b32d9eb..c0005a2 100644
--- a/chrome/browser/profiles/profile_key.h
+++ b/chrome/browser/profiles/profile_key.h
@@ -49,7 +49,7 @@
 
  private:
   raw_ptr<PrefService> prefs_ = nullptr;
-  raw_ptr<leveldb_proto::ProtoDatabaseProvider, DanglingUntriaged>
+  raw_ptr<leveldb_proto::ProtoDatabaseProvider, DanglingAcrossTasks>
       db_provider_ = nullptr;
 
   // Points to the original (non off-the-record) ProfileKey.
diff --git a/chrome/browser/resources/chromeos/login/screens/common/gaia_signin.js b/chrome/browser/resources/chromeos/login/screens/common/gaia_signin.js
index 8e860599..9931f83 100644
--- a/chrome/browser/resources/chromeos/login/screens/common/gaia_signin.js
+++ b/chrome/browser/resources/chromeos/login/screens/common/gaia_signin.js
@@ -856,7 +856,7 @@
    * @private
    */
   onIdentifierEnteredMessage_(e) {
-    chrome.send('identifierEntered', [e.detail.accountIdentifier]);
+    this.userActed(['identifierEntered', e.detail.accountIdentifier]);
   }
 
   /**
diff --git a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
index 0b3bb74..828437a 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
@@ -606,12 +606,12 @@
  private:
   std::unique_ptr<TestSafeBrowsingServiceFactory> sb_factory_;
   // Owned by the V4Database.
-  raw_ptr<TestV4DatabaseFactory, DanglingUntriaged> v4_db_factory_;
+  raw_ptr<TestV4DatabaseFactory, DanglingAcrossTasks> v4_db_factory_;
   // Owned by the V4GetHashProtocolManager.
-  raw_ptr<TestV4GetHashProtocolManagerFactory, DanglingUntriaged>
+  raw_ptr<TestV4GetHashProtocolManagerFactory, DanglingAcrossTasks>
       v4_get_hash_factory_;
   // Owned by the V4Database.
-  raw_ptr<TestV4StoreFactory, DanglingUntriaged> store_factory_;
+  raw_ptr<TestV4StoreFactory, DanglingAcrossTasks> store_factory_;
 
 #if defined(ADDRESS_SANITIZER)
   // TODO(lukasza): https://crbug.com/971820: Disallow renderer crashes once the
@@ -1303,7 +1303,8 @@
 
 // Depending on the threat_type classification, if an embedded resource is
 // marked as Malware, an interstitial may be shown.
-IN_PROC_BROWSER_TEST_P(V4SafeBrowsingServiceMetadataTest, MalwareImg) {
+// TODO(crbug.com/1320123): Re-enable this test
+IN_PROC_BROWSER_TEST_P(V4SafeBrowsingServiceMetadataTest, DISABLED_MalwareImg) {
   GURL main_url = embedded_test_server()->GetURL(kMalwarePage);
   GURL img_url = embedded_test_server()->GetURL(kMalwareImg);
 
diff --git a/chrome/browser/safe_browsing/test_safe_browsing_database_helper.h b/chrome/browser/safe_browsing/test_safe_browsing_database_helper.h
index 57119403..5eaa575 100644
--- a/chrome/browser/safe_browsing/test_safe_browsing_database_helper.h
+++ b/chrome/browser/safe_browsing/test_safe_browsing_database_helper.h
@@ -65,11 +65,13 @@
  private:
   std::unique_ptr<safe_browsing::TestSafeBrowsingServiceFactory> sb_factory_;
   // Owned by the V4Database.
-  raw_ptr<InsertingDatabaseFactory, DanglingUntriaged> v4_db_factory_ = nullptr;
+  raw_ptr<InsertingDatabaseFactory, DanglingAcrossTasks> v4_db_factory_ =
+      nullptr;
 
   // Owned by the V4GetHashProtocolManager. Will stay nullptr if the v4 hash
   // factory is not being mocked.
-  raw_ptr<safe_browsing::TestV4GetHashProtocolManagerFactory, DanglingUntriaged>
+  raw_ptr<safe_browsing::TestV4GetHashProtocolManagerFactory,
+          DanglingAcrossTasks>
       v4_get_hash_factory_ = nullptr;
 };
 
diff --git a/chrome/browser/safe_browsing/v4_embedded_test_server_browsertest.cc b/chrome/browser/safe_browsing/v4_embedded_test_server_browsertest.cc
index 3bf67536..a263259 100644
--- a/chrome/browser/safe_browsing/v4_embedded_test_server_browsertest.cc
+++ b/chrome/browser/safe_browsing/v4_embedded_test_server_browsertest.cc
@@ -120,7 +120,7 @@
   std::unique_ptr<net::MappedHostResolver> mapped_host_resolver_;
 
   // Owned by the V4Database.
-  raw_ptr<TestV4DatabaseFactory, DanglingUntriaged> v4_db_factory_ = nullptr;
+  raw_ptr<TestV4DatabaseFactory, DanglingAcrossTasks> v4_db_factory_ = nullptr;
 };
 
 IN_PROC_BROWSER_TEST_F(V4EmbeddedTestServerBrowserTest, SimpleTest) {
diff --git a/chrome/browser/sharing/sharing_fcm_handler.h b/chrome/browser/sharing/sharing_fcm_handler.h
index c5c897a..97928072 100644
--- a/chrome/browser/sharing/sharing_fcm_handler.h
+++ b/chrome/browser/sharing/sharing_fcm_handler.h
@@ -101,7 +101,7 @@
       absl::optional<std::string> message_id,
       SharingChannelType channel_type);
 
-  const raw_ptr<gcm::GCMDriver, DanglingUntriaged> gcm_driver_;
+  const raw_ptr<gcm::GCMDriver, DanglingAcrossTasks> gcm_driver_;
   raw_ptr<syncer::DeviceInfoTracker, DanglingUntriaged> device_info_tracker_;
   raw_ptr<SharingFCMSender, DanglingUntriaged> sharing_fcm_sender_;
   raw_ptr<SharingHandlerRegistry, DanglingUntriaged> handler_registry_;
diff --git a/chrome/browser/sharing/sharing_fcm_sender.h b/chrome/browser/sharing/sharing_fcm_sender.h
index 5f6d925..678acc6 100644
--- a/chrome/browser/sharing/sharing_fcm_sender.h
+++ b/chrome/browser/sharing/sharing_fcm_sender.h
@@ -142,7 +142,7 @@
   raw_ptr<SharingMessageBridge, DanglingUntriaged> sharing_message_bridge_;
   raw_ptr<SharingSyncPreference, DanglingUntriaged> sync_preference_;
   raw_ptr<VapidKeyManager, DanglingUntriaged> vapid_key_manager_;
-  raw_ptr<gcm::GCMDriver, DanglingUntriaged> gcm_driver_;
+  raw_ptr<gcm::GCMDriver, DanglingAcrossTasks> gcm_driver_;
   raw_ptr<syncer::LocalDeviceInfoProvider, DanglingUntriaged>
       local_device_info_provider_;
   raw_ptr<syncer::SyncService, DanglingUntriaged> sync_service_;
diff --git a/chrome/browser/site_isolation/chrome_site_per_process_browsertest.cc b/chrome/browser/site_isolation/chrome_site_per_process_browsertest.cc
index aaa3f2f8..42d6328 100644
--- a/chrome/browser/site_isolation/chrome_site_per_process_browsertest.cc
+++ b/chrome/browser/site_isolation/chrome_site_per_process_browsertest.cc
@@ -1160,9 +1160,8 @@
 
   // Close the second tab.  This should return false to indicate that we're
   // waiting for the beforeunload dialog.
-  int previous_tab_count = tab_strip_model->count();
-  tab_strip_model->CloseWebContentsAt(tab_strip_model->active_index(), 0);
-  EXPECT_EQ(previous_tab_count, tab_strip_model->count());
+  EXPECT_FALSE(
+      tab_strip_model->CloseWebContentsAt(tab_strip_model->active_index(), 0));
 
   // Cancel the dialog and make sure the tab stays alive.
   auto* dialog = ui_test_utils::WaitForAppModalDialog();
@@ -1172,8 +1171,8 @@
   EXPECT_EQ(2, browser()->tab_strip_model()->count());
 
   // Try closing the tab again.
-  tab_strip_model->CloseWebContentsAt(tab_strip_model->active_index(), 0);
-  EXPECT_EQ(previous_tab_count, tab_strip_model->count());
+  EXPECT_FALSE(
+      tab_strip_model->CloseWebContentsAt(tab_strip_model->active_index(), 0));
 
   // Accept the dialog and wait for tab close to complete.
   content::WebContentsDestroyedWatcher destroyed_watcher(second_web_contents);
@@ -1210,10 +1209,10 @@
   EXPECT_TRUE(ExecJs(child, "window.onbeforeunload = () => { return 'x' };"));
   content::PrepContentsForBeforeUnloadTest(second_web_contents);
 
-  // Close the second tab. This should return false to indicate that we're
+  // Close the second tab.  This should return false to indicate that we're
   // waiting for the beforeunload dialog.
-  tab_strip_model->CloseWebContentsAt(tab_strip_model->active_index(), 0);
-  EXPECT_EQ(2, tab_strip_model->count());
+  EXPECT_FALSE(
+      tab_strip_model->CloseWebContentsAt(tab_strip_model->active_index(), 0));
 
   // Cancel the dialog and make sure the tab stays alive.
   auto* dialog = ui_test_utils::WaitForAppModalDialog();
@@ -1223,8 +1222,8 @@
   EXPECT_EQ(2, browser()->tab_strip_model()->count());
 
   // Try closing the tab again.
-  tab_strip_model->CloseWebContentsAt(tab_strip_model->active_index(), 0);
-  EXPECT_EQ(2, tab_strip_model->count());
+  EXPECT_FALSE(
+      tab_strip_model->CloseWebContentsAt(tab_strip_model->active_index(), 0));
 
   // Accept the dialog and wait for tab close to complete.
   content::WebContentsDestroyedWatcher destroyed_watcher(second_web_contents);
@@ -1276,8 +1275,8 @@
 
   // Close the second tab.  This should return false to indicate that we're
   // waiting for the beforeunload dialog.
-  tab_strip_model->CloseWebContentsAt(tab_strip_model->active_index(), 0);
-  EXPECT_EQ(2, tab_strip_model->count());
+  EXPECT_FALSE(
+      tab_strip_model->CloseWebContentsAt(tab_strip_model->active_index(), 0));
 
   // From the first tab, execute window.close() on the popup and wait for the
   // second WebContents to be destroyed.
@@ -1332,8 +1331,8 @@
 
   // Close the second tab.  This should return false to indicate that we're
   // waiting for the beforeunload dialog.
-  tab_strip_model->CloseWebContentsAt(tab_strip_model->active_index(), 0);
-  EXPECT_EQ(2, tab_strip_model->count());
+  EXPECT_FALSE(
+      tab_strip_model->CloseWebContentsAt(tab_strip_model->active_index(), 0));
 
   // From the first tab, execute window.close() on the popup and wait for the
   // second WebContents to be destroyed.
diff --git a/chrome/browser/subresource_filter/subresource_filter_history_observer.h b/chrome/browser/subresource_filter/subresource_filter_history_observer.h
index 6a3e3d5c..74e24f4 100644
--- a/chrome/browser/subresource_filter/subresource_filter_history_observer.h
+++ b/chrome/browser/subresource_filter/subresource_filter_history_observer.h
@@ -47,7 +47,7 @@
 
   // Outlives this object.
   raw_ptr<subresource_filter::SubresourceFilterContentSettingsManager,
-          DanglingUntriaged>
+          DanglingAcrossTasks>
       settings_manager_;
 };
 
diff --git a/chrome/browser/supervised_user/supervised_user_service_factory.cc b/chrome/browser/supervised_user/supervised_user_service_factory.cc
index 7414706..496a406 100644
--- a/chrome/browser/supervised_user/supervised_user_service_factory.cc
+++ b/chrome/browser/supervised_user/supervised_user_service_factory.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_key.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/supervised_user/kids_chrome_management/kids_chrome_management_client_factory.h"
 #include "chrome/browser/supervised_user/supervised_user_browser_utils.h"
 #include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h"
@@ -72,6 +73,7 @@
 // static
 KeyedService* SupervisedUserServiceFactory::BuildInstanceFor(Profile* profile) {
   return new supervised_user::SupervisedUserService(
+      IdentityManagerFactory::GetForProfile(profile),
       KidsChromeManagementClientFactory::GetInstance()->GetForProfile(profile),
       *profile->GetPrefs(),
       *SupervisedUserSettingsServiceFactory::GetInstance()->GetForKey(
@@ -98,6 +100,7 @@
   DependsOn(
       extensions::ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
 #endif
+  DependsOn(IdentityManagerFactory::GetInstance());
   DependsOn(KidsChromeManagementClientFactory::GetInstance());
   DependsOn(SyncServiceFactory::GetInstance());
   DependsOn(SupervisedUserSettingsServiceFactory::GetInstance());
diff --git a/chrome/browser/sync/sessions/sync_sessions_router_tab_helper.h b/chrome/browser/sync/sessions/sync_sessions_router_tab_helper.h
index c2639ad3..f17827c 100644
--- a/chrome/browser/sync/sessions/sync_sessions_router_tab_helper.h
+++ b/chrome/browser/sync/sessions/sync_sessions_router_tab_helper.h
@@ -78,9 +78,9 @@
   // |router_| is a KeyedService and is guaranteed to outlive |this|.
   raw_ptr<SyncSessionsWebContentsRouter, DanglingUntriaged> router_;
 
-  raw_ptr<ChromeTranslateClient, DanglingUntriaged> chrome_translate_client_;
+  raw_ptr<ChromeTranslateClient, DanglingAcrossTasks> chrome_translate_client_;
 
-  raw_ptr<favicon::FaviconDriver, DanglingUntriaged> favicon_driver_;
+  raw_ptr<favicon::FaviconDriver, DanglingAcrossTasks> favicon_driver_;
 
   WEB_CONTENTS_USER_DATA_KEY_DECL();
 };
diff --git a/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc b/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc
index e6905da6..20a469bb 100644
--- a/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc
@@ -201,22 +201,18 @@
   base::test::ScopedFeatureList features_override_;
 };
 
-class SingleClientBookmarksSyncTestWithEnabledThrottling : public SyncTest {
+class SingleClientBookmarksThrottlingSyncTest : public SyncTest {
  public:
-  SingleClientBookmarksSyncTestWithEnabledThrottling()
-      : SyncTest(SINGLE_CLIENT) {
-    features_override_.InitAndEnableFeature(
-        syncer::kSyncExtensionTypesThrottling);
-  }
+  SingleClientBookmarksThrottlingSyncTest() : SyncTest(SINGLE_CLIENT) {}
 
   void SetUpInProcessBrowserTestFixture() override {
     SyncTest::SetUpInProcessBrowserTestFixture();
     create_services_subscription_ =
         BrowserContextDependencyManager::GetInstance()
-            ->RegisterCreateServicesCallbackForTesting(base::BindRepeating(
-                &SingleClientBookmarksSyncTestWithEnabledThrottling::
-                    OnWillCreateBrowserContextServices,
-                base::Unretained(this)));
+            ->RegisterCreateServicesCallbackForTesting(
+                base::BindRepeating(&SingleClientBookmarksThrottlingSyncTest::
+                                        OnWillCreateBrowserContextServices,
+                                    base::Unretained(this)));
   }
 
   void OnWillCreateBrowserContextServices(content::BrowserContext* context) {
@@ -246,7 +242,6 @@
 
  private:
   base::CallbackListSubscription create_services_subscription_;
-  base::test::ScopedFeatureList features_override_;
 };
 
 class SingleClientBookmarksSyncTestWithEnforcedBookmarksCountLimit
@@ -1857,8 +1852,7 @@
                 .value());
 }
 
-IN_PROC_BROWSER_TEST_F(SingleClientBookmarksSyncTestWithEnabledThrottling,
-                       DepleteQuota) {
+IN_PROC_BROWSER_TEST_F(SingleClientBookmarksThrottlingSyncTest, DepleteQuota) {
   ASSERT_TRUE(SetupClients());
 
   // Setup custom quota params: to effectively never refill.
@@ -1891,7 +1885,7 @@
   // Recovering from depleted quota is tested by another test.
 }
 
-IN_PROC_BROWSER_TEST_F(SingleClientBookmarksSyncTestWithEnabledThrottling,
+IN_PROC_BROWSER_TEST_F(SingleClientBookmarksThrottlingSyncTest,
                        DepletedQuotaDoesNotStopCommitCycle) {
   ASSERT_TRUE(SetupClients());
 
@@ -1926,7 +1920,7 @@
                        ModelTypeHistogramValue(syncer::BOOKMARKS)));
 }
 
-IN_PROC_BROWSER_TEST_F(SingleClientBookmarksSyncTestWithEnabledThrottling,
+IN_PROC_BROWSER_TEST_F(SingleClientBookmarksThrottlingSyncTest,
                        DoNotDepleteQuota) {
   ASSERT_TRUE(SetupClients());
 
@@ -1970,7 +1964,7 @@
 }
 
 // TODO(crbug.com/1447535): Disabled due to flakiness.
-IN_PROC_BROWSER_TEST_F(SingleClientBookmarksSyncTestWithEnabledThrottling,
+IN_PROC_BROWSER_TEST_F(SingleClientBookmarksThrottlingSyncTest,
                        DISABLED_DepleteQuotaAndRecover) {
   ASSERT_TRUE(SetupClients());
 
diff --git a/chrome/browser/sync/test/integration/single_client_passwords_sync_test.cc b/chrome/browser/sync/test/integration/single_client_passwords_sync_test.cc
index 9595f20..fb79a6f2 100644
--- a/chrome/browser/sync/test/integration/single_client_passwords_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_passwords_sync_test.cc
@@ -95,49 +95,14 @@
   }
 };
 
-class SingleClientPasswordsSyncTestWithBaseSpecificsInMetadata
-    : public SyncTest {
+class SingleClientPasswordsSyncTestWithNotes : public SyncTest {
  public:
-  SingleClientPasswordsSyncTestWithBaseSpecificsInMetadata()
-      : SyncTest(SINGLE_CLIENT) {
+  SingleClientPasswordsSyncTestWithNotes() : SyncTest(SINGLE_CLIENT) {
     feature_list_.InitWithFeatures(
-        /*enabled_features=*/{syncer::kCacheBaseEntitySpecificsInMetadata},
+        /*enabled_features=*/{syncer::kPasswordNotesWithBackup},
         /*disabled_features=*/{});
   }
-  ~SingleClientPasswordsSyncTestWithBaseSpecificsInMetadata() override =
-      default;
-
- private:
-  base::test::ScopedFeatureList feature_list_;
-};
-
-class SingleClientPasswordsSyncTestWithBaseSpecificsInMetadataAndNotes
-    : public SyncTest {
- public:
-  SingleClientPasswordsSyncTestWithBaseSpecificsInMetadataAndNotes()
-      : SyncTest(SINGLE_CLIENT) {
-    feature_list_.InitWithFeatures(
-        /*enabled_features=*/{syncer::kCacheBaseEntitySpecificsInMetadata,
-                              syncer::kPasswordNotesWithBackup},
-        /*disabled_features=*/{});
-  }
-  ~SingleClientPasswordsSyncTestWithBaseSpecificsInMetadataAndNotes() override =
-      default;
-
- private:
-  base::test::ScopedFeatureList feature_list_;
-};
-
-class SingleClientPasswordsSyncTestWithCachingSpecificsEnabledAfterRestart
-    : public SyncTest {
- public:
-  SingleClientPasswordsSyncTestWithCachingSpecificsEnabledAfterRestart()
-      : SyncTest(SINGLE_CLIENT) {
-    feature_list_.InitWithFeatureState(
-        syncer::kCacheBaseEntitySpecificsInMetadata, GetTestPreCount() == 0);
-  }
-  ~SingleClientPasswordsSyncTestWithCachingSpecificsEnabledAfterRestart()
-      override = default;
+  ~SingleClientPasswordsSyncTestWithNotes() override = default;
 
  private:
   base::test::ScopedFeatureList feature_list_;
@@ -620,7 +585,7 @@
 }
 #endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
-IN_PROC_BROWSER_TEST_F(SingleClientPasswordsSyncTestWithBaseSpecificsInMetadata,
+IN_PROC_BROWSER_TEST_F(SingleClientPasswordsSyncTest,
                        PreservesUnsupportedFieldsDataOnCommits) {
   // Create an unsupported field with an unused tag.
   const std::string kUnsupportedField =
@@ -671,9 +636,8 @@
                   cryptographer.get(), "new_password", kUnsupportedField)));
 }
 
-IN_PROC_BROWSER_TEST_F(
-    SingleClientPasswordsSyncTestWithBaseSpecificsInMetadataAndNotes,
-    PreservesUnsupportedNotesFieldsDataOnCommits) {
+IN_PROC_BROWSER_TEST_F(SingleClientPasswordsSyncTestWithNotes,
+                       PreservesUnsupportedNotesFieldsDataOnCommits) {
   // Create an unsupported field in the PasswordSpecificsData_Notes with an
   // unused tag.
   const std::string kUnsupportedNotesField =
@@ -751,52 +715,6 @@
   }
 }
 
-IN_PROC_BROWSER_TEST_F(
-    SingleClientPasswordsSyncTestWithCachingSpecificsEnabledAfterRestart,
-    PRE_PasswordBridgeIgnoresEntriesWithoutCachedBaseSpecificOnRestart) {
-  // Disabled by the test fixture.
-  ASSERT_FALSE(base::FeatureList::IsEnabled(
-      syncer::kCacheBaseEntitySpecificsInMetadata));
-
-  // Add password entity with caching entity specifics disabled in the PRE test.
-  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
-  PasswordForm form = CreateTestPasswordForm(0);
-  GetProfilePasswordStoreInterface(0)->AddLogin(form);
-  ASSERT_EQ(1, GetPasswordCount(0));
-
-  // Setup sync, wait for its completion, and make sure changes were synced.
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
-  ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait());
-}
-
-// Regression test for crrev.com/c/3755526. Checks that password bridge ignores
-// entries without a password field in entity specifics cache (added by the PRE
-// test with `syncer::kCacheBaseEntitySpecificsInMetadata` disabled).
-IN_PROC_BROWSER_TEST_F(
-    SingleClientPasswordsSyncTestWithCachingSpecificsEnabledAfterRestart,
-    PasswordBridgeIgnoresEntriesWithoutCachedBaseSpecificOnRestart) {
-  // Enabled by the test fixture.
-  ASSERT_TRUE(base::FeatureList::IsEnabled(
-      syncer::kCacheBaseEntitySpecificsInMetadata));
-
-  base::HistogramTester histogram_tester;
-  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
-  ASSERT_EQ(1, GetPasswordCount(0));
-
-  // Wait for data types to be ready for sync (and hence model types are
-  // loaded).
-  ASSERT_TRUE(GetClient(0)->AwaitSyncSetupCompletion());
-
-  // The original metric is defined in password_sync_bridge.cc.
-  const int kNone = 0;
-  // Since the local base entity specifics cache doesn't contain supported
-  // fields, running into the initial sync flow is not expected. Since the
-  // bridge is initialized for both account and profile store, the metric is
-  // expected to be recorded twice.
-  histogram_tester.ExpectUniqueSample("PasswordManager.SyncMetadataReadError2",
-                                      kNone, /*expected_bucket_count=*/2);
-}
-
 // The follow 3 tests are testing the interaction between clients that support
 // and don't support notes. The test fixture enables the features for even
 // number of PREs.
diff --git a/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc b/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc
index e43cb7c5..20ce4f1 100644
--- a/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc
@@ -50,18 +50,6 @@
   }
 };
 
-class SingleClientUserEventsSyncTestWithEnabledThrottling
-    : public SingleClientUserEventsSyncTest {
- public:
-  SingleClientUserEventsSyncTestWithEnabledThrottling() {
-    features_override_.InitAndEnableFeature(
-        syncer::kSyncExtensionTypesThrottling);
-  }
-
- private:
-  base::test::ScopedFeatureList features_override_;
-};
-
 IN_PROC_BROWSER_TEST_F(SingleClientUserEventsSyncTest, Sanity) {
   ASSERT_TRUE(SetupSync());
   EXPECT_EQ(
@@ -248,8 +236,7 @@
 
 // This is an analogy to SingleClientBookmarksSyncTest.DepleteQuota, tested on
 // a datatype that has no quota restrictions.
-IN_PROC_BROWSER_TEST_F(SingleClientUserEventsSyncTestWithEnabledThrottling,
-                       NoQuotaApplied) {
+IN_PROC_BROWSER_TEST_F(SingleClientUserEventsSyncTest, NoQuotaApplied) {
   ASSERT_TRUE(SetupSync());
   // Add enough user events that would deplete quota in the initial cycle.
   syncer::UserEventService* event_service =
diff --git a/chrome/browser/sync_file_system/local/sync_file_system_backend.h b/chrome/browser/sync_file_system/local/sync_file_system_backend.h
index 2748e3922..c58cd484b 100644
--- a/chrome/browser/sync_file_system/local/sync_file_system_backend.h
+++ b/chrome/browser/sync_file_system/local/sync_file_system_backend.h
@@ -95,7 +95,7 @@
 
   // |profile_| will initially be valid but may be destroyed before |this|, so
   // it should be checked before being accessed.
-  raw_ptr<Profile, DanglingUntriaged> profile_;
+  raw_ptr<Profile, DanglingAcrossTasks> profile_;
 
   // A flag to skip the initialization sequence of SyncFileSystemService for
   // testing.
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
index 33a8c36af..e539ed47 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
+++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -4083,13 +4083,13 @@
               Manage account
       </message>
       <message name="IDS_ACCESSIBILITY_TOOLBAR_BTN_IDENTITY_DISC_WITH_NAME_AND_EMAIL" desc="The content description for a toolbar button displaying user profile picture. Tapping on this button navigates to 'Sync and Google services' page in settings">
-        Signed in as <ph name="USER_NAME">%1$s<ex>Peter Parker</ex></ph>. <ph name="USER_EMAIL">%2$s<ex>peter.parker@gmail.com</ex></ph>. Button. Opens settings.
+        Signed in as <ph name="USER_NAME">%1$s<ex>Peter Parker</ex></ph>. <ph name="USER_EMAIL">%2$s<ex>peter.parker@gmail.com</ex></ph>. Opens settings.
       </message>
       <message name="IDS_ACCESSIBILITY_TOOLBAR_BTN_IDENTITY_DISC_WITH_NAME" desc="The content description for a toolbar button displaying user profile picture, for users who don't have a readable email address. Tapping on this button navigates to 'Sync and Google services' page in settings">
-              Signed in as <ph name="USER_NAME">%s<ex>Bruce Wayne</ex></ph>. Button. Opens settings.
+              Signed in as <ph name="USER_NAME">%s<ex>Bruce Wayne</ex></ph>. Opens settings.
       </message>
       <message name="IDS_ACCESSIBILITY_TOOLBAR_BTN_SIGNED_OUT_IDENTITY_DISC" desc="The content description for a toolbar button displaying the signed-out avatar. Tapping on this button navigates to 'Turn on Sync' page in settings">
-        Signed out. Button. Opens dialog to sign in and turn on sync.
+        Signed out. Opens dialog to sign in and turn on sync.
       </message>
       <message name="IDS_ACCESSIBILITY_TOOLBAR_BTN_HOME" desc="Content description for the home button.">
         Home
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESSIBILITY_TOOLBAR_BTN_IDENTITY_DISC_WITH_NAME.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESSIBILITY_TOOLBAR_BTN_IDENTITY_DISC_WITH_NAME.png.sha1
index 46b560c..27152453 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESSIBILITY_TOOLBAR_BTN_IDENTITY_DISC_WITH_NAME.png.sha1
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESSIBILITY_TOOLBAR_BTN_IDENTITY_DISC_WITH_NAME.png.sha1
@@ -1 +1 @@
-07dfa23554442801c1ace4b0f9705311f50a4190
\ No newline at end of file
+b356d0087512a0a7f90f14fa566b5c80e24702e1
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESSIBILITY_TOOLBAR_BTN_IDENTITY_DISC_WITH_NAME_AND_EMAIL.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESSIBILITY_TOOLBAR_BTN_IDENTITY_DISC_WITH_NAME_AND_EMAIL.png.sha1
index 46b560c..54352cb5 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESSIBILITY_TOOLBAR_BTN_IDENTITY_DISC_WITH_NAME_AND_EMAIL.png.sha1
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESSIBILITY_TOOLBAR_BTN_IDENTITY_DISC_WITH_NAME_AND_EMAIL.png.sha1
@@ -1 +1 @@
-07dfa23554442801c1ace4b0f9705311f50a4190
\ No newline at end of file
+29a58bf7c796a2e97dc401fb7e004fff848cbf35
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESSIBILITY_TOOLBAR_BTN_SIGNED_OUT_IDENTITY_DISC.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESSIBILITY_TOOLBAR_BTN_SIGNED_OUT_IDENTITY_DISC.png.sha1
index b90976f1..54352cb5 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESSIBILITY_TOOLBAR_BTN_SIGNED_OUT_IDENTITY_DISC.png.sha1
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESSIBILITY_TOOLBAR_BTN_SIGNED_OUT_IDENTITY_DISC.png.sha1
@@ -1 +1 @@
-08869ca759e078de6a5c680d231722da7e5beb98
\ No newline at end of file
+29a58bf7c796a2e97dc401fb7e004fff848cbf35
\ No newline at end of file
diff --git a/chrome/browser/ui/ash/shelf/app_shortcut_shelf_item_controller_browsertest.cc b/chrome/browser/ui/ash/shelf/app_shortcut_shelf_item_controller_browsertest.cc
index 90cf7cf..b109f311 100644
--- a/chrome/browser/ui/ash/shelf/app_shortcut_shelf_item_controller_browsertest.cc
+++ b/chrome/browser/ui/ash/shelf/app_shortcut_shelf_item_controller_browsertest.cc
@@ -133,12 +133,12 @@
                                          /*command_id=*/0, ui::EF_NONE,
                                          display::kInvalidDisplayId);
 
-  // Shift-clicking on an item should not close it as it is a pinned home tab.
+  // Shift-clicking on an item should close it.
   EXPECT_EQ(2u, GetAppMenuItems(0).size());
   GetShelfItemDelegate()->ExecuteCommand(/*from_context_menu=*/false,
                                          /*command_id=*/0, ui::EF_SHIFT_DOWN,
                                          display::kInvalidDisplayId);
-  EXPECT_EQ(2u, GetAppMenuItems(0).size());
+  EXPECT_EQ(1u, GetAppMenuItems(0).size());
 }
 
 // Test interacting with the app menu with shift key down: the app menu has
@@ -179,16 +179,10 @@
                                          /*command_id=*/0, ui::EF_NONE,
                                          display::kInvalidDisplayId);
 
-  // Shift-clicking on an item should not close it if it is a pinned home tab.
+  // Shift-clicking on a item should close it.
   EXPECT_EQ(3u, GetAppMenuItems(ui::EF_SHIFT_DOWN).size());
   GetShelfItemDelegate()->ExecuteCommand(/*from_context_menu=*/false,
                                          /*command_id=*/0, ui::EF_SHIFT_DOWN,
                                          display::kInvalidDisplayId);
-  EXPECT_EQ(3u, GetAppMenuItems(ui::EF_SHIFT_DOWN).size());
-
-  // Shift-clicking on an item that is not a pinned home tab should close it.
-  GetShelfItemDelegate()->ExecuteCommand(/*from_context_menu=*/false,
-                                         /*command_id=*/1, ui::EF_SHIFT_DOWN,
-                                         display::kInvalidDisplayId);
   EXPECT_EQ(2u, GetAppMenuItems(ui::EF_SHIFT_DOWN).size());
 }
diff --git a/chrome/browser/ui/autofill/autofill_context_menu_manager.cc b/chrome/browser/ui/autofill/autofill_context_menu_manager.cc
index 2d9c1a70..01016587 100644
--- a/chrome/browser/ui/autofill/autofill_context_menu_manager.cc
+++ b/chrome/browser/ui/autofill/autofill_context_menu_manager.cc
@@ -256,7 +256,7 @@
   chrome::ShowFeedbackPage(
       browser_, chrome::kFeedbackSourceAutofillContextMenu,
       /*description_template=*/std::string(),
-      /*description_placeholder_text=*/std::string(kFeedbackPlaceholder),
+      /*description_placeholder_text=*/kFeedbackPlaceholder,
       /*category_tag=*/"dogfood_autofill_feedback",
       /*extra_diagnostics=*/std::string(),
       /*autofill_metadata=*/
diff --git a/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl_unittest.cc b/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl_unittest.cc
index 17f7f38..8e97a9d6 100644
--- a/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl_unittest.cc
+++ b/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl_unittest.cc
@@ -113,11 +113,10 @@
               Run(AutofillClient::SaveAddressProfileOfferUserDecision::kIgnored,
                   testing::_));
   // Close controller tab.
-  int previous_tab_count = browser()->tab_strip_model()->count();
-  browser()->tab_strip_model()->CloseWebContentsAt(
+  EXPECT_TRUE(browser()->tab_strip_model()->CloseWebContentsAt(
       tab_strip_model->GetIndexOfWebContents(controller_web_contents),
-      TabCloseTypes::CLOSE_USER_GESTURE);
-  EXPECT_EQ(previous_tab_count - 1, browser()->tab_strip_model()->count());
+      TabCloseTypes::CLOSE_USER_GESTURE));
+  EXPECT_EQ(1, tab_strip_model->count());
 }
 
 // This is testing that when the SaveAddressProfilePromptOptions has the
diff --git a/chrome/browser/ui/bookmarks/bookmark_browsertest.cc b/chrome/browser/ui/bookmarks/bookmark_browsertest.cc
index 52fb323..d798540 100644
--- a/chrome/browser/ui/bookmarks/bookmark_browsertest.cc
+++ b/chrome/browser/ui/bookmarks/bookmark_browsertest.cc
@@ -303,9 +303,9 @@
   auto close_all_tabs_except_first = [](Browser* browser) {
     int num_tabs = browser->tab_strip_model()->GetTabCount();
     for (int i = 0; i < num_tabs - 1; ++i) {
-      browser->tab_strip_model()->CloseWebContentsAt(num_tabs - 1 - i, 0);
+      ASSERT_TRUE(
+          browser->tab_strip_model()->CloseWebContentsAt(num_tabs - 1 - i, 0));
     }
-    EXPECT_EQ(1, browser->tab_strip_model()->count());
   };
 
   auto open_urls_and_test = [&regular_browser, &incognito_browser, &bbar,
diff --git a/chrome/browser/ui/bookmarks/bookmark_tab_helper.h b/chrome/browser/ui/bookmarks/bookmark_tab_helper.h
index 91868a2..359b9c43 100644
--- a/chrome/browser/ui/bookmarks/bookmark_tab_helper.h
+++ b/chrome/browser/ui/bookmarks/bookmark_tab_helper.h
@@ -104,7 +104,7 @@
 
   // The BookmarkDrag is used to forward bookmark drag and drop events to
   // extensions.
-  raw_ptr<BookmarkDrag, DanglingUntriaged> bookmark_drag_;
+  raw_ptr<BookmarkDrag, DanglingAcrossTasks> bookmark_drag_;
 
   WEB_CONTENTS_USER_DATA_KEY_DECL();
 };
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h
index 2cbbda0..55d2b67 100644
--- a/chrome/browser/ui/browser.h
+++ b/chrome/browser/ui/browser.h
@@ -247,7 +247,7 @@
     Type type;
 
     // The associated profile.
-    raw_ptr<Profile, DanglingUntriaged> profile;
+    raw_ptr<Profile, DanglingAcrossTasks> profile;
 
     // Specifies the browser `is_trusted_source_` value.
     bool trusted_source = false;
@@ -1189,7 +1189,7 @@
   const Type type_;
 
   // This Browser's profile.
-  const raw_ptr<Profile, DanglingUntriaged> profile_;
+  const raw_ptr<Profile, DanglingAcrossTasks> profile_;
 
   // Prevent Profile deletion until this browser window is closed.
   std::unique_ptr<ScopedProfileKeepAlive> profile_keep_alive_;
diff --git a/chrome/browser/ui/browser_navigator_browsertest.cc b/chrome/browser/ui/browser_navigator_browsertest.cc
index 6748989d..8a476df 100644
--- a/chrome/browser/ui/browser_navigator_browsertest.cc
+++ b/chrome/browser/ui/browser_navigator_browsertest.cc
@@ -697,10 +697,8 @@
 
   NavigateHelper(GURL("chrome://about"), browser(),
                  WindowOpenDisposition::NEW_FOREGROUND_TAB, true);
-  int previous_tab_count = browser()->tab_strip_model()->count();
   browser()->tab_strip_model()->CloseWebContentsAt(0,
                                                    TabCloseTypes::CLOSE_NONE);
-  EXPECT_EQ(previous_tab_count - 1, browser()->tab_strip_model()->count());
   // This expects a new WebContents, since we just closed the tab.
   NavigateHelper(singleton_url, browser(), WindowOpenDisposition::SWITCH_TO_TAB,
                  true, nullptr /* expected_contents */);
@@ -1612,10 +1610,8 @@
     observer.Wait();
   }
 
-  int previous_tab_count = browser()->tab_strip_model()->count();
-  browser()->tab_strip_model()->CloseWebContentsAt(
-      2, TabCloseTypes::CLOSE_USER_GESTURE);
-  EXPECT_EQ(previous_tab_count - 1, browser()->tab_strip_model()->count());
+  EXPECT_TRUE(browser()->tab_strip_model()->CloseWebContentsAt(
+      2, TabCloseTypes::CLOSE_USER_GESTURE));
   EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
 }
 
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
index e89a2f60..f439e355 100644
--- a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
+++ b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
@@ -703,6 +703,12 @@
     WebContents* web_contents)
     : ContentSettingBubbleModel(delegate, web_contents) {
   set_title(l10n_util::GetStringUTF16(IDS_SITE_SETTINGS_TYPE_STORAGE_ACCESS));
+
+  // TODO(crbug.com/1433644): Consider to add subtitles to all permissions.
+  set_subtitle(url_formatter::FormatUrlForSecurityDisplay(
+      web_contents->GetURL(),
+      url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC));
+
   set_message(l10n_util::GetStringFUTF16(
       IDS_STORAGE_ACCESS_PERMISSION_BUBBLE_MESSAGE,
       url_formatter::FormatUrlForSecurityDisplay(
@@ -713,6 +719,11 @@
       PageSpecificContentSettings::GetForFrame(&GetPage().GetMainDocument());
   set_site_list(page_content_settings->GetTwoSiteRequests(
       ContentSettingsType::STORAGE_ACCESS));
+
+  set_manage_text_style(ManageTextStyle::kHoverButton);
+  set_manage_text(l10n_util::GetStringUTF16(IDS_STORAGE_ACCESS_MANAGE_TEXT));
+  set_manage_tooltip(
+      l10n_util::GetStringUTF16(IDS_STORAGE_ACCESS_MANAGE_TOOLTIP));
 }
 
 ContentSettingStorageAccessBubbleModel::
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model.h b/chrome/browser/ui/content_settings/content_setting_bubble_model.h
index d9fc9a5..1c8d1b1 100644
--- a/chrome/browser/ui/content_settings/content_setting_bubble_model.h
+++ b/chrome/browser/ui/content_settings/content_setting_bubble_model.h
@@ -135,6 +135,9 @@
     kButton,
     // Manage text is used as a checkbox title.
     kCheckbox,
+    // Manage text is shown in a HoverButton. The "Manage" and "Done" buttons
+    // are hidden.
+    kHoverButton,
   };
 
   struct BubbleContent {
@@ -146,6 +149,7 @@
     ~BubbleContent();
 
     std::u16string title;
+    std::u16string subtitle;
     std::u16string message;
     // Whether the user can modify the content of the bubble.
     // False if controlled by policy, etc.
@@ -156,6 +160,7 @@
     std::u16string custom_link;
     bool custom_link_enabled = false;
     std::u16string manage_text;
+    std::u16string manage_tooltip;
     ManageTextStyle manage_text_style = ManageTextStyle::kButton;
     MediaMenuMap media_menus;
     bool show_learn_more = false;
@@ -242,6 +247,9 @@
   content::Page& GetPage() const { return web_contents_->GetPrimaryPage(); }
 
   void set_title(const std::u16string& title) { bubble_content_.title = title; }
+  void set_subtitle(const std::u16string& subtitle) {
+    bubble_content_.subtitle = subtitle;
+  }
   void set_message(const std::u16string& message) {
     bubble_content_.message = message;
   }
@@ -263,6 +271,9 @@
   void set_manage_text(const std::u16string& text) {
     bubble_content_.manage_text = text;
   }
+  void set_manage_tooltip(const std::u16string& text) {
+    bubble_content_.manage_tooltip = text;
+  }
   void set_manage_text_style(ManageTextStyle manage_text_style) {
     bubble_content_.manage_text_style = manage_text_style;
   }
diff --git a/chrome/browser/ui/passwords/manage_passwords_state.h b/chrome/browser/ui/passwords/manage_passwords_state.h
index c2fdcee..4817210 100644
--- a/chrome/browser/ui/passwords/manage_passwords_state.h
+++ b/chrome/browser/ui/passwords/manage_passwords_state.h
@@ -163,7 +163,7 @@
   password_manager::ui::State state_;
 
   // The client used for logging.
-  raw_ptr<password_manager::PasswordManagerClient, DanglingUntriaged> client_;
+  raw_ptr<password_manager::PasswordManagerClient, DanglingAcrossTasks> client_;
 
   // Whether the last attempt to authenticate to opt-in using password account
   // storage failed.
diff --git a/chrome/browser/ui/tabs/pinned_tab_service_browsertest.cc b/chrome/browser/ui/tabs/pinned_tab_service_browsertest.cc
index 1e0ea7d4..fd265f9 100644
--- a/chrome/browser/ui/tabs/pinned_tab_service_browsertest.cc
+++ b/chrome/browser/ui/tabs/pinned_tab_service_browsertest.cc
@@ -81,9 +81,9 @@
       profile, ProfileKeepAliveOrigin::kBrowserWindow);
   BrowserRemovalWaiter waiter(browser());
   tab_strip_model->SetTabPinned(0, false);
-  int previous_tab_count = tab_strip_model->count();
-  tab_strip_model->CloseWebContentsAt(0, TabCloseTypes::CLOSE_NONE);
-  EXPECT_EQ(previous_tab_count - 1, tab_strip_model->count());
+  EXPECT_TRUE(
+      tab_strip_model->CloseWebContentsAt(0, TabCloseTypes::CLOSE_NONE));
+  EXPECT_TRUE(tab_strip_model->empty());
   waiter.WaitForRemoval();
 
   // Let's see it's cleared out properly.
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc
index 311daa4..2878ae66 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -56,10 +56,6 @@
 #include "chrome/browser/ui/web_applications/web_app_dialog_utils.h"
 #include "chrome/browser/ui/web_applications/web_app_launch_utils.h"
 #include "chrome/browser/ui/web_applications/web_app_tabbed_utils.h"
-#include "chrome/browser/web_applications/policy/web_app_policy_manager.h"
-#include "chrome/browser/web_applications/web_app_id.h"
-#include "chrome/browser/web_applications/web_app_provider.h"
-#include "chrome/browser/web_applications/web_app_tab_helper.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
@@ -125,7 +121,7 @@
                                       ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
 }
 
-// Installs RenderWidgetVisibilityTracker when the active tab has changed.
+// Intalls RenderWidgetVisibilityTracker when the active tab has changed.
 std::unique_ptr<RenderWidgetHostVisibilityTracker>
 InstallRenderWigetVisibilityTracker(const TabStripSelectionChange& selection) {
   if (!selection.active_tab_changed())
@@ -270,7 +266,7 @@
   //
   // Once the notification for change of active web contents has been sent,
   // this field is set to nullptr.
-  raw_ptr<WebContents, DanglingUntriaged> initially_active_web_contents =
+  raw_ptr<WebContents, DanglingAcrossTasks> initially_active_web_contents =
       nullptr;
 
   // The WebContents that were recently detached. Observers need to be notified
@@ -718,10 +714,10 @@
   CloseTabs(closing_tabs, TabCloseTypes::CLOSE_CREATE_HISTORICAL_TAB);
 }
 
-void TabStripModel::CloseWebContentsAt(int index, uint32_t close_types) {
+bool TabStripModel::CloseWebContentsAt(int index, uint32_t close_types) {
   CHECK(ContainsIndex(index));
   WebContents* contents = GetWebContentsAt(index);
-  CloseTabs(base::span<WebContents* const>(&contents, 1u), close_types);
+  return CloseTabs(base::span<WebContents* const>(&contents, 1u), close_types);
 }
 
 bool TabStripModel::TabsAreLoading() const {
@@ -831,12 +827,7 @@
 }
 
 bool TabStripModel::IsTabClosable(int index) const {
-  return PolicyAllowsTabClosing(GetWebContentsAt(index)) &&
-         (!web_app::IsPinnedHomeTab(this, index) || count() == 1);
-}
-
-bool TabStripModel::IsTabClosable(const content::WebContents* contents) const {
-  return IsTabClosable(GetIndexOfWebContents(contents));
+  return !web_app::IsPinnedHomeTab(this, index) || count() == 1;
 }
 
 absl::optional<tab_groups::TabGroupId> TabStripModel::GetTabGroupForTab(
@@ -1870,29 +1861,21 @@
   return index;
 }
 
-void TabStripModel::CloseTabs(base::span<content::WebContents* const> items,
+bool TabStripModel::CloseTabs(base::span<content::WebContents* const> items,
                               uint32_t close_types) {
-  std::vector<content::WebContents*> filtered_items;
-  base::ranges::copy_if(items, std::back_inserter(filtered_items),
-                        [this](content::WebContents* const contents) {
-                          return IsTabClosable(contents);
-                        });
+  if (items.empty())
+    return true;
 
-  if (filtered_items.empty()) {
-    return;
-  }
-
-  const bool closing_all = static_cast<int>(filtered_items.size()) == count();
+  const bool closing_all = static_cast<int>(items.size()) == count();
   base::WeakPtr<TabStripModel> ref = weak_factory_.GetWeakPtr();
   if (closing_all) {
-    for (auto& observer : observers_) {
+    for (auto& observer : observers_)
       observer.WillCloseAllTabs(this);
-    }
   }
 
   DetachNotifications notifications(GetActiveWebContents(), selection_model_);
   const bool closed_all =
-      CloseWebContentses(filtered_items, close_types, &notifications);
+      CloseWebContentses(items, close_types, &notifications);
 
   // When unload handler is triggered for all items, we should wait for the
   // result.
@@ -1900,7 +1883,7 @@
     SendDetachWebContentsNotifications(&notifications);
 
   if (!ref)
-    return;
+    return closed_all;
   if (closing_all) {
     // CloseAllTabsStopped is sent with reason kCloseAllCompleted if
     // closed_all; otherwise kCloseAllCanceled is sent.
@@ -1909,6 +1892,8 @@
           this, closed_all ? TabStripModelObserver::kCloseAllCompleted
                            : TabStripModelObserver::kCloseAllCanceled);
   }
+
+  return closed_all;
 }
 
 bool TabStripModel::CloseWebContentses(
@@ -2630,24 +2615,6 @@
   }
 }
 
-bool TabStripModel::PolicyAllowsTabClosing(
-    content::WebContents* contents) const {
-  if (!contents) {
-    return true;
-  }
-
-  web_app::WebAppProvider* provider =
-      web_app::WebAppProvider::GetForWebContents(contents);
-  // Can be null if there is no tab helper or app id.
-  const web_app::AppId* app_id = web_app::WebAppTabHelper::GetAppId(contents);
-  if (!app_id) {
-    return true;
-  }
-
-  return !delegate()->IsForWebApp() ||
-         !provider->policy_manager().IsPreventCloseEnabled(*app_id);
-}
-
 int TabStripModel::DetermineInsertionIndex(ui::PageTransition transition,
                                            bool foreground) {
   int tab_count = count();
diff --git a/chrome/browser/ui/tabs/tab_strip_model.h b/chrome/browser/ui/tabs/tab_strip_model.h
index 5656b5d..b396ba4 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.h
+++ b/chrome/browser/ui/tabs/tab_strip_model.h
@@ -114,7 +114,7 @@
     // guaranteed to be valid for the life time of the notification (and
     // possibly longer).
     std::unique_ptr<content::WebContents> owned_contents;
-    raw_ptr<content::WebContents, DanglingUntriaged> contents;
+    raw_ptr<content::WebContents, DanglingAcrossTasks> contents;
 
     // The index of the WebContents in the original selection model of the tab
     // strip [prior to any tabs being removed, if multiple tabs are being
@@ -214,8 +214,11 @@
       absl::optional<tab_groups::TabGroupId> group = absl::nullopt);
   // Closes the WebContents at the specified index. This causes the
   // WebContents to be destroyed, but it may not happen immediately.
-  // |close_types| is a bitmask of CloseTypes.
-  void CloseWebContentsAt(int index, uint32_t close_types);
+  // |close_types| is a bitmask of CloseTypes. Returns true if the
+  // WebContents was closed immediately, false if it was not closed (we
+  // may be waiting for a response from an onunload handler, or waiting for the
+  // user to confirm closure).
+  bool CloseWebContentsAt(int index, uint32_t close_types);
 
   // Replaces the WebContents at |index| with |new_contents|. The
   // WebContents that was at |index| is returned and its ownership returns
@@ -347,10 +350,6 @@
   // Returns true if the tab at |index| is allowed to be closed.
   bool IsTabClosable(int index) const;
 
-  // Returns true if the tab corresponding to |contents| is allowed to be
-  // closed.
-  bool IsTabClosable(const content::WebContents* contents) const;
-
   // Returns the group that contains the tab at |index|, or nullopt if the tab
   // index is invalid or not grouped.
   absl::optional<tab_groups::TabGroupId> GetTabGroupForTab(
@@ -670,7 +669,10 @@
   // the page in question has an unload event the WebContents will not be
   // destroyed until after the event has completed, which will then call back
   // into this method.
-  void CloseTabs(base::span<content::WebContents* const> items,
+  //
+  // Returns true if the WebContentses were closed immediately, false if we
+  // are waiting for the result of an onunload handler.
+  bool CloseTabs(base::span<content::WebContents* const> items,
                  uint32_t close_types);
 
   // |close_types| is a bitmask of the types in CloseTypes.
@@ -799,9 +801,6 @@
   // Takes the |selection| change and decides whether to forget the openers.
   void OnActiveTabChanged(const TabStripSelectionChange& selection);
 
-  // Checks if policy allows a tab to be closed.
-  bool PolicyAllowsTabClosing(content::WebContents* contents) const;
-
   // Determine where to shift selection after a tab is closed.
   absl::optional<int> DetermineNewSelectedIndex(int removed_index) const;
 
@@ -819,7 +818,7 @@
   base::ObserverList<TabStripModelObserver>::Unchecked observers_;
 
   // A profile associated with this TabStripModel.
-  raw_ptr<Profile, DanglingUntriaged> profile_;
+  raw_ptr<Profile, DanglingAcrossTasks> profile_;
 
   // True if all tabs are currently being closed via CloseAllTabs.
   bool closing_all_ = false;
diff --git a/chrome/browser/ui/tabs/tab_strip_model_browsertest.cc b/chrome/browser/ui/tabs/tab_strip_model_browsertest.cc
deleted file mode 100644
index 6ff2d2c6..0000000
--- a/chrome/browser/ui/tabs/tab_strip_model_browsertest.cc
+++ /dev/null
@@ -1,155 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-
-#include "base/json/json_reader.h"
-#include "base/test/scoped_feature_list.h"
-#include "base/values.h"
-#include "chrome/browser/policy/policy_test_utils.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
-#include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
-#include "chrome/browser/web_applications/web_app_id.h"
-#include "chrome/browser/web_applications/web_app_id_constants.h"
-#include "chrome/browser/web_applications/web_app_install_info.h"
-#include "chrome/common/chrome_features.h"
-#include "components/policy/core/browser/browser_policy_connector.h"
-#include "components/policy/core/browser/browser_policy_connector_base.h"
-#include "components/policy/core/common/mock_configuration_policy_provider.h"
-#include "components/policy/core/common/policy_map.h"
-#include "components/policy/policy_constants.h"
-#include "content/public/test/browser_test.h"
-#include "ui/base/window_open_disposition.h"
-#include "url/gurl.h"
-
-namespace {
-constexpr char kCalculatorAppUrl[] = "https://calculator.apps.chrome/";
-
-constexpr char kPreventCloseEnabledForCalculator[] = R"([
-  {
-    "manifest_id": "https://calculator.apps.chrome/",
-    "run_on_os_login": "run_windowed",
-    "prevent_close_after_run_on_login": true
-  }
-])";
-
-#if BUILDFLAG(IS_CHROMEOS)
-constexpr bool kShouldPreventClose = true;
-#else
-constexpr bool kShouldPreventClose = false;
-#endif  // BUILDFLAG(IS_CHROMEOS)
-
-}  // namespace
-
-class TabStripModelPreventCloseTest : public policy::PolicyTest {
- public:
-  TabStripModelPreventCloseTest() {
-    scoped_feature_list_.InitWithFeatures(
-        /*enabled_features=*/{features::kDesktopPWAsEnforceWebAppSettingsPolicy,
-                              features::kDesktopPWAsPreventClose},
-        /*disabled_features=*/{});
-  }
-  TabStripModelPreventCloseTest(const TabStripModelPreventCloseTest&) = delete;
-  TabStripModelPreventCloseTest& operator=(
-      const TabStripModelPreventCloseTest&) = delete;
-  ~TabStripModelPreventCloseTest() override = default;
-
-  void SetUpInProcessBrowserTestFixture() override {
-    provider_.SetDefaultReturns(
-        /*is_initialization_complete_return=*/true,
-        /*is_first_policy_load_complete_return=*/true);
-    policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_);
-  }
-
-  void TearDownInProcessBrowserTestFixture() override {
-    ClearWebAppSettings();
-    policy::PolicyTest::TearDownInProcessBrowserTestFixture();
-  }
-
-  void SetWebAppSettings(base::StringPiece config) {
-    policy::PolicyMap policies;
-    SetPolicy(&policies, policy::key::kWebAppSettings,
-              ReturnPolicyValueFromJson(config));
-    provider_.UpdateChromePolicy(policies);
-  }
-
-  void ClearWebAppSettings() { SetWebAppSettings(/*config=*/"[]"); }
-
-  void InstallPWA(const GURL& app_url, const web_app::AppId& app_id) {
-    auto web_app_info = std::make_unique<web_app::WebAppInstallInfo>();
-    web_app_info->start_url = app_url;
-    web_app_info->scope = app_url.GetWithoutFilename();
-    web_app::AppId installed_app_id = web_app::test::InstallWebApp(
-        browser()->profile(), std::move(web_app_info));
-    EXPECT_EQ(app_id, installed_app_id);
-  }
-
-  Browser* LaunchPWA(const web_app::AppId& app_id, bool launch_in_window) {
-    return launch_in_window
-               ? web_app::LaunchWebAppBrowserAndWait(
-                     profile(), app_id, WindowOpenDisposition::NEW_WINDOW)
-               : web_app::LaunchBrowserForWebAppInTab(profile(), app_id);
-  }
-
-  base::Value ReturnPolicyValueFromJson(base::StringPiece policy) {
-    auto result = base::JSONReader::ReadAndReturnValueWithError(
-        policy, base::JSONParserOptions::JSON_ALLOW_TRAILING_COMMAS);
-    DCHECK(result.has_value()) << result.error().message;
-    DCHECK(result->is_list());
-    return std::move(*result);
-  }
-
-  Profile* profile() { return browser()->profile(); }
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-  testing::NiceMock<policy::MockConfigurationPolicyProvider> provider_;
-};
-
-IN_PROC_BROWSER_TEST_F(TabStripModelPreventCloseTest,
-                       PreventCloseEnforedByPolicy) {
-  InstallPWA(GURL(kCalculatorAppUrl), web_app::kCalculatorAppId);
-  SetWebAppSettings(kPreventCloseEnabledForCalculator);
-
-  Browser* const browser =
-      LaunchPWA(web_app::kCalculatorAppId, /*launch_in_window=*/true);
-  ASSERT_TRUE(browser);
-
-  TabStripModel* const tab_strip_model = browser->tab_strip_model();
-  EXPECT_EQ(1, tab_strip_model->count());
-  EXPECT_EQ(!kShouldPreventClose, tab_strip_model->IsTabClosable(
-                                      tab_strip_model->GetActiveWebContents()));
-
-  tab_strip_model->CloseAllTabs();
-  EXPECT_EQ(kShouldPreventClose ? 1 : 0, tab_strip_model->count());
-
-  if (kShouldPreventClose) {
-    ClearWebAppSettings();
-    EXPECT_TRUE(tab_strip_model->IsTabClosable(
-        tab_strip_model->GetActiveWebContents()));
-
-    tab_strip_model->CloseAllTabs();
-    EXPECT_EQ(0, tab_strip_model->count());
-  }
-}
-
-IN_PROC_BROWSER_TEST_F(TabStripModelPreventCloseTest,
-                       PreventCloseEnforedByPolicyTabbedAppShallBeClosable) {
-  InstallPWA(GURL(kCalculatorAppUrl), web_app::kCalculatorAppId);
-  SetWebAppSettings(kPreventCloseEnabledForCalculator);
-
-  Browser* const browser =
-      LaunchPWA(web_app::kCalculatorAppId, /*launch_in_window=*/false);
-  ASSERT_TRUE(browser);
-
-  TabStripModel* const tab_strip_model = browser->tab_strip_model();
-  EXPECT_EQ(2, tab_strip_model->count());
-  EXPECT_TRUE(
-      tab_strip_model->IsTabClosable(tab_strip_model->GetActiveWebContents()));
-
-  tab_strip_model->CloseAllTabs();
-  EXPECT_EQ(0, tab_strip_model->count());
-}
diff --git a/chrome/browser/ui/tabs/tab_strip_model_observer.h b/chrome/browser/ui/tabs/tab_strip_model_observer.h
index 4f489ebd..63cabb9 100644
--- a/chrome/browser/ui/tabs/tab_strip_model_observer.h
+++ b/chrome/browser/ui/tabs/tab_strip_model_observer.h
@@ -230,7 +230,7 @@
     return selected_tabs_were_removed || old_model != new_model;
   }
 
-  raw_ptr<content::WebContents, DanglingUntriaged> old_contents = nullptr;
+  raw_ptr<content::WebContents, DanglingAcrossTasks> old_contents = nullptr;
   raw_ptr<content::WebContents, DanglingUntriaged> new_contents = nullptr;
 
   ui::ListSelectionModel old_model;
diff --git a/chrome/browser/ui/tabs/tab_strip_model_unittest.cc b/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
index 76e6f35..7fadd11 100644
--- a/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
@@ -622,9 +622,8 @@
 
   // Test CloseWebContentsAt
   {
-    int previous_tab_count = tabstrip.count();
-    tabstrip.CloseWebContentsAt(2, TabCloseTypes::CLOSE_NONE);
-    EXPECT_EQ(previous_tab_count - 1, tabstrip.count());
+    EXPECT_TRUE(tabstrip.CloseWebContentsAt(2, TabCloseTypes::CLOSE_NONE));
+    EXPECT_EQ(2, tabstrip.count());
 
     EXPECT_EQ(5, observer.GetStateCount());
     State s1(raw_contents3, 2, MockTabStripModelObserver::CLOSE);
@@ -1066,11 +1065,9 @@
   EXPECT_EQ(2, tabstrip.GetIndexOfLastWebContentsOpenedBy(raw_child11, 1));
 
   // Closing a tab should cause its children to inherit the tab's opener.
-  int previous_tab_count = tabstrip.count();
-  tabstrip.CloseWebContentsAt(1,
-                              TabCloseTypes::CLOSE_USER_GESTURE |
-                                  TabCloseTypes::CLOSE_CREATE_HISTORICAL_TAB);
-  EXPECT_EQ(previous_tab_count - 1, tabstrip.count());
+  EXPECT_EQ(true, tabstrip.CloseWebContentsAt(
+                      1, TabCloseTypes::CLOSE_USER_GESTURE |
+                             TabCloseTypes::CLOSE_CREATE_HISTORICAL_TAB));
   EXPECT_EQ("1 111 12 2", GetTabStripStateString(tabstrip));
   EXPECT_EQ(1, GetID(tabstrip.GetActiveWebContents()));
   // opener1 is now the opener of 111, so has two adjacent descendants (111, 12)
@@ -1986,9 +1983,7 @@
   // and make sure the correct tab gets selected when the new tab is closed.
   tabstrip.AppendWebContents(CreateWebContents(), true);
   EXPECT_EQ(2, tabstrip.active_index());
-  int previous_tab_count = tabstrip.count();
   tabstrip.CloseWebContentsAt(2, TabCloseTypes::CLOSE_NONE);
-  EXPECT_EQ(previous_tab_count - 1, tabstrip.count());
   EXPECT_EQ(0, tabstrip.active_index());
 
   // Clean up after ourselves.
diff --git a/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc b/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc
index 60505fe..4d42ca3 100644
--- a/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc
+++ b/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc
@@ -803,8 +803,14 @@
     SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream,
     ::testing::Bool());
 
+// TODO(crbug.com/1455908): FindViewInBubbleById() hits CHECK.
+#if BUILDFLAG(IS_LINUX)
+#define MAYBE_AlertAccessibleEvent DISABLED_AlertAccessibleEvent
+#else
+#define MAYBE_AlertAccessibleEvent AlertAccessibleEvent
+#endif
 IN_PROC_BROWSER_TEST_P(SaveCardBubbleViewsFullFormBrowserTest,
-                       AlertAccessibleEvent) {
+                       MAYBE_AlertAccessibleEvent) {
   views::test::AXEventCounter counter(views::AXEventManager::Get());
   EXPECT_EQ(0, counter.GetCount(ax::mojom::Event::kAlert));
 
@@ -885,9 +891,8 @@
 // dismissed and then immediately torn down (e.g. by closing browser window)
 // before the asynchronous close completes. Regression test for
 // https://crbug.com/842577 .
-//
-// TODO(crbug.com/1360234): Flaky on Mac.
-#if BUILDFLAG(IS_MAC)
+// TODO(crbug.com/1455908): FindViewInBubbleById() hits CHECK.
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
 #define MAYBE_Local_SynchronousCloseAfterAsynchronousClose \
   DISABLED_Local_SynchronousCloseAfterAsynchronousClose
 #else
@@ -1160,9 +1165,17 @@
 
 // Tests the upload save bubble. Ensures that the bubble surfaces a textfield
 // requesting cardholder name if cardholder name is missing.
+// TODO(crbug.com/1455908): FindViewInBubbleById() hits CHECK.
+#if BUILDFLAG(IS_LINUX)
+#define MAYBE_Upload_SubmittingFormWithMissingNamesRequestsCardholderNameIfExpOn \
+  DISABLED_Upload_SubmittingFormWithMissingNamesRequestsCardholderNameIfExpOn
+#else
+#define MAYBE_Upload_SubmittingFormWithMissingNamesRequestsCardholderNameIfExpOn \
+  Upload_SubmittingFormWithMissingNamesRequestsCardholderNameIfExpOn
+#endif
 IN_PROC_BROWSER_TEST_P(
     SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream,
-    Upload_SubmittingFormWithMissingNamesRequestsCardholderNameIfExpOn) {
+    MAYBE_Upload_SubmittingFormWithMissingNamesRequestsCardholderNameIfExpOn) {
   // Start sync.
   ASSERT_TRUE(SetupSync());
 
@@ -1352,9 +1365,17 @@
 // Tests the upload save bubble. Ensures that if cardholder name is explicitly
 // requested and the user accepts the dialog after changing it, the correct
 // metric is logged.
+// TODO(crbug.com/1455908): FindViewInBubbleById() hits CHECK.
+#if BUILDFLAG(IS_LINUX)
+#define MAYBE_Upload_CardholderNameRequested_SubmittingChangedValueLogsEditedMetric \
+  DISABLED_Upload_CardholderNameRequested_SubmittingChangedValueLogsEditedMetric
+#else
+#define MAYBE_Upload_CardholderNameRequested_SubmittingChangedValueLogsEditedMetric \
+  Upload_CardholderNameRequested_SubmittingChangedValueLogsEditedMetric
+#endif
 IN_PROC_BROWSER_TEST_P(
     SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream,
-    Upload_CardholderNameRequested_SubmittingChangedValueLogsEditedMetric) {
+    MAYBE_Upload_CardholderNameRequested_SubmittingChangedValueLogsEditedMetric) {
   // Start sync.
   ASSERT_TRUE(SetupSync());
   // Set the user's full name.
@@ -1796,9 +1817,17 @@
 // Tests the upload save bubble. Ensures that the bubble surfaces a pair of
 // dropdowns requesting expiration date if expiration date month is missing and
 // year is detected but passed.
+// TODO(crbug.com/1455908): FindViewInBubbleById() hits CHECK.
+#if BUILDFLAG(IS_LINUX)
+#define MAYBE_Upload_SubmittingFormWithExpirationDateMonthAndYearExpired \
+  DISABLED_Upload_SubmittingFormWithExpirationDateMonthAndYearExpired
+#else
+#define MAYBE_Upload_SubmittingFormWithExpirationDateMonthAndYearExpired \
+  Upload_SubmittingFormWithExpirationDateMonthAndYearExpired
+#endif
 IN_PROC_BROWSER_TEST_P(
     SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream,
-    Upload_SubmittingFormWithExpirationDateMonthAndYearExpired) {
+    MAYBE_Upload_SubmittingFormWithExpirationDateMonthAndYearExpired) {
   SetUpForEditableExpirationDate();
   // Fill form with a valid month but a passed year.
   FillFormWithSpecificExpirationDate("08", "2000");
@@ -1837,8 +1866,16 @@
 //                         boolean to branch local vs. upload logic.
 // Tests the local save bubble. Ensures that clicking the [No thanks] button
 // successfully causes a strike to be added.
+// TODO(crbug.com/1455908): FindViewInBubbleById() hits CHECK.
+#if BUILDFLAG(IS_LINUX)
+#define MAYBE_StrikeDatabase_Local_AddStrikeIfBubbleDeclined \
+  DISABLED_StrikeDatabase_Local_AddStrikeIfBubbleDeclined
+#else
+#define MAYBE_StrikeDatabase_Local_AddStrikeIfBubbleDeclined \
+  StrikeDatabase_Local_AddStrikeIfBubbleDeclined
+#endif
 IN_PROC_BROWSER_TEST_P(SaveCardBubbleViewsFullFormBrowserTest,
-                       StrikeDatabase_Local_AddStrikeIfBubbleDeclined) {
+                       MAYBE_StrikeDatabase_Local_AddStrikeIfBubbleDeclined) {
   FillForm();
   SubmitFormAndWaitForCardLocalSaveBubble();
 
@@ -1881,8 +1918,16 @@
 // example of declining the prompt three times and ensuring that the
 // offer-to-save bubble does not appear on the fourth try. Then, ensures that no
 // strikes are added if the card already has max strikes.
+// TODO(crbug.com/1455908): FindViewInBubbleById() hits CHECK.
+#if BUILDFLAG(IS_LINUX)
+#define MAYBE_StrikeDatabase_Local_FullFlowTest \
+  DISABLED_StrikeDatabase_Local_FullFlowTest
+#else
+#define MAYBE_StrikeDatabase_Local_FullFlowTest \
+  StrikeDatabase_Local_FullFlowTest
+#endif
 IN_PROC_BROWSER_TEST_P(SaveCardBubbleViewsFullFormBrowserTest,
-                       StrikeDatabase_Local_FullFlowTest) {
+                       MAYBE_StrikeDatabase_Local_FullFlowTest) {
   // Show and ignore the bubble enough times in order to accrue maximum strikes.
   for (int i = 0;
        i < credit_card_save_manager_->GetCreditCardSaveStrikeDatabase()
@@ -1943,9 +1988,17 @@
 // example of declining the prompt three times and ensuring that the
 // offer-to-save bubble does not appear on the fourth try. Then, ensures that no
 // strikes are added if the card already has max strikes.
+// TODO(crbug.com/1455908): FindViewInBubbleById() hits CHECK.
+#if BUILDFLAG(IS_LINUX)
+#define MAYBE_StrikeDatabase_Upload_FullFlowTest \
+  DISABLED_StrikeDatabase_Upload_FullFlowTest
+#else
+#define MAYBE_StrikeDatabase_Upload_FullFlowTest \
+  StrikeDatabase_Upload_FullFlowTest
+#endif
 IN_PROC_BROWSER_TEST_P(
     SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream,
-    StrikeDatabase_Upload_FullFlowTest) {
+    MAYBE_StrikeDatabase_Upload_FullFlowTest) {
   // Start sync.
   ASSERT_TRUE(SetupSync());
 
@@ -2014,9 +2067,15 @@
 }
 
 // Tests to ensure the card nickname is shown correctly in the Upstream bubble.
+// TODO(crbug.com/1455908): FindViewInBubbleById() hits CHECK.
+#if BUILDFLAG(IS_LINUX)
+#define MAYBE_LocalCardHasNickname DISABLED_LocalCardHasNickname
+#else
+#define MAYBE_LocalCardHasNickname LocalCardHasNickname
+#endif
 IN_PROC_BROWSER_TEST_P(
     SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream,
-    LocalCardHasNickname) {
+    MAYBE_LocalCardHasNickname) {
   base::HistogramTester histogram_tester;
   CreditCard card = test::GetCreditCard();
   // Set card number to match the number to be filled in the form.
@@ -2055,8 +2114,15 @@
 
 // Tests the local save bubble. Ensures that clicking the [Save] button
 // successfully causes the bubble to go away.
+// TODO(crbug.com/1455908): FindViewInBubbleById() hits CHECK.
+#if BUILDFLAG(IS_LINUX)
+#define MAYBE_Local_ClickingSaveClosesBubble \
+  DISABLED_Local_ClickingSaveClosesBubble
+#else
+#define MAYBE_Local_ClickingSaveClosesBubble Local_ClickingSaveClosesBubble
+#endif
 IN_PROC_BROWSER_TEST_P(SaveCardBubbleViewsFullFormBrowserTest,
-                       Local_ClickingSaveClosesBubble) {
+                       MAYBE_Local_ClickingSaveClosesBubble) {
   FillForm();
   SubmitFormAndWaitForCardLocalSaveBubble();
 
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.h b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.h
index f3ec625..dedb545 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.h
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.h
@@ -370,7 +370,8 @@
   PrefChangeRegistrar profile_pref_registrar_;
 
   // Used for opening urls.
-  raw_ptr<content::PageNavigator, DanglingUntriaged> page_navigator_ = nullptr;
+  raw_ptr<content::PageNavigator, DanglingAcrossTasks> page_navigator_ =
+      nullptr;
 
   // BookmarkModel that owns the entries and folders that are shown in this
   // view. This is owned by the Profile.
diff --git a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.h b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.h
index 02bac22..582b5cd 100644
--- a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.h
+++ b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.h
@@ -167,7 +167,7 @@
   // Provides a callback that returns the page navigator
   base::RepeatingCallback<content::PageNavigator*()> GetPageNavigatorGetter();
 
-  raw_ptr<views::MenuButton, DanglingUntriaged> overflow_button_;
+  raw_ptr<views::MenuButton, DanglingAcrossTasks> overflow_button_;
 
   // Used to show the overflow menu when clicked.
   raw_ptr<views::BubbleDialogDelegate> bubble_delegate_ = nullptr;
@@ -176,7 +176,8 @@
   raw_ptr<SavedTabGroupModel> saved_tab_group_model_;
 
   // The page navigator used to create tab groups
-  raw_ptr<content::PageNavigator, DanglingUntriaged> page_navigator_ = nullptr;
+  raw_ptr<content::PageNavigator, DanglingAcrossTasks> page_navigator_ =
+      nullptr;
   raw_ptr<Browser> browser_;
 
   // During a drag and drop session, `drag_data_` owns the state for the drag.
diff --git a/chrome/browser/ui/views/content_setting_bubble_contents.cc b/chrome/browser/ui/views/content_setting_bubble_contents.cc
index 8a93399..80c4db4 100644
--- a/chrome/browser/ui/views/content_setting_bubble_contents.cc
+++ b/chrome/browser/ui/views/content_setting_bubble_contents.cc
@@ -5,21 +5,20 @@
 #include "chrome/browser/ui/views/content_setting_bubble_contents.h"
 
 #include <algorithm>
+#include <memory>
 #include <utility>
 #include <vector>
 
 #include "base/memory/raw_ptr.h"
 #include "base/ranges/algorithm.h"
 #include "base/strings/utf_string_conversions.h"
-#include "build/build_config.h"
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
 #include "chrome/browser/ui/content_settings/content_setting_bubble_model.h"
 #include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
-#include "chrome/browser/ui/views/chrome_typography.h"
 #include "chrome/browser/ui/views/content_setting_site_row_view.h"
+#include "chrome/browser/ui/views/controls/rich_hover_button.h"
 #include "chrome/grit/generated_resources.h"
-#include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/vector_icons/vector_icons.h"
 #include "content/public/browser/navigation_handle.h"
@@ -29,20 +28,14 @@
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/base/models/combobox_model.h"
 #include "ui/base/models/image_model.h"
-#include "ui/base/resource/resource_bundle.h"
 #include "ui/base/ui_base_features.h"
 #include "ui/color/color_id.h"
 #include "ui/color/color_provider.h"
-#include "ui/gfx/color_utils.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/paint_vector_icon.h"
-#include "ui/gfx/vector_icon_types.h"
-#include "ui/views/border.h"
 #include "ui/views/controls/button/image_button.h"
 #include "ui/views/controls/button/image_button_factory.h"
-#include "ui/views/controls/button/label_button_border.h"
-#include "ui/views/controls/button/md_text_button.h"
 #include "ui/views/controls/button/radio_button.h"
 #include "ui/views/controls/combobox/combobox.h"
 #include "ui/views/controls/image_view.h"
@@ -71,6 +64,20 @@
                                     : std::u16string();
 }
 
+ui::ImageModel GetSiteSettingsIcon() {
+  return ui::ImageModel::FromVectorIcon(
+      features::IsChromeRefresh2023() ? vector_icons::kSettingsChromeRefreshIcon
+                                      : vector_icons::kSettingsIcon,
+      ui::kColorIcon);
+}
+
+ui::ImageModel GetLaunchIcon() {
+  return ui::ImageModel::FromVectorIcon(
+      features::IsChromeRefresh2023() ? vector_icons::kLaunchChromeRefreshIcon
+                                      : vector_icons::kLaunchIcon,
+      ui::kColorIconSecondary);
+}
+
 bool ShouldShowMediaDeviceMenus(ContentSettingBubbleModel* model) {
   return model->AsMediaStreamBubbleModel() &&
          model->bubble_content().is_user_modifiable;
@@ -490,6 +497,12 @@
   const ContentSettingBubbleModel::BubbleContent& bubble_content =
       content_setting_bubble_model_->bubble_content();
 
+  if (!bubble_content.subtitle.empty()) {
+    SetSubtitle(bubble_content.subtitle);
+    auto separator = std::make_unique<views::Separator>();
+    rows.push_back({std::move(separator), LayoutRowType::FULL_WIDTH});
+  }
+
   if (!bubble_content.message.empty()) {
     auto message_label = std::make_unique<views::Label>(
         bubble_content.message, views::style::CONTEXT_LABEL,
@@ -578,6 +591,25 @@
     rows.push_back({std::move(manage_checkbox), LayoutRowType::DEFAULT});
   }
 
+  if (bubble_content.manage_text_style ==
+      ContentSettingBubbleModel::ManageTextStyle::kHoverButton) {
+    SetButtons(ui::DIALOG_BUTTON_NONE);
+    auto separator = std::make_unique<views::Separator>();
+    rows.push_back({std::move(separator), LayoutRowType::DEFAULT});
+
+    auto site_settings_link = std::make_unique<RichHoverButton>(
+        base::BindRepeating(
+            [](ContentSettingBubbleContents* bubble) {
+              bubble->GetWidget()->Close();
+              bubble->content_setting_bubble_model_->OnManageButtonClicked();
+            },
+            this),
+        GetSiteSettingsIcon(), bubble_content.manage_text,
+        /*secondary_text=*/std::u16string(), bubble_content.manage_tooltip,
+        /*subtitle_text=*/std::u16string(), GetLaunchIcon());
+    rows.push_back({std::move(site_settings_link), LayoutRowType::FULL_WIDTH});
+  }
+
   // We have to apply the left and right margins manually, because rows using
   // LayoutRowType::FULL_WIDTH need to not have them applied to look correct.
   const int left_margin = margins().left();
diff --git a/chrome/browser/ui/views/desktop_capture/share_this_tab_source_view.cc b/chrome/browser/ui/views/desktop_capture/share_this_tab_source_view.cc
index f521655..d4b27daa 100644
--- a/chrome/browser/ui/views/desktop_capture/share_this_tab_source_view.cc
+++ b/chrome/browser/ui/views/desktop_capture/share_this_tab_source_view.cc
@@ -12,9 +12,13 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "media/base/video_util.h"
+#include "ui/base/metadata/metadata_impl_macros.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/skia_conversions.h"
 #include "ui/gfx/image/image_skia_operations.h"
 #include "ui/gfx/text_constants.h"
 #include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/layout_provider.h"
 
 namespace {
 
@@ -63,6 +67,36 @@
       FROM_HERE, base::BindOnce(std::move(reply), hash, image));
 }
 
+// TODO(crbug.com/1458354): Add support for rounded image corners to ImageView
+class RoundedCornerImageView : public views::ImageView {
+ public:
+  METADATA_HEADER(RoundedCornerImageView);
+  RoundedCornerImageView() = default;
+  RoundedCornerImageView(const RoundedCornerImageView&) = delete;
+  RoundedCornerImageView& operator=(const RoundedCornerImageView&) = delete;
+
+  // views::ImageView:
+  bool GetCanProcessEventsWithinSubtree() const override { return false; }
+
+ protected:
+  // views::ImageView:
+  void OnPaint(gfx::Canvas* canvas) override;
+};
+
+void RoundedCornerImageView::OnPaint(gfx::Canvas* canvas) {
+  SkPath mask;
+  CHECK(GetLayoutProvider());
+  const int corner_radius =
+      GetLayoutProvider()->GetCornerRadiusMetric(views::Emphasis::kMedium);
+  mask.addRoundRect(gfx::RectToSkRect(GetImageBounds()), corner_radius,
+                    corner_radius);
+  canvas->ClipPath(mask, true);
+  ImageView::OnPaint(canvas);
+}
+
+BEGIN_METADATA(RoundedCornerImageView, views::ImageView)
+END_METADATA
+
 }  // namespace
 
 ShareThisTabSourceView::ShareThisTabSourceView(
@@ -82,7 +116,7 @@
   throbber_->SetBoundsRect(kThrobberRect);
   throbber_->Start();
 
-  image_view_ = AddChildView(std::make_unique<views::ImageView>());
+  image_view_ = AddChildView(std::make_unique<RoundedCornerImageView>());
   image_view_->SetVisible(false);
   image_view_->SetBoundsRect(kPreviewRect);
 
diff --git a/chrome/browser/ui/views/extensions/extension_install_dialog_view_browsertest.cc b/chrome/browser/ui/views/extensions/extension_install_dialog_view_browsertest.cc
index e3fd5be..3710d18 100644
--- a/chrome/browser/ui/views/extensions/extension_install_dialog_view_browsertest.cc
+++ b/chrome/browser/ui/views/extensions/extension_install_dialog_view_browsertest.cc
@@ -308,9 +308,8 @@
     int tab1_idx = tab_strip_model->GetIndexOfWebContents(originator_contents);
     content::WebContentsDestroyedWatcher tab_destroyed_watcher(
         tab_strip_model->GetWebContentsAt(tab1_idx));
-    int previous_tab_count = tab_strip_model->count();
-    tab_strip_model->CloseWebContentsAt(tab1_idx, TabCloseTypes::CLOSE_NONE);
-    EXPECT_EQ(previous_tab_count - 1, tab_strip_model->count());
+    EXPECT_TRUE(tab_strip_model->CloseWebContentsAt(tab1_idx,
+                                                    TabCloseTypes::CLOSE_NONE));
     tab_destroyed_watcher.Wait();
   }
 
diff --git a/chrome/browser/ui/views/extensions/extension_install_friction_dialog_view_browsertest.cc b/chrome/browser/ui/views/extensions/extension_install_friction_dialog_view_browsertest.cc
index d56c1a6..cfb5fe0d 100644
--- a/chrome/browser/ui/views/extensions/extension_install_friction_dialog_view_browsertest.cc
+++ b/chrome/browser/ui/views/extensions/extension_install_friction_dialog_view_browsertest.cc
@@ -107,9 +107,8 @@
     int tab1_idx = tab_strip_model->GetIndexOfWebContents(originator_contents);
     content::WebContentsDestroyedWatcher tab_destroyed_watcher(
         tab_strip_model->GetWebContentsAt(tab1_idx));
-    int previous_tab_count = tab_strip_model->count();
-    tab_strip_model->CloseWebContentsAt(tab1_idx, TabCloseTypes::CLOSE_NONE);
-    EXPECT_EQ(previous_tab_count - 1, tab_strip_model->count());
+    EXPECT_TRUE(tab_strip_model->CloseWebContentsAt(tab1_idx,
+                                                    TabCloseTypes::CLOSE_NONE));
     tab_destroyed_watcher.Wait();
   }
 
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_container.h b/chrome/browser/ui/views/extensions/extensions_toolbar_container.h
index 0f45497..97bdc1b8 100644
--- a/chrome/browser/ui/views/extensions/extensions_toolbar_container.h
+++ b/chrome/browser/ui/views/extensions/extensions_toolbar_container.h
@@ -318,7 +318,8 @@
   // `extensions_features::kExtensionsMenuAccessControl` experiment is released.
   // Exactly one of `extensions_button_ and `extensions_controls_` is created;
   // the other is null.
-  const raw_ptr<ExtensionsToolbarButton, DanglingUntriaged> extensions_button_;
+  const raw_ptr<ExtensionsToolbarButton, DanglingAcrossTasks>
+      extensions_button_;
   const raw_ptr<ExtensionsToolbarControls, DanglingUntriaged>
       extensions_controls_;
   DisplayMode display_mode_;
diff --git a/chrome/browser/ui/views/frame/browser_root_view.h b/chrome/browser/ui/views/frame/browser_root_view.h
index b81de341..c9df835 100644
--- a/chrome/browser/ui/views/frame/browser_root_view.h
+++ b/chrome/browser/ui/views/frame/browser_root_view.h
@@ -138,7 +138,7 @@
       std::unique_ptr<ui::LayerTreeOwner> drag_image_layer_owner);
 
   // The BrowserView.
-  raw_ptr<BrowserView, DanglingUntriaged> browser_view_ = nullptr;
+  raw_ptr<BrowserView, DanglingAcrossTasks> browser_view_ = nullptr;
 
   // Used to calculate partial offsets in scrolls that occur for a smooth
   // scroll device.
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index 31ecd1e..ccdf5ffe 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -993,7 +993,7 @@
   // The view that manages the tab strip, toolbar, and sometimes the bookmark
   // bar. Stacked top in the view hiearachy so it can be used to slide out
   // the top views in immersive fullscreen.
-  raw_ptr<TopContainerView, DanglingUntriaged> top_container_ = nullptr;
+  raw_ptr<TopContainerView, DanglingAcrossTasks> top_container_ = nullptr;
 
   // Menu button and page status icons. Only used by web-app windows.
   raw_ptr<WebAppFrameToolbarView, DanglingUntriaged> web_app_frame_toolbar_ =
@@ -1006,11 +1006,11 @@
   raw_ptr<views::Label, DanglingUntriaged> web_app_window_title_ = nullptr;
 
   // The view that contains the tabstrip, new tab button, and grab handle space.
-  raw_ptr<TabStripRegionView, DanglingUntriaged> tab_strip_region_view_ =
+  raw_ptr<TabStripRegionView, DanglingAcrossTasks> tab_strip_region_view_ =
       nullptr;
 
   // The TabStrip.
-  raw_ptr<TabStrip, DanglingUntriaged> tabstrip_ = nullptr;
+  raw_ptr<TabStrip, DanglingAcrossTasks> tabstrip_ = nullptr;
 
   // the webui based tabstrip, when applicable. see https://crbug.com/989131.
   raw_ptr<WebUITabStripContainerView, DanglingUntriaged> webui_tab_strip_ =
@@ -1024,7 +1024,7 @@
   std::unique_ptr<AccessibilityModeObserver> accessibility_mode_observer_;
 
   // The Toolbar containing the navigation buttons, menus and the address bar.
-  raw_ptr<ToolbarView, DanglingUntriaged> toolbar_ = nullptr;
+  raw_ptr<ToolbarView, DanglingAcrossTasks> toolbar_ = nullptr;
 
   // The OverlayView for the widget, which is used to host `top_container_`
   // during immersive reveal.
@@ -1059,7 +1059,7 @@
   std::unique_ptr<BookmarkBarView> bookmark_bar_view_;
 
   // Separator between top container and contents.
-  raw_ptr<views::View, DanglingUntriaged> contents_separator_ = nullptr;
+  raw_ptr<views::View, DanglingAcrossTasks> contents_separator_ = nullptr;
 
   // Loading bar (part of top container for / WebUI tab strip).
   raw_ptr<TopContainerLoadingBar, DanglingUntriaged> loading_bar_ = nullptr;
@@ -1067,37 +1067,38 @@
   // The do-nothing view which controls the z-order of the find bar widget
   // relative to views which paint into layers and views with an associated
   // NativeView.
-  raw_ptr<View, DanglingUntriaged> find_bar_host_view_ = nullptr;
+  raw_ptr<View, DanglingAcrossTasks> find_bar_host_view_ = nullptr;
 
   // The download shelf.
   raw_ptr<DownloadShelf, DanglingUntriaged> download_shelf_ = nullptr;
 
   // The InfoBarContainerView that contains InfoBars for the current tab.
-  raw_ptr<InfoBarContainerView, DanglingUntriaged> infobar_container_ = nullptr;
+  raw_ptr<InfoBarContainerView, DanglingAcrossTasks> infobar_container_ =
+      nullptr;
 
   // The view that contains the selected WebContents.
-  raw_ptr<ContentsWebView, DanglingUntriaged> contents_web_view_ = nullptr;
+  raw_ptr<ContentsWebView, DanglingAcrossTasks> contents_web_view_ = nullptr;
 
   // The view that contains devtools window for the selected WebContents.
-  raw_ptr<views::WebView, DanglingUntriaged> devtools_web_view_ = nullptr;
+  raw_ptr<views::WebView, DanglingAcrossTasks> devtools_web_view_ = nullptr;
 
   // The view managing the devtools and contents positions.
   // Handled by ContentsLayoutManager.
-  raw_ptr<views::View, DanglingUntriaged> contents_container_ = nullptr;
+  raw_ptr<views::View, DanglingAcrossTasks> contents_container_ = nullptr;
 
   // The side panel aligned to the left or the right side of the browser window
   // depending on the kSidePanelHorizontalAlignment pref's value.
-  raw_ptr<SidePanel, DanglingUntriaged> unified_side_panel_ = nullptr;
-  raw_ptr<views::View, DanglingUntriaged> right_aligned_side_panel_separator_ =
-      nullptr;
+  raw_ptr<SidePanel, DanglingAcrossTasks> unified_side_panel_ = nullptr;
+  raw_ptr<views::View, DanglingAcrossTasks>
+      right_aligned_side_panel_separator_ = nullptr;
 
   // The side search side panel.
-  raw_ptr<views::View, DanglingUntriaged> left_aligned_side_panel_separator_ =
+  raw_ptr<views::View, DanglingAcrossTasks> left_aligned_side_panel_separator_ =
       nullptr;
 
   // Provides access to the toolbar buttons this browser view uses. Buttons may
   // appear in a hosted app frame or in a tabbed UI toolbar.
-  raw_ptr<ToolbarButtonProvider, DanglingUntriaged> toolbar_button_provider_ =
+  raw_ptr<ToolbarButtonProvider, DanglingAcrossTasks> toolbar_button_provider_ =
       nullptr;
 
   // The handler responsible for showing autofill bubbles.
diff --git a/chrome/browser/ui/views/frame/browser_view_layout.h b/chrome/browser/ui/views/frame/browser_view_layout.h
index fc57462c..5d3dec20 100644
--- a/chrome/browser/ui/views/frame/browser_view_layout.h
+++ b/chrome/browser/ui/views/frame/browser_view_layout.h
@@ -175,27 +175,27 @@
   // Child views that the layout manager manages.
   // NOTE: If you add a view, try to add it as a views::View, which makes
   // testing much easier.
-  const raw_ptr<views::View, DanglingUntriaged> top_container_;
+  const raw_ptr<views::View, DanglingAcrossTasks> top_container_;
   const raw_ptr<WebAppFrameToolbarView, DanglingUntriaged>
       web_app_frame_toolbar_;
   const raw_ptr<views::Label, DanglingUntriaged> web_app_window_title_;
-  const raw_ptr<TabStripRegionView, DanglingUntriaged> tab_strip_region_view_;
-  const raw_ptr<views::View, DanglingUntriaged> toolbar_;
-  const raw_ptr<InfoBarContainerView, DanglingUntriaged> infobar_container_;
-  const raw_ptr<views::View, DanglingUntriaged> contents_container_;
-  const raw_ptr<views::View, DanglingUntriaged>
+  const raw_ptr<TabStripRegionView, DanglingAcrossTasks> tab_strip_region_view_;
+  const raw_ptr<views::View, DanglingAcrossTasks> toolbar_;
+  const raw_ptr<InfoBarContainerView, DanglingAcrossTasks> infobar_container_;
+  const raw_ptr<views::View, DanglingAcrossTasks> contents_container_;
+  const raw_ptr<views::View, DanglingAcrossTasks>
       left_aligned_side_panel_separator_;
-  const raw_ptr<views::View, DanglingUntriaged> unified_side_panel_;
-  const raw_ptr<views::View, DanglingUntriaged>
+  const raw_ptr<views::View, DanglingAcrossTasks> unified_side_panel_;
+  const raw_ptr<views::View, DanglingAcrossTasks>
       right_aligned_side_panel_separator_;
-  const raw_ptr<ImmersiveModeController, DanglingUntriaged>
+  const raw_ptr<ImmersiveModeController, DanglingAcrossTasks>
       immersive_mode_controller_;
-  const raw_ptr<views::View, DanglingUntriaged> contents_separator_;
+  const raw_ptr<views::View, DanglingAcrossTasks> contents_separator_;
 
   raw_ptr<views::View, DanglingUntriaged> webui_tab_strip_ = nullptr;
   raw_ptr<views::View, DanglingUntriaged> loading_bar_ = nullptr;
-  raw_ptr<TabStrip, DanglingUntriaged> tab_strip_ = nullptr;
-  raw_ptr<BookmarkBarView, DanglingUntriaged> bookmark_bar_ = nullptr;
+  raw_ptr<TabStrip, DanglingAcrossTasks> tab_strip_ = nullptr;
+  raw_ptr<BookmarkBarView, DanglingAcrossTasks> bookmark_bar_ = nullptr;
   raw_ptr<views::View, DanglingUntriaged> download_shelf_ = nullptr;
 
   // The widget displaying a border on top of contents container for
diff --git a/chrome/browser/ui/views/frame/desktop_browser_frame_aura.h b/chrome/browser/ui/views/frame/desktop_browser_frame_aura.h
index 0951fef..0e93907 100644
--- a/chrome/browser/ui/views/frame/desktop_browser_frame_aura.h
+++ b/chrome/browser/ui/views/frame/desktop_browser_frame_aura.h
@@ -66,7 +66,7 @@
   raw_ptr<BrowserFrame> browser_frame_;
 
   // Owned by the RootWindow.
-  raw_ptr<BrowserDesktopWindowTreeHost, DanglingUntriaged>
+  raw_ptr<BrowserDesktopWindowTreeHost, DanglingAcrossTasks>
       browser_desktop_window_tree_host_;
 
   std::unique_ptr<wm::VisibilityController> visibility_controller_;
diff --git a/chrome/browser/ui/views/frame/tab_strip_region_view.h b/chrome/browser/ui/views/frame/tab_strip_region_view.h
index 0c6a448..8bbedfac 100644
--- a/chrome/browser/ui/views/frame/tab_strip_region_view.h
+++ b/chrome/browser/ui/views/frame/tab_strip_region_view.h
@@ -85,9 +85,9 @@
   void UpdateNewTabButtonBorder();
 
   raw_ptr<views::FlexLayout, DanglingUntriaged> layout_manager_ = nullptr;
-  raw_ptr<views::View, DanglingUntriaged> tab_strip_container_ = nullptr;
+  raw_ptr<views::View, DanglingAcrossTasks> tab_strip_container_ = nullptr;
   raw_ptr<views::View, DanglingUntriaged> reserved_grab_handle_space_ = nullptr;
-  raw_ptr<TabStrip, DanglingUntriaged> tab_strip_ = nullptr;
+  raw_ptr<TabStrip, DanglingAcrossTasks> tab_strip_ = nullptr;
   raw_ptr<TabStripScrollContainer, DanglingUntriaged>
       tab_strip_scroll_container_ = nullptr;
   raw_ptr<NewTabButton, DanglingUntriaged> new_tab_button_ = nullptr;
diff --git a/chrome/browser/ui/views/frame/web_contents_close_handler.h b/chrome/browser/ui/views/frame/web_contents_close_handler.h
index 1077eb2..1e160262e 100644
--- a/chrome/browser/ui/views/frame/web_contents_close_handler.h
+++ b/chrome/browser/ui/views/frame/web_contents_close_handler.h
@@ -43,7 +43,7 @@
   // close was canceled.
   void OnStillHaventClosed();
 
-  raw_ptr<WebContentsCloseHandlerDelegate, DanglingUntriaged> delegate_;
+  raw_ptr<WebContentsCloseHandlerDelegate, DanglingAcrossTasks> delegate_;
 
   // If true, WillCloseAllTabs() has been invoked.
   bool in_close_;
diff --git a/chrome/browser/ui/views/passwords/password_bubble_interactive_uitest.cc b/chrome/browser/ui/views/passwords/password_bubble_interactive_uitest.cc
index 69968f3a..70d77e4 100644
--- a/chrome/browser/ui/views/passwords/password_bubble_interactive_uitest.cc
+++ b/chrome/browser/ui/views/passwords/password_bubble_interactive_uitest.cc
@@ -393,9 +393,7 @@
   EXPECT_TRUE(IsBubbleShowing());
 
   // Close the tab.
-  int previous_tab_count = tab_model->count();
-  tab_model->CloseWebContentsAt(0, 0);
-  ASSERT_EQ(previous_tab_count - 1, tab_model->count());
+  ASSERT_TRUE(tab_model->CloseWebContentsAt(0, 0));
   EXPECT_FALSE(IsBubbleShowing());
 
   // The bubble is now hidden, but not destroyed. However, the WebContents _is_
diff --git a/chrome/browser/ui/views/performance_controls/battery_saver_button_browsertest.cc b/chrome/browser/ui/views/performance_controls/battery_saver_button_browsertest.cc
index f992c6c..e3b75593 100644
--- a/chrome/browser/ui/views/performance_controls/battery_saver_button_browsertest.cc
+++ b/chrome/browser/ui/views/performance_controls/battery_saver_button_browsertest.cc
@@ -96,9 +96,9 @@
   }
 
  private:
-  raw_ptr<base::test::TestSamplingEventSource, DanglingUntriaged>
+  raw_ptr<base::test::TestSamplingEventSource, DanglingAcrossTasks>
       sampling_source_;
-  raw_ptr<base::test::TestBatteryLevelProvider, DanglingUntriaged>
+  raw_ptr<base::test::TestBatteryLevelProvider, DanglingAcrossTasks>
       battery_level_provider_;
   // Only used on platforms without a battery level provider implementation.
   std::unique_ptr<base::BatteryStateSampler> battery_state_sampler_;
diff --git a/chrome/browser/ui/views/sharing/sharing_icon_view.h b/chrome/browser/ui/views/sharing/sharing_icon_view.h
index f3d2b1b..dc971b6 100644
--- a/chrome/browser/ui/views/sharing/sharing_icon_view.h
+++ b/chrome/browser/ui/views/sharing/sharing_icon_view.h
@@ -58,7 +58,7 @@
   void UpdateOpacity();
 
  private:
-  raw_ptr<SharingUiController, DanglingUntriaged> last_controller_ = nullptr;
+  raw_ptr<SharingUiController, DanglingAcrossTasks> last_controller_ = nullptr;
   bool loading_animation_ = false;
   bool should_show_error_ = false;
   GetControllerCallback get_controller_callback_;
diff --git a/chrome/browser/ui/views/status_bubble_views.h b/chrome/browser/ui/views/status_bubble_views.h
index f17d92c..ecbb078 100644
--- a/chrome/browser/ui/views/status_bubble_views.h
+++ b/chrome/browser/ui/views/status_bubble_views.h
@@ -153,7 +153,7 @@
   // going outside the bounds of the hosting widget.
   std::unique_ptr<views::Widget> popup_;
 
-  raw_ptr<views::View, DanglingUntriaged> base_view_;
+  raw_ptr<views::View, DanglingAcrossTasks> base_view_;
   raw_ptr<StatusView, DanglingUntriaged> view_ = nullptr;
 
   // Manages the expansion of a status bubble to fit a long URL.
diff --git a/chrome/browser/ui/views/tabs/new_tab_button.h b/chrome/browser/ui/views/tabs/new_tab_button.h
index 6f882fa3..6f307b2 100644
--- a/chrome/browser/ui/views/tabs/new_tab_button.h
+++ b/chrome/browser/ui/views/tabs/new_tab_button.h
@@ -91,7 +91,7 @@
   void PaintFill(gfx::Canvas* canvas) const;
 
   // Tab strip that contains this button.
-  raw_ptr<TabStrip, DanglingUntriaged> tab_strip_;
+  raw_ptr<TabStrip, DanglingAcrossTasks> tab_strip_;
 
   // Contains our ink drop layer so it can paint above our background.
   raw_ptr<views::InkDropContainerView, DanglingUntriaged> ink_drop_container_;
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index f79595d..5597e4c2a 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -137,7 +137,7 @@
   }
 
  private:
-  const raw_ptr<TabStyleViews, DanglingUntriaged> tab_style_views_;
+  const raw_ptr<TabStyleViews, DanglingAcrossTasks> tab_style_views_;
 };
 
 }  // namespace
diff --git a/chrome/browser/ui/views/tabs/tab_container_impl.h b/chrome/browser/ui/views/tabs/tab_container_impl.h
index c9d42fd2..3a7c264d 100644
--- a/chrome/browser/ui/views/tabs/tab_container_impl.h
+++ b/chrome/browser/ui/views/tabs/tab_container_impl.h
@@ -336,7 +336,7 @@
 
   const raw_ref<TabContainerController, DanglingUntriaged> controller_;
 
-  const raw_ptr<TabHoverCardController, DanglingUntriaged>
+  const raw_ptr<TabHoverCardController, DanglingAcrossTasks>
       hover_card_controller_;
 
   // May be nullptr in tests.
@@ -351,7 +351,7 @@
   // This view is animated by `bounds_animator_` to guarantee that this
   // container's bounds change smoothly when tabs are animated into or out of
   // this container.
-  const raw_ref<views::View, DanglingUntriaged> overall_bounds_view_;
+  const raw_ref<views::View, DanglingAcrossTasks> overall_bounds_view_;
 
   // Responsible for animating tabs in response to model changes.
   views::BoundsAnimator bounds_animator_;
diff --git a/chrome/browser/ui/views/tabs/tab_slot_animation_delegate.h b/chrome/browser/ui/views/tabs/tab_slot_animation_delegate.h
index 32a1743..52fb4201 100644
--- a/chrome/browser/ui/views/tabs/tab_slot_animation_delegate.h
+++ b/chrome/browser/ui/views/tabs/tab_slot_animation_delegate.h
@@ -28,7 +28,7 @@
 
  private:
   const raw_ptr<TabContainer, DanglingUntriaged> tab_container_;
-  const raw_ptr<TabSlotView, DanglingUntriaged> slot_view_;
+  const raw_ptr<TabSlotView, DanglingAcrossTasks> slot_view_;
 };
 
 #endif  // CHROME_BROWSER_UI_VIEWS_TABS_TAB_SLOT_ANIMATION_DELEGATE_H_
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h
index 9fb8e73..0c3e8f9 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.h
+++ b/chrome/browser/ui/views/tabs/tab_strip.h
@@ -421,10 +421,10 @@
 
   std::unique_ptr<TabHoverCardController> hover_card_controller_;
 
-  raw_ref<TabDragContextImpl, DanglingUntriaged> drag_context_;
+  raw_ref<TabDragContextImpl, DanglingAcrossTasks> drag_context_;
 
   // The View parent for the tabs and the various group views.
-  raw_ref<TabContainer, DanglingUntriaged> tab_container_;
+  raw_ref<TabContainer, DanglingAcrossTasks> tab_container_;
 
   // The background offset used by inactive tabs to match the frame image.
   int background_offset_ = 0;
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_button.h b/chrome/browser/ui/views/toolbar/chrome_labs_button.h
index 3f7fb47..b63dac06 100644
--- a/chrome/browser/ui/views/toolbar/chrome_labs_button.h
+++ b/chrome/browser/ui/views/toolbar/chrome_labs_button.h
@@ -44,7 +44,7 @@
 
   raw_ptr<BrowserView, DanglingUntriaged> browser_view_;
 
-  raw_ptr<const ChromeLabsModel, DanglingUntriaged> model_;
+  raw_ptr<const ChromeLabsModel, DanglingAcrossTasks> model_;
 
   raw_ptr<views::DotIndicator> new_experiments_indicator_;
 
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_coordinator.h b/chrome/browser/ui/views/toolbar/chrome_labs_coordinator.h
index c5f1fa1..acbb6cd2 100644
--- a/chrome/browser/ui/views/toolbar/chrome_labs_coordinator.h
+++ b/chrome/browser/ui/views/toolbar/chrome_labs_coordinator.h
@@ -64,7 +64,7 @@
 
   raw_ptr<ChromeLabsButton, DanglingUntriaged> anchor_view_;
   raw_ptr<Browser, DanglingUntriaged> browser_;
-  raw_ptr<const ChromeLabsModel, DanglingUntriaged> chrome_labs_model_;
+  raw_ptr<const ChromeLabsModel, DanglingAcrossTasks> chrome_labs_model_;
   raw_ptr<ChromeLabsBubbleView, DanglingUntriaged> chrome_labs_bubble_view_ =
       nullptr;
 
diff --git a/chrome/browser/ui/views/toolbar/toolbar_icon_container_view.h b/chrome/browser/ui/views/toolbar/toolbar_icon_container_view.h
index 449704d..0ab6a0f 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_icon_container_view.h
+++ b/chrome/browser/ui/views/toolbar/toolbar_icon_container_view.h
@@ -112,7 +112,7 @@
 
   // The main view is nominally always present and is last child in the view
   // hierarchy.
-  raw_ptr<views::View, DanglingUntriaged> main_item_ = nullptr;
+  raw_ptr<views::View, DanglingAcrossTasks> main_item_ = nullptr;
 
   // Override for the icon color. If not set, |kColorToolbarButtonIcon| is used.
   absl::optional<SkColor> icon_color_;
diff --git a/chrome/browser/ui/web_applications/web_app_ui_manager_impl.h b/chrome/browser/ui/web_applications/web_app_ui_manager_impl.h
index e3bffef..907bbf7 100644
--- a/chrome/browser/ui/web_applications/web_app_ui_manager_impl.h
+++ b/chrome/browser/ui/web_applications/web_app_ui_manager_impl.h
@@ -108,7 +108,7 @@
   const raw_ptr<Profile> profile_;
 
   raw_ptr<WebAppSyncBridge> sync_bridge_ = nullptr;
-  raw_ptr<OsIntegrationManager, DanglingUntriaged> os_integration_manager_ =
+  raw_ptr<OsIntegrationManager, DanglingAcrossTasks> os_integration_manager_ =
       nullptr;
 
   std::map<AppId, std::vector<base::OnceClosure>> windows_closed_requests_map_;
diff --git a/chrome/browser/ui/webui/ash/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/ash/login/gaia_screen_handler.cc
index f3cb2a35..b65076f6 100644
--- a/chrome/browser/ui/webui/ash/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/ash/login/gaia_screen_handler.cc
@@ -63,7 +63,6 @@
 #include "chrome/browser/certificate_provider/certificate_provider_service_factory.h"
 #include "chrome/browser/certificate_provider/pin_dialog_manager.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/enterprise/util/managed_browser_utils.h"
 #include "chrome/browser/lifetime/browser_shutdown.h"
 #include "chrome/browser/net/nss_temp_certs_cache_chromeos.h"
 #include "chrome/browser/net/system_network_context_manager.h"
@@ -648,7 +647,6 @@
   AddCallback("samlChallengeMachineKey",
               &GaiaScreenHandler::HandleSamlChallengeMachineKey);
   AddCallback("loginWebuiReady", &GaiaScreenHandler::HandleGaiaUIReady);
-  AddCallback("identifierEntered", &GaiaScreenHandler::HandleIdentifierEntered);
   AddCallback("authExtensionLoaded",
               &GaiaScreenHandler::HandleAuthExtensionLoaded);
   AddCallback("setIsFirstSigninStep",
@@ -663,14 +661,6 @@
               &GaiaScreenHandler::HandleShowLoadingTimeoutError);
 }
 
-void GaiaScreenHandler::HandleIdentifierEntered(const std::string& user_email) {
-  if (MaybeTriggerEnrollmentNudge(user_email)) {
-    return;
-  }
-
-  CheckIfAllowlisted(user_email);
-}
-
 void GaiaScreenHandler::HandleAuthExtensionLoaded() {
   VLOG(1) << "Auth extension finished loading";
   // Recreate the client cert usage observer, in order to track only the certs
@@ -1341,6 +1331,10 @@
   gaia_reauth_request_token_ = reauth_request_token;
 }
 
+void GaiaScreenHandler::ShowEnrollmentNudge(const std::string& email_domain) {
+  CallExternalAPI("showEnrollmentNudge", email_domain);
+}
+
 void GaiaScreenHandler::LoadAuthExtension(bool force) {
   VLOG(1) << "LoadAuthExtension, force: " << force;
   if (!initialized_) {
@@ -1592,42 +1586,6 @@
       std::move(scraped_saml_passwords), std::move(user_context));
 }
 
-bool GaiaScreenHandler::MaybeTriggerEnrollmentNudge(
-    const std::string& user_email) {
-  const bool is_enterprise_managed = g_browser_process->platform_part()
-                                         ->browser_policy_connector_ash()
-                                         ->IsDeviceEnterpriseManaged();
-  if (is_enterprise_managed) {
-    // Device either already went through enterprise enrollment flow or goes
-    // through it right now. No need for nudging.
-    return false;
-  }
-  const bool is_first_user =
-      user_manager::UserManager::Get()->GetUsers().empty();
-  if (!is_first_user) {
-    // Enrollment nudge targets only initial OOBE flow on unowned devices.
-    // Current user is not a first user which means that device is already
-    // owned.
-    return false;
-  }
-  const std::string email_domain =
-      chrome::enterprise_util::GetDomainFromEmail(user_email);
-  if (chrome::enterprise_util::IsKnownConsumerDomain(email_domain)) {
-    // User doesn't belong to a managed domain, so enrollment nudging can't
-    // apply.
-    return false;
-  }
-
-  // TODO(b/271104781): replace this check with a policy fetch through a special
-  // DM server API when it is available.
-  if (!ash::features::IsEnrollmentNudgingForTestingEnabled()) {
-    return false;
-  }
-
-  CallExternalAPI("showEnrollmentNudge", email_domain);
-  return true;
-}
-
 void GaiaScreenHandler::CheckIfAllowlisted(const std::string& user_email) {
   // We cannot tell a user type from the identifier, so we delay checking if
   // the account should be allowed.
diff --git a/chrome/browser/ui/webui/ash/login/gaia_screen_handler.h b/chrome/browser/ui/webui/ash/login/gaia_screen_handler.h
index c17f578..b5b44433 100644
--- a/chrome/browser/ui/webui/ash/login/gaia_screen_handler.h
+++ b/chrome/browser/ui/webui/ash/login/gaia_screen_handler.h
@@ -93,6 +93,10 @@
   // for recovery.
   virtual void SetReauthRequestToken(
       const std::string& reauth_request_token) = 0;
+  // Shows pop-up saying that enrollment is required for user's managed domain.
+  virtual void ShowEnrollmentNudge(const std::string& email_domain) = 0;
+  // Checks if user's email is allowlisted.
+  virtual void CheckIfAllowlisted(const std::string& user_email) = 0;
 
   // Show sign-in screen for the given credentials. `services` is a list of
   // services returned by userInfo call as JSON array. Should be an empty array
@@ -148,6 +152,8 @@
   void ShowAllowlistCheckFailedError() override;
   void ReloadGaiaAuthenticator() override;
   void SetReauthRequestToken(const std::string& reauth_request_token) override;
+  void ShowEnrollmentNudge(const std::string& email_domain) override;
+  void CheckIfAllowlisted(const std::string& user_email) override;
 
   void ShowSigninScreenForTest(const std::string& username,
                                const std::string& password,
@@ -244,8 +250,6 @@
 
   void HandleGaiaUIReady();
 
-  void HandleIdentifierEntered(const std::string& account_identifier);
-
   void HandleAuthExtensionLoaded();
 
   // Allows WebUI to control the login shelf's guest and apps buttons visibility
@@ -347,9 +351,6 @@
   void SAMLConfirmPassword(::login::StringList scraped_saml_passwords,
                            std::unique_ptr<UserContext> user_context);
 
-  bool MaybeTriggerEnrollmentNudge(const std::string& user_email);
-  void CheckIfAllowlisted(const std::string& user_email);
-
   // Current state of Gaia frame.
   FrameState frame_state_ = FRAME_STATE_UNKNOWN;
 
diff --git a/chrome/browser/web_applications/externally_managed_app_manager.h b/chrome/browser/web_applications/externally_managed_app_manager.h
index df2e6dfd..f1b5ed7 100644
--- a/chrome/browser/web_applications/externally_managed_app_manager.h
+++ b/chrome/browser/web_applications/externally_managed_app_manager.h
@@ -256,9 +256,9 @@
 
   base::OnceClosure registrations_complete_callback_;
 
-  raw_ptr<WebAppUiManager, DanglingUntriaged> ui_manager_ = nullptr;
-  raw_ptr<WebAppInstallFinalizer, DanglingUntriaged> finalizer_ = nullptr;
-  raw_ptr<WebAppCommandScheduler, DanglingUntriaged> command_scheduler_ =
+  raw_ptr<WebAppUiManager, DanglingAcrossTasks> ui_manager_ = nullptr;
+  raw_ptr<WebAppInstallFinalizer, DanglingAcrossTasks> finalizer_ = nullptr;
+  raw_ptr<WebAppCommandScheduler, DanglingAcrossTasks> command_scheduler_ =
       nullptr;
 
   const raw_ptr<Profile> profile_;
diff --git a/chrome/browser/web_applications/manifest_update_manager.h b/chrome/browser/web_applications/manifest_update_manager.h
index 81bd89f7d..007c56f 100644
--- a/chrome/browser/web_applications/manifest_update_manager.h
+++ b/chrome/browser/web_applications/manifest_update_manager.h
@@ -191,13 +191,13 @@
   static bool& BypassWindowCloseWaitingForTesting();
 
   raw_ptr<WebAppRegistrar, DanglingUntriaged> registrar_ = nullptr;
-  raw_ptr<WebAppUiManager, DanglingUntriaged> ui_manager_ = nullptr;
+  raw_ptr<WebAppUiManager, DanglingAcrossTasks> ui_manager_ = nullptr;
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   raw_ptr<const ash::SystemWebAppDelegateMap, DanglingUntriaged>
       system_web_apps_delegate_map_ = nullptr;
 #endif
-  raw_ptr<WebAppInstallManager, DanglingUntriaged> install_manager_ = nullptr;
-  raw_ptr<WebAppCommandScheduler, DanglingUntriaged> command_scheduler_ =
+  raw_ptr<WebAppInstallManager, DanglingAcrossTasks> install_manager_ = nullptr;
+  raw_ptr<WebAppCommandScheduler, DanglingAcrossTasks> command_scheduler_ =
       nullptr;
 
   base::ScopedObservation<WebAppInstallManager, WebAppInstallManagerObserver>
diff --git a/chrome/browser/web_applications/os_integration/web_app_shortcut_manager.h b/chrome/browser/web_applications/os_integration/web_app_shortcut_manager.h
index 0077ca2..952087f8 100644
--- a/chrome/browser/web_applications/os_integration/web_app_shortcut_manager.h
+++ b/chrome/browser/web_applications/os_integration/web_app_shortcut_manager.h
@@ -173,11 +173,11 @@
 
   const raw_ptr<Profile> profile_;
 
-  raw_ptr<WebAppRegistrar, DanglingUntriaged> registrar_ = nullptr;
-  raw_ptr<WebAppIconManager, DanglingUntriaged> icon_manager_ = nullptr;
-  raw_ptr<WebAppFileHandlerManager, DanglingUntriaged> file_handler_manager_ =
+  raw_ptr<WebAppRegistrar, DanglingAcrossTasks> registrar_ = nullptr;
+  raw_ptr<WebAppIconManager, DanglingAcrossTasks> icon_manager_ = nullptr;
+  raw_ptr<WebAppFileHandlerManager, DanglingAcrossTasks> file_handler_manager_ =
       nullptr;
-  raw_ptr<WebAppProtocolHandlerManager, DanglingUntriaged>
+  raw_ptr<WebAppProtocolHandlerManager, DanglingAcrossTasks>
       protocol_handler_manager_ = nullptr;
 
   base::WeakPtrFactory<WebAppShortcutManager> weak_ptr_factory_{this};
diff --git a/chrome/browser/web_applications/policy/web_app_policy_manager.h b/chrome/browser/web_applications/policy/web_app_policy_manager.h
index 89c7e7e..f070d1fb 100644
--- a/chrome/browser/web_applications/policy/web_app_policy_manager.h
+++ b/chrome/browser/web_applications/policy/web_app_policy_manager.h
@@ -189,7 +189,7 @@
   raw_ptr<const ash::SystemWebAppDelegateMap, DanglingUntriaged>
       system_web_apps_delegate_map_ = nullptr;
 #endif
-  raw_ptr<OsIntegrationManager, DanglingUntriaged> os_integration_manager_ =
+  raw_ptr<OsIntegrationManager, DanglingAcrossTasks> os_integration_manager_ =
       nullptr;
   PrefChangeRegistrar pref_change_registrar_;
   PrefChangeRegistrar local_state_pref_change_registrar_;
diff --git a/chrome/browser/web_applications/preinstalled_web_app_manager.h b/chrome/browser/web_applications/preinstalled_web_app_manager.h
index 7d15e92..1894cf8 100644
--- a/chrome/browser/web_applications/preinstalled_web_app_manager.h
+++ b/chrome/browser/web_applications/preinstalled_web_app_manager.h
@@ -175,8 +175,8 @@
       int force_reinstall_for_milestone);
 
   raw_ptr<WebAppRegistrar, DanglingUntriaged> registrar_ = nullptr;
-  raw_ptr<const WebAppUiManager, DanglingUntriaged> ui_manager_ = nullptr;
-  raw_ptr<ExternallyManagedAppManager, DanglingUntriaged>
+  raw_ptr<const WebAppUiManager, DanglingAcrossTasks> ui_manager_ = nullptr;
+  raw_ptr<ExternallyManagedAppManager, DanglingAcrossTasks>
       externally_managed_app_manager_ = nullptr;
   const raw_ptr<Profile> profile_;
 
diff --git a/chrome/browser/web_applications/web_app_icon_manager.h b/chrome/browser/web_applications/web_app_icon_manager.h
index 82f3062..b0a4dae 100644
--- a/chrome/browser/web_applications/web_app_icon_manager.h
+++ b/chrome/browser/web_applications/web_app_icon_manager.h
@@ -242,7 +242,7 @@
                                  gfx::ImageSkia converted_image);
 
   raw_ptr<WebAppRegistrar, DanglingUntriaged> registrar_;
-  raw_ptr<WebAppInstallManager, DanglingUntriaged> install_manager_;
+  raw_ptr<WebAppInstallManager, DanglingAcrossTasks> install_manager_;
   base::FilePath web_apps_directory_;
   scoped_refptr<FileUtilsWrapper> utils_;
   scoped_refptr<base::SequencedTaskRunner> icon_task_runner_;
diff --git a/chrome/browser/web_applications/web_app_install_finalizer.h b/chrome/browser/web_applications/web_app_install_finalizer.h
index b6b0265..c42aa32 100644
--- a/chrome/browser/web_applications/web_app_install_finalizer.h
+++ b/chrome/browser/web_applications/web_app_install_finalizer.h
@@ -243,18 +243,18 @@
       const AppId& app_id,
       const WebAppInstallInfo& new_web_app_info);
 
-  raw_ptr<WebAppInstallManager, DanglingUntriaged> install_manager_ = nullptr;
+  raw_ptr<WebAppInstallManager, DanglingAcrossTasks> install_manager_ = nullptr;
   raw_ptr<WebAppRegistrar, DanglingUntriaged> registrar_ = nullptr;
   raw_ptr<WebAppSyncBridge, DanglingUntriaged> sync_bridge_ = nullptr;
-  raw_ptr<WebAppUiManager, DanglingUntriaged> ui_manager_ = nullptr;
-  raw_ptr<OsIntegrationManager, DanglingUntriaged> os_integration_manager_ =
+  raw_ptr<WebAppUiManager, DanglingAcrossTasks> ui_manager_ = nullptr;
+  raw_ptr<OsIntegrationManager, DanglingAcrossTasks> os_integration_manager_ =
       nullptr;
   raw_ptr<WebAppIconManager, DanglingUntriaged> icon_manager_ = nullptr;
-  raw_ptr<WebAppPolicyManager, DanglingUntriaged> policy_manager_ = nullptr;
+  raw_ptr<WebAppPolicyManager, DanglingAcrossTasks> policy_manager_ = nullptr;
   raw_ptr<WebAppTranslationManager, DanglingUntriaged> translation_manager_ =
       nullptr;
-  raw_ptr<WebAppCommandManager, DanglingUntriaged> command_manager_ = nullptr;
-  raw_ptr<WebAppOriginAssociationManager, DanglingUntriaged>
+  raw_ptr<WebAppCommandManager, DanglingAcrossTasks> command_manager_ = nullptr;
+  raw_ptr<WebAppOriginAssociationManager, DanglingAcrossTasks>
       origin_association_manager_ = nullptr;
 
   const raw_ptr<Profile> profile_;
diff --git a/chrome/browser/web_applications/web_app_registrar.h b/chrome/browser/web_applications/web_app_registrar.h
index 6eefa2dc..68260f96 100644
--- a/chrome/browser/web_applications/web_app_registrar.h
+++ b/chrome/browser/web_applications/web_app_registrar.h
@@ -530,8 +530,8 @@
 
  private:
   const raw_ptr<Profile> profile_;
-  raw_ptr<WebAppPolicyManager, DanglingUntriaged> policy_manager_ = nullptr;
-  raw_ptr<WebAppTranslationManager, DanglingUntriaged> translation_manager_ =
+  raw_ptr<WebAppPolicyManager, DanglingAcrossTasks> policy_manager_ = nullptr;
+  raw_ptr<WebAppTranslationManager, DanglingAcrossTasks> translation_manager_ =
       nullptr;
 
   base::ScopedObservation<ProfileManager, ProfileManagerObserver>
diff --git a/chrome/browser/web_applications/web_app_sync_bridge.h b/chrome/browser/web_applications/web_app_sync_bridge.h
index a0254af..a20507b4 100644
--- a/chrome/browser/web_applications/web_app_sync_bridge.h
+++ b/chrome/browser/web_applications/web_app_sync_bridge.h
@@ -226,9 +226,9 @@
 
   std::unique_ptr<WebAppDatabase> database_;
   const raw_ptr<WebAppRegistrarMutable, DanglingUntriaged> registrar_;
-  raw_ptr<WebAppCommandManager, DanglingUntriaged> command_manager_;
-  raw_ptr<WebAppCommandScheduler, DanglingUntriaged> command_scheduler_;
-  raw_ptr<WebAppInstallManager, DanglingUntriaged> install_manager_;
+  raw_ptr<WebAppCommandManager, DanglingAcrossTasks> command_manager_;
+  raw_ptr<WebAppCommandScheduler, DanglingAcrossTasks> command_scheduler_;
+  raw_ptr<WebAppInstallManager, DanglingAcrossTasks> install_manager_;
 
   base::OneShotEvent on_sync_connected_;
 
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 00becf1b..5e145f2 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1687823988-498cc1bd24cdee556cb70ef87f293b9522f58636.profdata
+chrome-linux-main-1687845407-147206efc0c24cfd192464c1153ed8fb2274f49c.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index fc0e495..306d222 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1687845407-2fbcc5ef33335cd7837d337c67c9fc2d0b193290.profdata
+chrome-mac-arm-main-1687867043-1061de77ad0901c9b8489b0558746297cfee7a11.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index d4260c171..0d665904 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1687823988-db3f2f35c91f5b9069e9bb9675db7de036054dab.profdata
+chrome-mac-main-1687845407-30c24b7eac8a3387d6b3dad7fddc47be77c7a0f7.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index fbf6aad..0103529 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1687834535-9aeb1b5b573fb2ab28ce7731127ad97f3bafb8fc.profdata
+chrome-win32-main-1687856322-4e9150603b0604097161cba9f7f63a291794d0f7.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 9ef37c9d2..50e3220 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1687834535-9620309ba0c3ba9bb66781c55cda238b6ecaa330.profdata
+chrome-win64-main-1687856322-302c353499e17bd67d3171f0e1ba147f239253f2.profdata
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index cabc94a4..c2c4314 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2368,7 +2368,6 @@
       "../browser/ui/tab_modal_confirm_dialog_browsertest.h",
       "../browser/ui/tab_ui_helper_browsertest.cc",
       "../browser/ui/tabs/pinned_tab_service_browsertest.cc",
-      "../browser/ui/tabs/tab_strip_model_browsertest.cc",
       "../browser/ui/test/browser_ui_browsertest.cc",
       "../browser/ui/test/popup_browsertest.cc",
       "../browser/ui/test/popup_fullscreen_browsertest.cc",
@@ -5676,6 +5675,7 @@
     "../browser/component_updater/chrome_component_updater_configurator_unittest.cc",
     "../browser/component_updater/crl_set_component_installer_unittest.cc",
     "../browser/component_updater/first_party_sets_component_installer_unittest.cc",
+    "../browser/component_updater/masked_domain_list_component_installer_unittest.cc",
     "../browser/component_updater/origin_trials_component_installer_unittest.cc",
     "../browser/component_updater/pki_metadata_component_installer_unittest.cc",
     "../browser/component_updater/privacy_sandbox_attestations_component_installer_unittest.cc",
@@ -5769,6 +5769,7 @@
     # as presentation_service_delegate_impl.* files.
     "../browser/media/router/presentation/presentation_service_delegate_impl_unittest.cc",
     "../browser/media/webrtc/capture_policy_utils_unittest.cc",
+    "../browser/media/webrtc/media_device_salt_service_factory_unittest.cc",
     "../browser/media/webrtc/media_stream_device_permission_context_unittest.cc",
     "../browser/metrics/chrome_browser_main_extra_parts_metrics_unittest.cc",
     "../browser/metrics/chrome_metrics_extensions_helper_unittest.cc",
@@ -6330,6 +6331,7 @@
     "//components/live_caption:constants",
     "//components/lookalikes/core",
     "//components/lookalikes/core:safety_tips",
+    "//components/media_device_salt",
     "//components/media_router/common/providers/cast/channel",
     "//components/media_router/common/providers/cast/channel:test_support",
     "//components/memory_pressure:test_support",
diff --git a/chrome/test/base/in_process_browser_test.h b/chrome/test/base/in_process_browser_test.h
index 22550828..8534e586 100644
--- a/chrome/test/base/in_process_browser_test.h
+++ b/chrome/test/base/in_process_browser_test.h
@@ -387,7 +387,7 @@
   // If no browser is created in BrowserMain(), then |browser_| will remain
   // nullptr unless SelectFirstBrowser() is called after the creation of the
   // first browser instance at a later time.
-  raw_ptr<Browser, DanglingUntriaged> browser_ = nullptr;
+  raw_ptr<Browser, DanglingAcrossTasks> browser_ = nullptr;
 
   // Used to run the process until the BrowserProcess signals the test to quit.
   std::unique_ptr<base::RunLoop> run_loop_;
diff --git a/chrome/test/chromedriver/capabilities.cc b/chrome/test/chromedriver/capabilities.cc
index a29dc8e..0b2d485 100644
--- a/chrome/test/chromedriver/capabilities.cc
+++ b/chrome/test/chromedriver/capabilities.cc
@@ -198,13 +198,10 @@
     absl::optional<bool> mobile = metrics->FindBool("mobile");
     if (metrics->Find("mobile") && !mobile.has_value())
       return Status(kInvalidArgument, "'mobile' must be a boolean");
-    // We don't infere deviceMetrics.mobile form mobile_ua because
-    // mobile device may have no "Mobile" word in its userAgent.
-    // Example: Lumia 950 (Chrome on Windows 10 Mobile)
     if (!mobile.has_value()) {
       // Due to legacy reasons missing 'deviceMetrics.mobile' is inferred as
       // true.
-      VLOG(0) << "Inferring 'deviceMetrics.mobile' as true";
+      VLOG(logging::LOGGING_INFO) << "Inferring 'deviceMetrics.mobile' as true";
       mobile = true;
     }
 
@@ -217,10 +214,11 @@
     }
 
     if (!touch.has_value()) {
-      VLOG(0) << "Inferring 'deviceMetrics.touch' as true.";
+      VLOG(logging::LOGGING_INFO) << "Inferring 'deviceMetrics.touch' as true.";
     }
     if (!maybe_device_scale_factor.has_value()) {
-      VLOG(0) << "Inferring 'deviceMetrics.pixelRatio' as 0.";
+      VLOG(logging::LOGGING_INFO)
+          << "Inferring 'deviceMetrics.pixelRatio' as 0.";
     }
 
     DeviceMetrics device_metrics{width, height,
@@ -230,8 +228,9 @@
   }
 
   if (mobile_ua && !mobile_device.device_metrics.has_value()) {
-    VLOG(0) << "The 'userAgent' value corresponds to a mobile UserAgent but "
-               "'deviceMetrics' is not provided.";
+    VLOG(logging::LOGGING_INFO)
+        << "The 'userAgent' value corresponds to a mobile UserAgent but "
+           "'deviceMetrics' is not provided.";
   }
 
   if (mobile_emulation->Find("clientHints")) {
@@ -269,38 +268,28 @@
     if (client_hints_dict.Find("mobile") && !mobile.has_value()) {
       return Status(kInvalidArgument, "'clientHints.mobile' must be a boolean");
     }
-    if (mobile_device.device_metrics.has_value()) {
-      if (mobile.has_value() &&
-          mobile_device.device_metrics->mobile != mobile.value()) {
-        VLOG(logging::LOGGING_WARNING)
-            << "The mobility in 'deviceMetrics.mobile' contradicts "
-               "'clientHints.mobile' value.";
-      }
-      if (!mobile.has_value()) {
-        VLOG(0) << "Inferring 'clientHints.mobile' as 'deviceMetrics.mobile'.";
-        mobile = mobile_device.device_metrics->mobile;
-      }
-    } else {
-      if (mobile.has_value() && mobile.value()) {
-        VLOG(0) << "User does not provide 'deviceMetrics' while "
-                   "'clintHints.mobile' is true";
-      }
-      // We don't infere deviceMetrics.mobile form mobile_ua because
-      // mobile device may have no "Mobile" word in its userAgent.
-      // Example: Lumia 950 (Chrome on Windows 10 Mobile)
-      if (!mobile.has_value()) {
-        VLOG(0) << "Inferring 'clientHints.mobile' as false";
+    if (!mobile.has_value()) {
+      if (base::ToUpperASCII(client_hints.platform) == "ANDROID" &&
+          mobile_device.user_agent.has_value()) {
+        VLOG(logging::LOGGING_INFO)
+            << "Inferring 'clientHints.mobile' from 'userAgent' as "
+            << mobile_ua;
+        mobile = mobile_ua;
+      } else {
+        VLOG(logging::LOGGING_INFO)
+            << "Inferring 'clientHints.mobile' as false";
         mobile = false;
       }
     }
-    // All the paths above assign some value to 'mobile'
-    if (mobile_device.user_agent.has_value() && mobile_ua && !mobile.value()) {
-      // Presence of word Mobile in UserAgent clearly hints that the device is
-      // mobile. The opposite is not true.
-      VLOG(logging::LOGGING_WARNING)
-          << "The mobility in 'userAgent' contradicts "
-             "'clientHints.mobile' value.";
+    if (mobile_device.device_metrics.has_value()) {
+      if (mobile.has_value() && mobile.value() &&
+          !mobile_device.device_metrics->mobile) {
+        VLOG(logging::LOGGING_WARNING)
+            << "The mobility in 'clientHints.mobile' contradicts "
+               "'deviceMetrics.mobile' value.";
+      }
     }
+    // All the paths above assign some value to 'mobile'
     client_hints.mobile = mobile.value();
 
     if (client_hints_dict.Find("architecture")) {
@@ -312,7 +301,8 @@
       }
       client_hints.architecture = *architecture;
     } else {
-      VLOG(0) << "Inferring 'clientHints.architecture' as an empty string.";
+      VLOG(logging::LOGGING_INFO)
+          << "Inferring 'clientHints.architecture' as an empty string.";
       client_hints.architecture = "";
     }
 
@@ -324,7 +314,8 @@
       }
       client_hints.bitness = *bitness;
     } else {
-      VLOG(0) << "Inferring 'clientHints.bitness' as an empty string.";
+      VLOG(logging::LOGGING_INFO)
+          << "Inferring 'clientHints.bitness' as an empty string.";
       client_hints.bitness = "";
     }
 
@@ -360,7 +351,8 @@
 
       client_hints.brands = std::move(brands);
     } else {
-      VLOG(0) << "Inferring 'clientHints.brands' as browser defined.";
+      VLOG(logging::LOGGING_INFO)
+          << "Inferring 'clientHints.brands' as browser defined.";
     }
 
     if (client_hints_dict.Find("fullVersionList")) {
@@ -397,7 +389,8 @@
 
       client_hints.full_version_list = std::move(full_version_list);
     } else {
-      VLOG(0) << "Inferring 'clientHints.fullversionList' as browser defined.";
+      VLOG(logging::LOGGING_INFO)
+          << "Inferring 'clientHints.fullversionList' as browser defined.";
     }
 
     if (client_hints_dict.Find("model")) {
@@ -406,12 +399,14 @@
         return Status(kInvalidArgument, "'clientHints.model' must be a string");
       }
       if (!client_hints.mobile && model->size() > 0) {
-        VLOG(0) << "User provides 'clientHints.model' for a non-mobile "
-                   "platform as indicated by 'clientHints.mobile'";
+        VLOG(logging::LOGGING_INFO)
+            << "User provides 'clientHints.model' for a non-mobile "
+               "platform as indicated by 'clientHints.mobile'";
       }
       client_hints.model = *model;
     } else {
-      VLOG(0) << "Inferring 'clientHints.model' as an empty string.";
+      VLOG(logging::LOGGING_INFO)
+          << "Inferring 'clientHints.model' as an empty string.";
       client_hints.model = "";
     }
 
@@ -424,7 +419,8 @@
       }
       client_hints.platform_version = *platform_version;
     } else {
-      VLOG(0) << "Inferring 'clientHints.platformVersion' as an empty string.";
+      VLOG(logging::LOGGING_INFO)
+          << "Inferring 'clientHints.platformVersion' as an empty string.";
       client_hints.platform_version = "";
     }
 
@@ -436,25 +432,24 @@
       }
       client_hints.wow64 = *wow64;
     } else {
-      VLOG(0) << "Inferring 'clientHints.wow64' as false.";
+      VLOG(logging::LOGGING_INFO) << "Inferring 'clientHints.wow64' as false.";
       client_hints.wow64 = false;
     }
 
     mobile_device.client_hints = std::move(client_hints);
   } else if (mobile_device.user_agent.has_value()) {
-    VLOG(0)
+    VLOG(logging::LOGGING_INFO)
         << "Operating in legacy emulation mode as 'mobileEmulation' contains "
            "no 'clientHints'.";
     ClientHints client_hints;
-    client_hints.mobile = mobile_device.device_metrics.has_value()
-                              ? mobile_device.device_metrics->mobile
-                              : false;
     if (!MobileDevice::GuessPlatform(mobile_device.user_agent.value(),
                                      &client_hints.platform)) {
       // In legacy mode we allow platform to be empty.
       // Otherwise we might break the users' tests.
       client_hints.platform = "";
     }
+    client_hints.mobile =
+        client_hints.platform == "Android" ? mobile_ua : false;
     // Empty value corresponds to the result of GetCpuArchitecture in
     // //content/common/user_agent.cc.
     client_hints.architecture = "";
@@ -464,17 +459,18 @@
     client_hints.model = "";
     client_hints.platform_version = "";
     client_hints.wow64 = false;
-    VLOG(0) << "No 'clientHints' found. Operating in legacy mode. "
-            << "Inferring clientHints as: "
-            << "{architecture='" << client_hints.architecture << "'"
-            << ", bitness='" << client_hints.bitness << "'"
-            << ", brands=<browser-defined>"
-            << ", fullVersionList=<browser-defined>"
-            << ", mobile=" << std::boolalpha << client_hints.mobile
-            << ", model='" << client_hints.model << "'"
-            << ", platform='" << client_hints.platform << "'"
-            << ", platformVersion='" << client_hints.platform_version << "'"
-            << ", wow64=" << std::boolalpha << client_hints.wow64 << "}";
+    VLOG(logging::LOGGING_INFO)
+        << "No 'clientHints' found. Operating in legacy mode. "
+        << "Inferring clientHints as: "
+        << "{architecture='" << client_hints.architecture << "'"
+        << ", bitness='" << client_hints.bitness << "'"
+        << ", brands=<browser-defined>"
+        << ", fullVersionList=<browser-defined>"
+        << ", mobile=" << std::boolalpha << client_hints.mobile << ", model='"
+        << client_hints.model << "'"
+        << ", platform='" << client_hints.platform << "'"
+        << ", platformVersion='" << client_hints.platform_version << "'"
+        << ", wow64=" << std::boolalpha << client_hints.wow64 << "}";
     mobile_device.client_hints = std::move(client_hints);
   }
 
diff --git a/chrome/test/chromedriver/capabilities_unittest.cc b/chrome/test/chromedriver/capabilities_unittest.cc
index e4dd8b3..398eff67 100644
--- a/chrome/test/chromedriver/capabilities_unittest.cc
+++ b/chrome/test/chromedriver/capabilities_unittest.cc
@@ -825,7 +825,8 @@
 TEST(ParseClientHints, MinimalistMobileAndroid) {
   Capabilities capabilities;
   const std::string mobile_emulation =
-      "{\"deviceMetrics\": {}, \"clientHints\": {\"platform\": \"Android\"}}";
+      "{\"deviceMetrics\": {}, \"clientHints\": {\"platform\": \"Android\", "
+      "\"mobile\": true}}";
   base::Value::Dict caps = CreateCapabilitiesDict(mobile_emulation);
   EXPECT_TRUE(StatusOk(capabilities.Parse(caps)));
   ASSERT_TRUE(capabilities.mobile_device.has_value());
@@ -845,8 +846,8 @@
 TEST(ParseClientHints, MinimalistTabletAndroid) {
   Capabilities capabilities;
   const std::string mobile_emulation =
-      "{\"deviceMetrics\": {\"mobile\": false},"
-      "\"clientHints\": {\"platform\": \"Android\"}}";
+      "{\"deviceMetrics\": {},"
+      "\"clientHints\": {\"platform\": \"Android\", \"mobile\": false}}";
   base::Value::Dict caps = CreateCapabilitiesDict(mobile_emulation);
   EXPECT_TRUE(StatusOk(capabilities.Parse(caps)));
   ASSERT_TRUE(capabilities.mobile_device.has_value());
@@ -894,7 +895,7 @@
   Capabilities capabilities;
   const std::string mobile_emulation = base::StringPrintf(
       "{\"deviceMetrics\": {},"
-      "\"clientHints\": {\"platform\": \"%s\"}}",
+      "\"clientHints\": {\"platform\": \"%s\", \"mobile\": true}}",
       expected_platform.c_str());
   base::Value::Dict caps = CreateCapabilitiesDict(mobile_emulation);
   EXPECT_TRUE(StatusOk(capabilities.Parse(caps)));
@@ -917,8 +918,8 @@
   const std::string expected_user_agent = GetParam().second;
   Capabilities capabilities;
   const std::string mobile_emulation = base::StringPrintf(
-      "{\"deviceMetrics\": {\"mobile\": false},"
-      "\"clientHints\": {\"platform\": \"%s\"}}",
+      "{\"deviceMetrics\": {},"
+      "\"clientHints\": {\"platform\": \"%s\", \"mobile\": false}}",
       expected_platform.c_str());
   base::Value::Dict caps = CreateCapabilitiesDict(mobile_emulation);
   EXPECT_TRUE(StatusOk(capabilities.Parse(caps)));
@@ -950,7 +951,7 @@
   Capabilities capabilities;
   const std::string mobile_emulation = base::StringPrintf(
       "{\"userAgent\": \"%s\", \"deviceMetrics\": {},"
-      "\"clientHints\": {\"platform\": \"Custom\"}}",
+      "\"clientHints\": {\"platform\": \"Custom\", \"mobile\": true}}",
       kUserAgentMobileChromeOnIOS);
   base::Value::Dict caps = CreateCapabilitiesDict(mobile_emulation);
   EXPECT_TRUE(StatusOk(capabilities.Parse(caps)));
@@ -974,8 +975,8 @@
 TEST(ParseClientHints, MinimalistCustomTablet) {
   Capabilities capabilities;
   const std::string mobile_emulation = base::StringPrintf(
-      "{\"userAgent\": \"%s\", \"deviceMetrics\": {\"mobile\": false},"
-      "\"clientHints\": {\"platform\": \"Custom\"}}",
+      "{\"userAgent\": \"%s\", \"deviceMetrics\": {},"
+      "\"clientHints\": {\"platform\": \"Custom\", \"mobile\": false}}",
       kUserAgentNonMobileChromeOnIOS);
   base::Value::Dict caps = CreateCapabilitiesDict(mobile_emulation);
   EXPECT_TRUE(StatusOk(capabilities.Parse(caps)));
@@ -996,10 +997,12 @@
   EXPECT_TRUE(reduced_user_agent.empty());
 }
 
-class InferClientHintsOnAndroid : public testing::TestWithParam<std::string> {};
+class InferClientHintsOnAndroid
+    : public testing::TestWithParam<std::pair<std::string, bool>> {};
 
 TEST_P(InferClientHintsOnAndroid, NoDeviceMetrics) {
-  const std::string input_user_agent = GetParam();
+  const std::string input_user_agent = GetParam().first;
+  const bool expected_is_mobile = GetParam().second;
   const std::string mobile_emulation =
       base::StringPrintf("{\"userAgent\": \"%s\"}", input_user_agent.c_str());
   Capabilities capabilities;
@@ -1013,16 +1016,16 @@
   EXPECT_TRUE(capabilities.mobile_device->user_agent.has_value());
   ASSERT_EQ(input_user_agent, capabilities.mobile_device->user_agent.value());
   EXPECT_EQ("Android", client_hints.platform);
-  // Inferred as non-mobile due to the lack of device metrics
-  EXPECT_EQ(false, client_hints.mobile);
+  EXPECT_EQ(expected_is_mobile, client_hints.mobile);
   std::string reduced_user_agent;
   EXPECT_TRUE(StatusOk(capabilities.mobile_device->GetReducedUserAgent(
       "114", &reduced_user_agent)));
-  EXPECT_EQ(kUserAgentNonMobileChromeOnAndroid, reduced_user_agent);
+  EXPECT_EQ(input_user_agent, reduced_user_agent);
 }
 
 TEST_P(InferClientHintsOnAndroid, MobileDeviceMetrics) {
-  const std::string input_user_agent = GetParam();
+  const std::string input_user_agent = GetParam().first;
+  const bool expected_is_mobile = GetParam().second;
   const std::string mobile_emulation =
       base::StringPrintf("{\"userAgent\": \"%s\", \"deviceMetrics\": {}}",
                          input_user_agent.c_str());
@@ -1037,16 +1040,16 @@
   EXPECT_TRUE(capabilities.mobile_device->user_agent.has_value());
   ASSERT_EQ(input_user_agent, capabilities.mobile_device->user_agent.value());
   EXPECT_EQ("Android", client_hints.platform);
-  // Deriverd from deviceMetrics.mobile that always defaults to true
-  EXPECT_EQ(true, client_hints.mobile);
+  EXPECT_EQ(expected_is_mobile, client_hints.mobile);
   std::string reduced_user_agent;
   EXPECT_TRUE(StatusOk(capabilities.mobile_device->GetReducedUserAgent(
       "114", &reduced_user_agent)));
-  EXPECT_EQ(kUserAgentMobileChromeOnAndroid, reduced_user_agent);
+  EXPECT_EQ(input_user_agent, reduced_user_agent);
 }
 
 TEST_P(InferClientHintsOnAndroid, TabletDeviceMetrics) {
-  const std::string input_user_agent = GetParam();
+  const std::string input_user_agent = GetParam().first;
+  const bool expected_is_mobile = GetParam().second;
   const std::string mobile_emulation = base::StringPrintf(
       "{\"userAgent\": \"%s\", \"deviceMetrics\": {\"mobile\": false}}",
       input_user_agent.c_str());
@@ -1062,17 +1065,18 @@
   ASSERT_EQ(input_user_agent, capabilities.mobile_device->user_agent.value());
   EXPECT_EQ("Android", client_hints.platform);
   // Deriverd from deviceMetrics.mobile
-  EXPECT_EQ(false, client_hints.mobile);
+  EXPECT_EQ(expected_is_mobile, client_hints.mobile);
   std::string reduced_user_agent;
   EXPECT_TRUE(StatusOk(capabilities.mobile_device->GetReducedUserAgent(
       "114", &reduced_user_agent)));
-  EXPECT_EQ(kUserAgentNonMobileChromeOnAndroid, reduced_user_agent);
+  EXPECT_EQ(input_user_agent, reduced_user_agent);
 }
 
-INSTANTIATE_TEST_SUITE_P(Inference,
-                         InferClientHintsOnAndroid,
-                         testing::Values(kUserAgentMobileChromeOnAndroid,
-                                         kUserAgentNonMobileChromeOnAndroid));
+INSTANTIATE_TEST_SUITE_P(
+    Inference,
+    InferClientHintsOnAndroid,
+    testing::Values(std::make_pair(kUserAgentMobileChromeOnAndroid, true),
+                    std::make_pair(kUserAgentNonMobileChromeOnAndroid, false)));
 
 class InferClientHintsPerPlatform
     : public testing::TestWithParam<std::pair<std::string, std::string>> {};
@@ -1120,8 +1124,7 @@
   ASSERT_EQ(expected_user_agent,
             capabilities.mobile_device->user_agent.value());
   EXPECT_EQ(expected_platform, client_hints.platform);
-  // Deriverd from deviceMetrics.mobile that always defaults to true
-  EXPECT_EQ(true, client_hints.mobile);
+  EXPECT_EQ(false, client_hints.mobile);
   std::string reduced_user_agent;
   EXPECT_TRUE(StatusOk(capabilities.mobile_device->GetReducedUserAgent(
       "114", &reduced_user_agent)));
@@ -1181,7 +1184,6 @@
   EXPECT_TRUE(capabilities.mobile_device->user_agent.has_value());
   ASSERT_EQ(input_user_agent, capabilities.mobile_device->user_agent.value());
   EXPECT_EQ("", client_hints.platform);
-  // Inferred as non-mobile due to the lack of device metrics
   EXPECT_EQ(false, client_hints.mobile);
   std::string reduced_user_agent;
   EXPECT_TRUE(capabilities.mobile_device
@@ -1206,8 +1208,7 @@
   EXPECT_TRUE(capabilities.mobile_device->user_agent.has_value());
   ASSERT_EQ(input_user_agent, capabilities.mobile_device->user_agent.value());
   EXPECT_EQ("", client_hints.platform);
-  // Deriverd from deviceMetrics.mobile that always defaults to true
-  EXPECT_EQ(true, client_hints.mobile);
+  EXPECT_EQ(false, client_hints.mobile);
   std::string reduced_user_agent;
   EXPECT_TRUE(capabilities.mobile_device
                   ->GetReducedUserAgent("114", &reduced_user_agent)
@@ -1231,7 +1232,6 @@
   EXPECT_TRUE(capabilities.mobile_device->user_agent.has_value());
   ASSERT_EQ(input_user_agent, capabilities.mobile_device->user_agent.value());
   EXPECT_EQ("", client_hints.platform);
-  // Deriverd from deviceMetrics.mobile
   EXPECT_EQ(false, client_hints.mobile);
   std::string reduced_user_agent;
   EXPECT_TRUE(capabilities.mobile_device
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index ea4be2a..c9397a84 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -5172,9 +5172,10 @@
     self.assertFalse(driver.w3c_compliant)
 
   def testClientHintsMobileLegacy(self):
-    expected_ua = 'Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 5 Bui'
-    'ld/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko) Chr'
-    'ome/18.0.1025.166 Mobile Safari/535.19'
+    expected_ua = ''.join(['Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 5',
+                          'Build/JOP40D) AppleWebKit/535.19',
+                          '(KHTML, like Gecko) Chrome/18.0.1025.166 Mobile',
+                           'Safari/535.19'])
     driver = self.CreateDriver(
         mobile_emulation = {
             'deviceMetrics': {'width': 360, 'height': 640, 'pixelRatio': 3},
@@ -5225,6 +5226,7 @@
                 'platformVersion': '17',
                 'architecture': 'arm',
                 'bitness': '32',
+                'mobile': True,
                 'model': 'Special',
             }
         })
diff --git a/chromeos/ash/components/auth_panel/BUILD.gn b/chromeos/ash/components/auth_panel/BUILD.gn
index 7266408..b5fcd8c 100644
--- a/chromeos/ash/components/auth_panel/BUILD.gn
+++ b/chromeos/ash/components/auth_panel/BUILD.gn
@@ -14,6 +14,8 @@
     "//ui/views",
   ]
   sources = [
+    "auth_factor_store.cc",
+    "auth_factor_store.h",
     "auth_panel.cc",
     "auth_panel.h",
     "auth_panel_event_dispatcher.cc",
diff --git a/chromeos/ash/components/auth_panel/auth_factor_store.cc b/chromeos/ash/components/auth_panel/auth_factor_store.cc
new file mode 100644
index 0000000..a7a9fc27
--- /dev/null
+++ b/chromeos/ash/components/auth_panel/auth_factor_store.cc
@@ -0,0 +1,33 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/ash/components/auth_panel/auth_factor_store.h"
+
+#include "base/notreached.h"
+#include "chromeos/ash/components/osauth/public/common_types.h"
+
+namespace ash {
+
+AuthFactorStore::AuthFactorStore() = default;
+
+AuthFactorStore::~AuthFactorStore() = default;
+
+void AuthFactorStore::OnUserAction(
+    AshAuthFactor factor,
+    const AuthPanelEventDispatcher::UserAction& action) {
+  NOTIMPLEMENTED();
+}
+
+void AuthFactorStore::OnFactorStateChanged(AshAuthFactor factor,
+                                           AuthFactorState state) {
+  NOTIMPLEMENTED();
+}
+
+void AuthFactorStore::OnAuthVerdict(
+    AshAuthFactor factor,
+    AuthPanelEventDispatcher::AuthVerdict verdict) {
+  NOTIMPLEMENTED();
+}
+
+}  // namespace ash
diff --git a/chromeos/ash/components/auth_panel/auth_factor_store.h b/chromeos/ash/components/auth_panel/auth_factor_store.h
new file mode 100644
index 0000000..d4b7169
--- /dev/null
+++ b/chromeos/ash/components/auth_panel/auth_factor_store.h
@@ -0,0 +1,34 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_ASH_COMPONENTS_AUTH_PANEL_AUTH_FACTOR_STORE_H_
+#define CHROMEOS_ASH_COMPONENTS_AUTH_PANEL_AUTH_FACTOR_STORE_H_
+
+#include "base/callback_list.h"
+#include "chromeos/ash/components/auth_panel/auth_panel_event_dispatcher.h"
+#include "chromeos/ash/components/auth_panel/factor_auth_view.h"
+#include "chromeos/ash/components/osauth/public/common_types.h"
+
+namespace ash {
+
+// This class encapsulates the UI state of `AuthPanel`.
+class AuthFactorStore {
+ public:
+  using OnStateUpdatedCallback = base::RepeatingCallback<void()>;
+
+  AuthFactorStore();
+  ~AuthFactorStore();
+
+  void Subscribe(OnStateUpdatedCallback callback);
+
+  void OnUserAction(AshAuthFactor factor,
+                    const AuthPanelEventDispatcher::UserAction& action);
+  void OnFactorStateChanged(AshAuthFactor factor, AuthFactorState state);
+  void OnAuthVerdict(AshAuthFactor factor,
+                     AuthPanelEventDispatcher::AuthVerdict verdict);
+};
+
+}  // namespace ash
+
+#endif  // CHROMEOS_ASH_COMPONENTS_AUTH_PANEL_AUTH_FACTOR_STORE_H_
diff --git a/chromeos/ash/components/auth_panel/auth_panel.cc b/chromeos/ash/components/auth_panel/auth_panel.cc
index f0659b4..ffe59f98 100644
--- a/chromeos/ash/components/auth_panel/auth_panel.cc
+++ b/chromeos/ash/components/auth_panel/auth_panel.cc
@@ -6,54 +6,53 @@
 
 #include "base/logging.h"
 #include "base/notreached.h"
+#include "chromeos/ash/components/auth_panel/auth_factor_store.h"
 #include "chromeos/ash/components/auth_panel/auth_panel_event_dispatcher.h"
 #include "chromeos/ash/components/auth_panel/factor_auth_view.h"
 #include "chromeos/ash/components/auth_panel/factor_auth_view_factory.h"
+#include "chromeos/ash/components/osauth/public/auth_factor_status_consumer.h"
 #include "chromeos/ash/components/osauth/public/common_types.h"
 
 namespace ash {
 
 AuthPanel::AuthPanel(std::unique_ptr<FactorAuthViewFactory> view_factory,
+                     std::unique_ptr<AuthFactorStore> store,
                      std::unique_ptr<AuthPanelEventDispatcher> event_dispatcher)
-    : view_factory_(std::move(view_factory)),
-      event_dispatcher_(std::move(event_dispatcher)) {}
+    : event_dispatcher_(std::move(event_dispatcher)),
+      view_factory_(std::move(view_factory)),
+      store_(std::move(store)) {}
 
 AuthPanel::~AuthPanel() = default;
 
 void AuthPanel::InitializeUi(AuthFactorsSet factors,
                              AuthHubConnector* connector) {
-  CHECK(views_.empty());
-  for (const auto factor : factors) {
-    auto view = view_factory_->CreateFactorAuthView(factor);
-    view->OnFactorStateChanged(AuthFactorState::kCheckingForPresence);
-    views_[factor] = std::move(view);
+  for (auto&& factor : factors) {
+    views_.push_back(view_factory_->CreateFactorAuthView(factor));
+    event_dispatcher_->DispatchEvent(factor,
+                                     AuthFactorState::kCheckingForPresence);
   }
 }
 
 void AuthPanel::OnFactorListChanged(FactorsStatusMap factors_with_status) {
-  views_.clear();
   for (const auto& [factor, status] : factors_with_status) {
-    auto view = view_factory_->CreateFactorAuthView(factor);
-    view->OnFactorStateChanged(status);
-    views_[factor] = std::move(view);
+    event_dispatcher_->DispatchEvent(factor, status);
   }
 }
 
 void AuthPanel::OnFactorStatusesChanged(FactorsStatusMap incremental_update) {
   for (const auto& [factor, status] : incremental_update) {
-    CHECK(views_.contains(factor));
-    views_[factor]->OnFactorStateChanged(status);
+    event_dispatcher_->DispatchEvent(factor, status);
   }
 }
 
 void AuthPanel::OnFactorAuthFailure(AshAuthFactor factor) {
-  CHECK(views_.contains(factor));
-  views_[factor]->OnAuthFailure();
+  event_dispatcher_->DispatchEvent(
+      factor, AuthPanelEventDispatcher::AuthVerdict::kFailure);
 }
 
 void AuthPanel::OnFactorAuthSuccess(AshAuthFactor factor) {
-  CHECK(views_.contains(factor));
-  views_[factor]->OnAuthSuccess();
+  event_dispatcher_->DispatchEvent(
+      factor, AuthPanelEventDispatcher::AuthVerdict::kSuccess);
 }
 
 void AuthPanel::OnEndAuthentication() {
diff --git a/chromeos/ash/components/auth_panel/auth_panel.h b/chromeos/ash/components/auth_panel/auth_panel.h
index 26b3046a..341aff3 100644
--- a/chromeos/ash/components/auth_panel/auth_panel.h
+++ b/chromeos/ash/components/auth_panel/auth_panel.h
@@ -5,15 +5,16 @@
 #ifndef CHROMEOS_ASH_COMPONENTS_AUTH_PANEL_AUTH_PANEL_H_
 #define CHROMEOS_ASH_COMPONENTS_AUTH_PANEL_AUTH_PANEL_H_
 
-#include <memory>
+#include <vector>
 
 #include "base/containers/flat_map.h"
-#include "chromeos/ash/components/auth_panel/auth_panel_event_dispatcher.h"
 #include "chromeos/ash/components/osauth/public/auth_factor_status_consumer.h"
 #include "chromeos/ash/components/osauth/public/common_types.h"
 
 namespace ash {
 
+class AuthPanelEventDispatcher;
+class AuthFactorStore;
 class FactorAuthView;
 class FactorAuthViewFactory;
 
@@ -28,6 +29,7 @@
 class AuthPanel : public AuthFactorStatusConsumer {
  public:
   AuthPanel(std::unique_ptr<FactorAuthViewFactory> view_factory,
+            std::unique_ptr<AuthFactorStore> store,
             std::unique_ptr<AuthPanelEventDispatcher> event_dispatcher);
   AuthPanel(const AuthPanel&) = delete;
   AuthPanel(AuthPanel&&) = delete;
@@ -45,9 +47,10 @@
   void OnEndAuthentication() override;
 
  private:
-  base::flat_map<AshAuthFactor, std::unique_ptr<FactorAuthView>> views_;
-  std::unique_ptr<FactorAuthViewFactory> view_factory_;
   std::unique_ptr<AuthPanelEventDispatcher> event_dispatcher_;
+  std::unique_ptr<FactorAuthViewFactory> view_factory_;
+  std::unique_ptr<AuthFactorStore> store_;
+  std::vector<std::unique_ptr<FactorAuthView>> views_;
 };
 
 }  // namespace ash
diff --git a/chromeos/ash/components/auth_panel/auth_panel_event_dispatcher.cc b/chromeos/ash/components/auth_panel/auth_panel_event_dispatcher.cc
index 2cbe5bd80..6854dfe3 100644
--- a/chromeos/ash/components/auth_panel/auth_panel_event_dispatcher.cc
+++ b/chromeos/ash/components/auth_panel/auth_panel_event_dispatcher.cc
@@ -9,12 +9,14 @@
 
 namespace ash {
 
-AuthPanelEventDispatcher::AuthPanelEventDispatcher() = default;
+AuthPanelEventDispatcher::AuthPanelEventDispatcher(
+    base::raw_ptr<AuthFactorStore> store)
+    : store_(store) {}
 
 AuthPanelEventDispatcher::~AuthPanelEventDispatcher() = default;
 
 void AuthPanelEventDispatcher::DispatchEvent(AshAuthFactor factor,
-                                             UserAction action) {
+                                             const UserAction& action) {
   NOTIMPLEMENTED();
 }
 
diff --git a/chromeos/ash/components/auth_panel/auth_panel_event_dispatcher.h b/chromeos/ash/components/auth_panel/auth_panel_event_dispatcher.h
index c47d41a..4da37df 100644
--- a/chromeos/ash/components/auth_panel/auth_panel_event_dispatcher.h
+++ b/chromeos/ash/components/auth_panel/auth_panel_event_dispatcher.h
@@ -8,15 +8,37 @@
 #include "chromeos/ash/components/osauth/public/auth_factor_status_consumer.h"
 #include "chromeos/ash/components/osauth/public/common_types.h"
 
+#include "base/containers/flat_map.h"
+#include "base/memory/weak_ptr.h"
+#include "chromeos/ash/components/auth_panel/factor_auth_view.h"
+#include "chromeos/ash/components/osauth/public/auth_factor_status_consumer.h"
+#include "chromeos/ash/components/osauth/public/common_types.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
 namespace ash {
 
+class AuthFactorStore;
+
 // This class is responsible for dispatching auth panel ui events to
 // `AuthFactorStore`.
 class AuthPanelEventDispatcher {
  public:
-  enum UserAction {
-    // Emitted whenever the user presses the pin/password toggle button.
-    kPasswordPinToggle,
+  struct UserAction {
+    enum Type {
+      // Emitted whenever the user presses the pin/password toggle button.
+      kPasswordPinToggle,
+      kMaxValue = kPasswordPinToggle,
+    };
+
+    UserAction();
+    ~UserAction();
+    UserAction(const UserAction& other) = delete;
+    UserAction& operator=(const UserAction& other) = delete;
+    UserAction(UserAction&& other) = delete;
+    UserAction& operator=(UserAction&& other) = delete;
+
+    Type type;
+    absl::optional<std::string> value;
   };
 
   enum AuthVerdict {
@@ -24,16 +46,19 @@
     kFailure,
   };
 
-  AuthPanelEventDispatcher();
+  explicit AuthPanelEventDispatcher(base::raw_ptr<AuthFactorStore> store);
   ~AuthPanelEventDispatcher();
   AuthPanelEventDispatcher(const AuthPanelEventDispatcher&) = delete;
   AuthPanelEventDispatcher(AuthPanelEventDispatcher&&) = delete;
   AuthPanelEventDispatcher& operator=(const AuthPanelEventDispatcher&) = delete;
   AuthPanelEventDispatcher& operator=(AuthPanelEventDispatcher&&) = delete;
 
-  void DispatchEvent(AshAuthFactor factor, UserAction action);
-  void DispatchEvent(AshAuthFactor factor, AuthVerdict verdict);
+  void DispatchEvent(AshAuthFactor factor, const UserAction& action);
   void DispatchEvent(AshAuthFactor factor, AuthFactorState state);
+  void DispatchEvent(AshAuthFactor factor, AuthVerdict verdict);
+
+ private:
+  base::raw_ptr<AuthFactorStore> store_;
 };
 
 }  // namespace ash
diff --git a/chromeos/ash/components/auth_panel/factor_auth_view_factory.cc b/chromeos/ash/components/auth_panel/factor_auth_view_factory.cc
index 889ea3f..924e9c42 100644
--- a/chromeos/ash/components/auth_panel/factor_auth_view_factory.cc
+++ b/chromeos/ash/components/auth_panel/factor_auth_view_factory.cc
@@ -10,8 +10,8 @@
 
 namespace ash {
 
-std::unique_ptr<FactorAuthView> FactorAuthViewFactory::CreateFactorAuthView(
-    AshAuthFactor factor) {
+[[nodiscard]] std::unique_ptr<FactorAuthView>
+FactorAuthViewFactory::CreateFactorAuthView(AshAuthFactor factor) {
   switch (factor) {
     case AshAuthFactor::kGaiaPassword:
       return CreatePasswordView();
diff --git a/chromeos/ash/components/auth_panel/factor_auth_view_factory.h b/chromeos/ash/components/auth_panel/factor_auth_view_factory.h
index 965d43b..80126b3 100644
--- a/chromeos/ash/components/auth_panel/factor_auth_view_factory.h
+++ b/chromeos/ash/components/auth_panel/factor_auth_view_factory.h
@@ -13,11 +13,10 @@
 
 namespace ash {
 
-// This class is responsible for creating the different `FactorAuthView` objects
-// that will be owned and managed by `AuthPanel`. This is done mainly to
-// facilitate dependency injection and testing and to centralize the creation
-// logic into one class, freeing up `AuthPanel` to deal exclusively with UI
-// update logic.
+// This class is responsible for creating the different `FactorAuthView`
+// objects. This is done mainly to facilitate dependency injection and testing
+// and to centralize the creation logic into one class, freeing up `AuthPanel`
+// to deal exclusively with UI update logic.
 class FactorAuthViewFactory {
  public:
   using FactorAuthViewCreator =
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index c86a6f0..fde59611 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -975,6 +975,7 @@
     "personal_data_manager_test_base.h",
     "personal_data_manager_unittest.cc",
     "profile_requirement_utils_unittest.cc",
+    "profile_token_quality_unittest.cc",
     "randomized_encoder_unittest.cc",
     "rationalization_util_unittest.cc",
     "single_field_form_fill_router_unittest.cc",
diff --git a/components/autofill/core/browser/autofill_field.cc b/components/autofill/core/browser/autofill_field.cc
index 68c0e89..b91c1bb 100644
--- a/components/autofill/core/browser/autofill_field.cc
+++ b/components/autofill/core/browser/autofill_field.cc
@@ -33,7 +33,8 @@
 // default prediction. We don't need to store it, because its meaning is that
 // there is no default prediction.
 bool IsDefaultPrediction(const FieldPrediction& prediction) {
-  constexpr DenseSet<FieldPrediction::Source, FieldPrediction::Source_MAX>
+  constexpr DenseSet<FieldPrediction::Source, FieldPrediction::Source(0),
+                     FieldPrediction::Source_MAX>
       default_sources = {FieldPrediction::SOURCE_AUTOFILL_DEFAULT,
                          FieldPrediction::SOURCE_PASSWORDS_DEFAULT,
                          FieldPrediction::SOURCE_OVERRIDE};
diff --git a/components/autofill/core/browser/autofill_profile_import_process.cc b/components/autofill/core/browser/autofill_profile_import_process.cc
index 1084b61..f580baf 100644
--- a/components/autofill/core/browser/autofill_profile_import_process.cc
+++ b/components/autofill/core/browser/autofill_profile_import_process.cc
@@ -11,6 +11,7 @@
 #include "components/autofill/core/browser/field_types.h"
 #include "components/autofill/core/browser/metrics/profile_import_metrics.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/browser/profile_requirement_utils.h"
 #include "components/autofill/core/common/autofill_clock.h"
 #include "components/autofill/core/common/autofill_features.h"
 
@@ -296,13 +297,9 @@
     return;
   }
   // Check the eligiblity of the user and profile.
-  if (!personal_data_manager_->IsEligibleForAddressAccountStorage() ||
-      personal_data_manager_->IsProfileMigrationBlocked(profile.guid()) ||
-      !personal_data_manager_->IsCountryEligibleForAccountStorage(
-          base::UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY)))) {
-    return;
+  if (IsEligibleForMigrationToAccount(*personal_data_manager_, profile)) {
+    migration_candidate = profile;
   }
-  migration_candidate = profile;
 }
 
 std::vector<AutofillProfile> ProfileImportProcess::GetResultingProfiles() {
diff --git a/components/autofill/core/browser/browser_autofill_manager.cc b/components/autofill/core/browser/browser_autofill_manager.cc
index c280d79..896ac49 100644
--- a/components/autofill/core/browser/browser_autofill_manager.cc
+++ b/components/autofill/core/browser/browser_autofill_manager.cc
@@ -1016,7 +1016,7 @@
   if (!GetCachedFormAndField(form, field, &form_structure, &autofill_field))
     return;
 
-  auto* logger = GetEventFormLogger(autofill_field->Type().group());
+  auto* logger = GetEventFormLogger(*autofill_field);
   if (logger)
     logger->OnPopupSuppressed(*form_structure, *autofill_field);
 }
@@ -1049,7 +1049,7 @@
     profile_form_bitmask = data_util::DetermineGroups(*form_structure);
   }
 
-  auto* logger = GetEventFormLogger(autofill_field->Type().group());
+  auto* logger = GetEventFormLogger(*autofill_field);
   if (!autofill_field->is_autofilled) {
     if (logger)
       logger->OnTypedIntoNonFilledField();
@@ -1580,7 +1580,7 @@
         client()->GetSecurityLevelForUmaHistograms(), profile_form_bitmask);
   }
 
-  auto* logger = GetEventFormLogger(autofill_field->Type().group());
+  auto* logger = GetEventFormLogger(*autofill_field);
   if (logger) {
     logger->OnDidShowSuggestions(*form_structure, *autofill_field,
                                  form_structure->form_parsed_timestamp(),
@@ -1712,7 +1712,7 @@
   if (!GetCachedFormAndField(form, field, &form_structure, &autofill_field))
     return;
 
-  auto* logger = GetEventFormLogger(autofill_field->Type().group());
+  auto* logger = GetEventFormLogger(*autofill_field);
   if (logger)
     logger->OnUserHideSuggestions(*form_structure, *autofill_field);
 }
@@ -1877,7 +1877,7 @@
   if (delta >= kLimitBeforeRefill)
     return;
 
-  auto* logger = GetEventFormLogger(autofill_field->Type().group());
+  auto* logger = GetEventFormLogger(*autofill_field);
   if (logger) {
     logger->OnAutofilledFieldWasClearedByJavaScriptShortlyAfterFill(
         *form_structure);
@@ -2026,7 +2026,7 @@
     FormInteractionCounts form_interaction_counts = {};
     if (submitted_form->field_count() > 0) {
       const AutofillField* autofill_field = submitted_form->field(0);
-      auto* logger = GetEventFormLogger(autofill_field->Type().group());
+      auto* logger = GetEventFormLogger(*autofill_field);
       if (logger) {
         form_interaction_counts = logger->form_interaction_counts();
       }
@@ -3264,7 +3264,7 @@
     if (context->focused_field->Type().group() == FieldTypeGroup::kCreditCard) {
       context->is_filling_credit_card = true;
     }
-    auto* logger = GetEventFormLogger(context->focused_field->Type().group());
+    auto* logger = GetEventFormLogger(*context->focused_field);
     if (logger) {
       logger->OnDidInteractWithAutofillableForm(*(context->form_structure),
                                                 sync_state_);
@@ -3419,9 +3419,16 @@
 #endif
 
 autofill_metrics::FormEventLoggerBase*
-BrowserAutofillManager::GetEventFormLogger(
-    FieldTypeGroup field_type_group) const {
-  switch (FieldTypeGroupToFormType(field_type_group)) {
+BrowserAutofillManager::GetEventFormLogger(const AutofillField& field) const {
+  if (field.ShouldSuppressSuggestionsAndFillingByDefault()) {
+    // Ignore ac=unrecognized fields in key metrics: Prior to
+    // `kAutofillPredictionsForAutocompleteUnrecognized`, ac=unrecognized fields
+    // did not receive a type prediction and were consequently not associated to
+    // any event logger. To retain the same baseline for key metrics, continue
+    // to exclude such fields.
+    return nullptr;
+  }
+  switch (FieldTypeGroupToFormType(field.Type().group())) {
     case FormType::kAddressForm:
       return address_form_event_logger_.get();
     case FormType::kCreditCardForm:
@@ -3430,8 +3437,7 @@
     case FormType::kUnknownFormType:
       return nullptr;
   }
-  NOTREACHED();
-  return nullptr;
+  NOTREACHED_NORETURN();
 }
 
 void BrowserAutofillManager::PreProcessStateMatchingTypes(
@@ -3663,7 +3669,18 @@
 void BrowserAutofillManager::SetFastCheckoutRunId(
     FieldTypeGroup field_type_group,
     int64_t run_id) {
-  GetEventFormLogger(field_type_group)->SetFastCheckoutRunId(run_id);
+  switch (FieldTypeGroupToFormType(field_type_group)) {
+    case FormType::kAddressForm:
+      address_form_event_logger_->SetFastCheckoutRunId(run_id);
+      return;
+    case FormType::kCreditCardForm:
+      credit_card_form_event_logger_->SetFastCheckoutRunId(run_id);
+      break;
+    case FormType::kPasswordForm:
+    case FormType::kUnknownFormType:
+      // FastCheckout only supports address and credit card forms.
+      NOTREACHED();
+  }
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/browser_autofill_manager.h b/components/autofill/core/browser/browser_autofill_manager.h
index 72dbbe0..a684139 100644
--- a/components/autofill/core/browser/browser_autofill_manager.h
+++ b/components/autofill/core/browser/browser_autofill_manager.h
@@ -737,10 +737,10 @@
   bool ShouldShowVirtualCardOption(FormStructure* form_structure);
 #endif
 
-  // Returns an appropriate EventFormLogger for the given |field_type_group|.
-  // May return nullptr.
+  // Returns an appropriate EventFormLogger, depending on the given `field`'s
+  // type. May return nullptr.
   autofill_metrics::FormEventLoggerBase* GetEventFormLogger(
-      FieldTypeGroup field_type_group) const;
+      const AutofillField& field) const;
 
   void SetDataList(const std::vector<std::u16string>& values,
                    const std::vector<std::u16string>& labels);
diff --git a/components/autofill/core/browser/browser_autofill_manager_unittest.cc b/components/autofill/core/browser/browser_autofill_manager_unittest.cc
index db79e66..81449c1 100644
--- a/components/autofill/core/browser/browser_autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/browser_autofill_manager_unittest.cc
@@ -3663,6 +3663,49 @@
   ExpectFilledForm(filled_form, fill_data, /*card_fill_data=*/absl::nullopt);
 }
 
+// Tests that when `kAutofillPredictionsForAutocompleteUnrecognized` is enabled,
+// fields with unrecognized autocomplete attribute don't contribute to key
+// metrics.
+TEST_F(BrowserAutofillManagerTest, AutocompleteUnrecognizedFields_KeyMetrics) {
+  base::test::ScopedFeatureList feature(
+      features::kAutofillPredictionsForAutocompleteUnrecognized);
+
+  // Create an address form where field 1 has an unrecognized autocomplete
+  // attribute.
+  FormData form;
+  test::CreateTestAddressFormData(&form);
+  ASSERT_GE(form.fields.size(), 2u);
+  form.fields[1].parsed_autocomplete =
+      AutocompleteParsingResult{.field_type = HtmlFieldType::kUnrecognized};
+
+  // Interact with an ac != unrecognized field: Expect key metrics to be
+  // emitted. Note that "interacting" means querying suggestions, usually
+  // caused by clicking into a field.
+  {
+    FormsSeen({form});
+    GetAutofillSuggestions(form, form.fields[0]);
+    FormSubmitted(form);
+
+    base::HistogramTester histogram_tester;
+    browser_autofill_manager_->Reset();
+    histogram_tester.ExpectTotalCount(
+        "Autofill.KeyMetrics.FillingAssistance.Address", 1);
+  }
+
+  // Interact with an ac = unrecognized field: Expect no key metric to be
+  // emitted.
+  {
+    FormsSeen({form});
+    GetAutofillSuggestions(form, form.fields[1]);
+    FormSubmitted(form);
+
+    base::HistogramTester histogram_tester;
+    browser_autofill_manager_->Reset();
+    histogram_tester.ExpectTotalCount(
+        "Autofill.KeyMetrics.FillingAssistance.Address", 0);
+  }
+}
+
 TEST_F(BrowserAutofillManagerTest, WillFillCreditCardNumber) {
   // Set up our form data.
   FormData form = CreateTestCreditCardFormData(true, false);
diff --git a/components/autofill/core/browser/field_types.h b/components/autofill/core/browser/field_types.h
index 2de9e93..1deab10 100644
--- a/components/autofill/core/browser/field_types.h
+++ b/components/autofill/core/browser/field_types.h
@@ -405,7 +405,8 @@
   kMaxValue = kIban,
 };
 
-using ServerFieldTypeSet = DenseSet<ServerFieldType, MAX_VALID_FIELD_TYPE>;
+using ServerFieldTypeSet =
+    DenseSet<ServerFieldType, NO_SERVER_DATA, MAX_VALID_FIELD_TYPE>;
 
 std::ostream& operator<<(std::ostream& o, ServerFieldTypeSet field_type_set);
 
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc
index a1a8a59..0f88e97 100644
--- a/components/autofill/core/browser/form_structure.cc
+++ b/components/autofill/core/browser/form_structure.cc
@@ -1690,7 +1690,15 @@
 DenseSet<FormType> FormStructure::GetFormTypes() const {
   DenseSet<FormType> form_types;
   for (const auto& field : fields_) {
-    form_types.insert(FieldTypeGroupToFormType(field->Type().group()));
+    if (field->ShouldSuppressSuggestionsAndFillingByDefault()) {
+      // When `kAutofillPredictionsForAutocompleteUnrecognized` is enabled,
+      // types are predicted for fields with unrecognized autocomplete
+      // attribute. They are excluded from the form types, to keep the baseline
+      // for key and quality metrics.
+      form_types.insert(FormType::kUnknownFormType);
+    } else {
+      form_types.insert(FieldTypeGroupToFormType(field->Type().group()));
+    }
   }
   return form_types;
 }
diff --git a/components/autofill/core/browser/form_structure_unittest.cc b/components/autofill/core/browser/form_structure_unittest.cc
index da59f50..498e9ff 100644
--- a/components/autofill/core/browser/form_structure_unittest.cc
+++ b/components/autofill/core/browser/form_structure_unittest.cc
@@ -6783,4 +6783,22 @@
               ElementsAre(0, 0, 1, 0, 0, 0));
 }
 
+// Tests that when `kAutofillPredictionsForAutocompleteUnrecognized` is enabled,
+// forms that are completely annotated with ac=unrecognized are not classified
+// as address forms.
+TEST_F(FormStructureTestImpl, GetFormTypes_AutocompleteUnrecognized) {
+  base::test::ScopedFeatureList feature(
+      features::kAutofillPredictionsForAutocompleteUnrecognized);
+
+  FormData form;
+  test::CreateTestAddressFormData(&form);
+  for (FormFieldData& field : form.fields) {
+    field.parsed_autocomplete =
+        AutocompleteParsingResult{.field_type = HtmlFieldType::kUnrecognized};
+  }
+  FormStructure form_structure(form);
+  EXPECT_THAT(form_structure.GetFormTypes(),
+              UnorderedElementsAre(FormType::kUnknownFormType));
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/browser/metrics/autofill_metrics.h b/components/autofill/core/browser/metrics/autofill_metrics.h
index 19aa3f3..f637e9d 100644
--- a/components/autofill/core/browser/metrics/autofill_metrics.h
+++ b/components/autofill/core/browser/metrics/autofill_metrics.h
@@ -653,8 +653,9 @@
     kMaxValue = kIsInSubFrame
   };
 
-  using FormEventSet =
-      DenseSet<autofill_metrics::FormEvent, autofill_metrics::NUM_FORM_EVENTS>;
+  using FormEventSet = DenseSet<autofill_metrics::FormEvent,
+                                autofill_metrics::FormEvent(0),
+                                autofill_metrics::NUM_FORM_EVENTS>;
 
   // Utility class for determining the seamlessness of a credit card fill.
   class CreditCardSeamlessness {
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager.h b/components/autofill/core/browser/payments/credit_card_access_manager.h
index adf082d..a5660b2 100644
--- a/components/autofill/core/browser/payments/credit_card_access_manager.h
+++ b/components/autofill/core/browser/payments/credit_card_access_manager.h
@@ -453,7 +453,7 @@
   raw_ptr<PersonalDataManager> personal_data_manager_;
 
   // For logging metrics.
-  raw_ptr<autofill_metrics::CreditCardFormEventLogger, DanglingUntriaged>
+  raw_ptr<autofill_metrics::CreditCardFormEventLogger, DanglingAcrossTasks>
       form_event_logger_;
 
   // Timestamp used for preflight call metrics.
diff --git a/components/autofill/core/browser/profile_requirement_utils.cc b/components/autofill/core/browser/profile_requirement_utils.cc
index a2d0d08..e2835037 100644
--- a/components/autofill/core/browser/profile_requirement_utils.cc
+++ b/components/autofill/core/browser/profile_requirement_utils.cc
@@ -4,6 +4,7 @@
 
 #include "components/autofill/core/browser/profile_requirement_utils.h"
 
+#include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/browser/field_types.h"
 #include "components/autofill/core/browser/geo/autofill_country.h"
 #include "components/autofill/core/common/autofill_internals/log_message.h"
@@ -106,7 +107,6 @@
       GetAutofillProfileRequirementResult(profile, predicted_country_code,
                                           app_locale,
                                           /*import_log_buffer=*/nullptr);
-
   return !base::ranges::any_of(
       kMinimumAddressRequirementViolations,
       [&](AddressImportRequirement address_requirement_violation) {
@@ -115,4 +115,13 @@
       });
 }
 
+bool IsEligibleForMigrationToAccount(
+    const PersonalDataManager& personal_data_manager,
+    const AutofillProfile& profile) {
+  return personal_data_manager.IsEligibleForAddressAccountStorage() &&
+         !personal_data_manager.IsProfileMigrationBlocked(profile.guid()) &&
+         personal_data_manager.IsCountryEligibleForAccountStorage(
+             base::UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY)));
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/browser/profile_requirement_utils.h b/components/autofill/core/browser/profile_requirement_utils.h
index 9fc05d08..8047775 100644
--- a/components/autofill/core/browser/profile_requirement_utils.h
+++ b/components/autofill/core/browser/profile_requirement_utils.h
@@ -9,6 +9,7 @@
 
 #include "components/autofill/core/browser/data_model/autofill_profile.h"
 #include "components/autofill/core/browser/metrics/profile_import_metrics.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/common/logging/log_buffer.h"
 
 namespace autofill {
@@ -52,6 +53,12 @@
                       const std::string& predicted_country_code,
                       const std::string& app_locale);
 
+// Returns true if the profile can be migrated to the Account. Only sufficiently
+// complete profiles are migrated and this method does not check for the
+// completeness of the `profile`.
+bool IsEligibleForMigrationToAccount(
+    const PersonalDataManager& personal_data_manager,
+    const AutofillProfile& profile);
 }  //  namespace autofill
 
 #endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_PROFILE_REQUIREMENT_UTILS_H_
diff --git a/components/autofill/core/browser/profile_token_quality.cc b/components/autofill/core/browser/profile_token_quality.cc
index 9ca1844..f9a49a94 100644
--- a/components/autofill/core/browser/profile_token_quality.cc
+++ b/components/autofill/core/browser/profile_token_quality.cc
@@ -8,12 +8,16 @@
 #include <vector>
 
 #include "base/check.h"
+#include "base/containers/circular_deque.h"
+#include "base/containers/contains.h"
+#include "base/containers/fixed_flat_map.h"
 #include "base/notreached.h"
 #include "components/autofill/core/browser/autofill_field.h"
 #include "components/autofill/core/browser/data_model/autofill_profile.h"
 #include "components/autofill/core/browser/field_types.h"
 #include "components/autofill/core/browser/form_structure.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/browser/webdata/autofill_table.h"
 
 namespace autofill {
 
@@ -25,6 +29,38 @@
   return types;
 }
 
+// Only a subset of the `GetSupportedTypes()` is stored. Every non-stored type
+// is derived from a stored type. This function returns the stored type of
+// `type`. If `type` is already a stored type, `type` is returned.
+//
+// ADDRESS_HOME_ADDRESS is not handled, since it is an artificial, unused type
+// to represent the root node of the address tree. The type is not stored and
+// not used for filling.
+ServerFieldType GetStoredTypeOf(ServerFieldType type) {
+  if (base::Contains(AutofillTable::GetStoredTypesForAutofillProfile(), type)) {
+    return type;
+  }
+  CHECK_NE(type, ADDRESS_HOME_ADDRESS);
+  static const auto kStoredTypeOf =
+      base::MakeFixedFlatMap<ServerFieldType, ServerFieldType>(
+          {{ADDRESS_HOME_LINE1, ADDRESS_HOME_STREET_ADDRESS},
+           {ADDRESS_HOME_LINE2, ADDRESS_HOME_STREET_ADDRESS},
+           {ADDRESS_HOME_LINE3, ADDRESS_HOME_STREET_ADDRESS},
+           {NAME_MIDDLE_INITIAL, NAME_MIDDLE},
+           {PHONE_HOME_NUMBER, PHONE_HOME_WHOLE_NUMBER},
+           {PHONE_HOME_CITY_CODE, PHONE_HOME_WHOLE_NUMBER},
+           {PHONE_HOME_CITY_CODE_WITH_TRUNK_PREFIX, PHONE_HOME_WHOLE_NUMBER},
+           {PHONE_HOME_COUNTRY_CODE, PHONE_HOME_WHOLE_NUMBER},
+           {PHONE_HOME_CITY_AND_NUMBER, PHONE_HOME_WHOLE_NUMBER},
+           {PHONE_HOME_CITY_AND_NUMBER_WITHOUT_TRUNK_PREFIX,
+            PHONE_HOME_WHOLE_NUMBER},
+           {PHONE_HOME_NUMBER_PREFIX, PHONE_HOME_WHOLE_NUMBER},
+           {PHONE_HOME_NUMBER_SUFFIX, PHONE_HOME_WHOLE_NUMBER}});
+  auto* it = kStoredTypeOf.find(type);
+  CHECK_NE(it, kStoredTypeOf.end());
+  return it->second;
+}
+
 }  // namespace
 
 ProfileTokenQuality::ProfileTokenQuality(AutofillProfile* profile)
@@ -42,12 +78,40 @@
   return false;
 }
 
+void ProfileTokenQuality::AddObservationForTesting(
+    ServerFieldType field_type,
+    ObservationType observation_type) {
+  AddObservation(field_type, Observation{.type = observation_type});
+}
+
 std::vector<ProfileTokenQuality::ObservationType>
 ProfileTokenQuality::GetObservationTypesForFieldType(
     ServerFieldType type) const {
   CHECK(GetSupportedTypes(*profile_).contains(type));
-  NOTIMPLEMENTED();
-  return {};
+  const auto it = observations_.find(GetStoredTypeOf(type));
+  if (it == observations_.end()) {
+    return {};
+  }
+  std::vector<ObservationType> types;
+  types.reserve(it->second.size());
+  for (const Observation& observation : it->second) {
+    types.push_back(observation.type);
+  }
+  return types;
+}
+
+void ProfileTokenQuality::AddObservation(ServerFieldType type,
+                                         Observation observation) {
+  CHECK(GetSupportedTypes(*profile_).contains(type));
+  CHECK_NE(observation.type, ObservationType::kNone);
+  base::circular_deque<Observation>& observations =
+      observations_[GetStoredTypeOf(type)];
+  CHECK_LE(observations.size(), kMaxObservationsPerToken);
+  static_assert(kMaxObservationsPerToken > 0);
+  if (observations.size() == kMaxObservationsPerToken) {
+    observations.pop_front();
+  }
+  observations.push_back(std::move(observation));
 }
 
 ProfileTokenQuality::FormAndFieldSignatureHash
diff --git a/components/autofill/core/browser/profile_token_quality.h b/components/autofill/core/browser/profile_token_quality.h
index 4edd0c4..0666a72 100644
--- a/components/autofill/core/browser/profile_token_quality.h
+++ b/components/autofill/core/browser/profile_token_quality.h
@@ -108,6 +108,9 @@
                                     const FormData& form_data,
                                     const PersonalDataManager& pdm);
 
+  void AddObservationForTesting(ServerFieldType field_type,
+                                ObservationType observation_type);
+
   // Returns all `ObservationType`s available for the `type`. The resulting
   // vector has at most `kMaxNumberOfObservations` items. It is guaranteed that
   // no observation type is `kNone`.
@@ -138,6 +141,11 @@
       FormSignature form_signature,
       FieldSignature field_signature) const;
 
+  // Adds the `observation` to the `observations_` for the stored type of
+  // `type`. The oldest existing observation for that type is discarded, if
+  // the limit of `kMaxObservationsPerToken` is exceeded.
+  void AddObservation(ServerFieldType type, Observation observation);
+
   // The profile for which observations are collected. Not null.
   base::raw_ptr<AutofillProfile> profile_;
 
diff --git a/components/autofill/core/browser/profile_token_quality_unittest.cc b/components/autofill/core/browser/profile_token_quality_unittest.cc
new file mode 100644
index 0000000..3c4f5c4
--- /dev/null
+++ b/components/autofill/core/browser/profile_token_quality_unittest.cc
@@ -0,0 +1,62 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/profile_token_quality.h"
+
+#include <vector>
+
+#include "components/autofill/core/browser/data_model/autofill_profile.h"
+#include "components/autofill/core/browser/field_types.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+
+using ObservationType = ProfileTokenQuality::ObservationType;
+
+// Ensures that `ProfileTokenQualityTest` supports all supported types of
+// `AutofillProfile`. In particular, this test ensures that whenever a new
+// non-stored type is added, the map in `GetStoredTypeOf()` is updated
+// accordingly. If the type is supposed to be stored, it should be added to
+// `AutofillTable::GetStoredTypesForAutofillProfile()`.
+TEST(ProfileTokenQualityTest, AllSupportedTypesHandled) {
+  ServerFieldTypeSet supported_types;
+  AutofillProfile profile;
+  profile.GetSupportedTypes(&supported_types);
+  ProfileTokenQuality quality(&profile);
+  for (ServerFieldType type : supported_types) {
+    // See comment above `GetStoredTypeOf()` why this type is special.
+    if (type == ADDRESS_HOME_ADDRESS) {
+      continue;
+    }
+    // `GetObservationTypesForFieldType()` will internally call
+    // `GetStoredTypeOf()`. A `CHECK()` will fail if the mapping is incomplete.
+    EXPECT_TRUE(quality.GetObservationTypesForFieldType(type).empty());
+  }
+}
+
+TEST(ProfileTokenQualityTest, GetObservationTypesForFieldType) {
+  AutofillProfile profile;
+  ProfileTokenQuality quality(&profile);
+
+  EXPECT_TRUE(quality.GetObservationTypesForFieldType(NAME_FIRST).empty());
+
+  quality.AddObservationForTesting(NAME_FIRST, ObservationType::kAccepted);
+  EXPECT_THAT(quality.GetObservationTypesForFieldType(NAME_FIRST),
+              testing::UnorderedElementsAre(ObservationType::kAccepted));
+  EXPECT_TRUE(quality.GetObservationTypesForFieldType(NAME_LAST).empty());
+
+  // Test that if more than `kMaxObservationsPerToken` observations are added,
+  // only the first `kMaxObservationsPerToken` are returned.
+  for (size_t i = 0; i < ProfileTokenQuality::kMaxObservationsPerToken; i++) {
+    quality.AddObservationForTesting(NAME_FIRST,
+                                     ObservationType::kEditedToSimilarValue);
+  }
+  EXPECT_THAT(quality.GetObservationTypesForFieldType(NAME_FIRST),
+              testing::UnorderedElementsAreArray(std::vector<ObservationType>(
+                  ProfileTokenQuality::kMaxObservationsPerToken,
+                  ObservationType::kEditedToSimilarValue)));
+}
+
+}  // namespace autofill
diff --git a/components/autofill/core/browser/webdata/contact_info_sync_bridge.cc b/components/autofill/core/browser/webdata/contact_info_sync_bridge.cc
index eb93ec9..1aebf9b 100644
--- a/components/autofill/core/browser/webdata/contact_info_sync_bridge.cc
+++ b/components/autofill/core/browser/webdata/contact_info_sync_bridge.cc
@@ -316,9 +316,7 @@
     change_processor()->ReportError(
         {FROM_HERE, "Failed reading CONTACT_INFO metadata from WebDatabase."});
     return;
-  } else if (base::FeatureList::IsEnabled(
-                 syncer::kCacheBaseEntitySpecificsInMetadata) &&
-             SyncMetadataCacheContainsSupportedFields(
+  } else if (SyncMetadataCacheContainsSupportedFields(
                  batch->GetAllMetadata())) {
     // Caching entity specifics is meant to preserve fields not supported in a
     // given browser version during commits to the server. If the cache
diff --git a/components/autofill/core/common/dense_set.h b/components/autofill/core/common/dense_set.h
index 800d5ad..9002d52 100644
--- a/components/autofill/core/common/dense_set.h
+++ b/components/autofill/core/common/dense_set.h
@@ -158,7 +158,7 @@
 // representation.
 //
 // The lower and upper bounds of elements storable in a container are
-// [T(0), kMaxValue]. By default, kMaxValue is T::kMaxValue.
+// [kMinValue, kMaxValue]. The default is [0, T::kMaxValue].
 //
 // The `packed` parameter indicates whether the memory consumption of a DenseSet
 // object should be minimized. That comes at the cost of slightly larger code
@@ -167,25 +167,50 @@
 // Time and space complexity:
 // - insert(), erase(), contains() run in time O(1)
 // - empty(), size(), iteration run in time O(kMaxValue)
-// - sizeof(DenseSet) is, for N = kMaxValue + 1,
+// - sizeof(DenseSet) is, for N = `kMaxValue - kMinValue + 1,
 //   - if `!packed`: the minimum of {1, 2, 4, 8 * ceil(N / 64)} bytes that has
 //     at least N bits;
 //   - if `packed`: ceil(N / 8) bytes.
 //
 // Iterators are invalidated when the owning container is destructed or moved,
 // or when the element the iterator points to is erased from the container.
-template <typename T, T kMaxValue = T::kMaxValue, bool packed = false>
+template <typename T,
+          T kMinValue = T(0),
+          T kMaxValue = T::kMaxValue,
+          bool packed = false>
 class DenseSet {
  private:
-  // The index of a bit.
-  using Index = std::make_unsigned_t<T>;
-
   static_assert(std::is_integral<T>::value || std::is_enum<T>::value);
-  static_assert(0 <= base::checked_cast<Index>(kMaxValue) + 1);
+
+  // Needed for std::conditional_t.
+  struct Wrapper {
+    using type = T;
+  };
+
+  // For arithmetic on `T`.
+  using UnderlyingType = typename std::conditional_t<std::is_enum<T>::value,
+                                                     std::underlying_type<T>,
+                                                     Wrapper>::type;
+
+  // The index of a bit in the underlying bitset. Use
+  // value_to_index() and index_to_value() for conversion.
+  using Index = std::make_unsigned_t<UnderlyingType>;
+
+  // We can't use `base::to_underlying()` because `T` may be not an enum.
+  static constexpr UnderlyingType to_underlying(T x) {
+    return static_cast<UnderlyingType>(x);
+  }
+
+  static_assert(to_underlying(kMinValue) <= to_underlying(kMaxValue));
 
   // The maximum supported bit index. Indexing starts at 0, so kMaxBitIndex ==
-  // 63 means we need 64 bits.
-  static constexpr size_t kMaxBitIndex = base::checked_cast<Index>(kMaxValue);
+  // 63 means we need 64 bits. This is a `size_t` to avoid `kMaxBitIndex + 1`
+  // from overflowing.
+  static constexpr size_t kMaxBitIndex = base::checked_cast<Index>(
+      to_underlying(kMaxValue) - to_underlying(kMinValue));
+
+  static_assert(kMaxBitIndex <
+                std::numeric_limits<decltype(kMaxBitIndex)>::max());
 
  public:
   // The bitset is represented as array of words.
@@ -450,23 +475,17 @@
 
   using Bitset = internal::Bitset<Word, kNumWords>;
 
-  // Needed to use std::conditional_t.
-  // Must be declared outside of index_to_value() to avoid compiler errors.
-  struct Wrapper {
-    using type = T;
-  };
-
   static constexpr Index value_to_index(T x) {
-    DCHECK(index_to_value(0) <= x && x <= kMaxValue);
-    return base::checked_cast<Index>(x);
+    DCHECK_LE(kMinValue, x);
+    DCHECK_LE(x, kMaxValue);
+    return base::checked_cast<Index>(to_underlying(x) -
+                                     to_underlying(kMinValue));
   }
 
   static constexpr T index_to_value(Index i) {
     DCHECK_LE(i, base::checked_cast<Index>(kMaxValue));
-    using UnderlyingType =
-        typename std::conditional_t<std::is_enum<T>::value,
-                                    std::underlying_type<T>, Wrapper>::type;
-    return static_cast<T>(base::checked_cast<UnderlyingType>(i));
+    return static_cast<T>(base::checked_cast<UnderlyingType>(i) +
+                          to_underlying(kMinValue));
   }
 
   Bitset bitset_{};
diff --git a/components/autofill/core/common/dense_set_unittest.cc b/components/autofill/core/common/dense_set_unittest.cc
index 8c4ccbf..1119acd0 100644
--- a/components/autofill/core/common/dense_set_unittest.cc
+++ b/components/autofill/core/common/dense_set_unittest.cc
@@ -15,43 +15,43 @@
 namespace autofill {
 
 TEST(DenseSetTest, size_of) {
-  EXPECT_EQ(sizeof(DenseSet<size_t, 1>), 1u);
-  EXPECT_EQ(sizeof(DenseSet<size_t, 7>), 1u);
-  EXPECT_EQ(sizeof(DenseSet<size_t, 8>), 2u);
-  EXPECT_EQ(sizeof(DenseSet<size_t, 15>), 2u);
-  EXPECT_EQ(sizeof(DenseSet<size_t, 16>), 4u);
-  EXPECT_EQ(sizeof(DenseSet<size_t, 31>), 4u);
-  EXPECT_EQ(sizeof(DenseSet<size_t, 32>), 8u);
-  EXPECT_EQ(sizeof(DenseSet<size_t, 63>), 8u);
-  EXPECT_EQ(sizeof(DenseSet<size_t, 64>), 16u);
-  EXPECT_EQ(sizeof(DenseSet<size_t, 127>), 16u);
-  EXPECT_EQ(sizeof(DenseSet<size_t, 255>), 32u);
+  EXPECT_EQ(sizeof(DenseSet<size_t, 0, 1>), 1u);
+  EXPECT_EQ(sizeof(DenseSet<size_t, 0, 7>), 1u);
+  EXPECT_EQ(sizeof(DenseSet<size_t, 0, 8>), 2u);
+  EXPECT_EQ(sizeof(DenseSet<size_t, 0, 15>), 2u);
+  EXPECT_EQ(sizeof(DenseSet<size_t, 0, 16>), 4u);
+  EXPECT_EQ(sizeof(DenseSet<size_t, 0, 31>), 4u);
+  EXPECT_EQ(sizeof(DenseSet<size_t, 0, 32>), 8u);
+  EXPECT_EQ(sizeof(DenseSet<size_t, 0, 63>), 8u);
+  EXPECT_EQ(sizeof(DenseSet<size_t, 0, 64>), 16u);
+  EXPECT_EQ(sizeof(DenseSet<size_t, 0, 127>), 16u);
+  EXPECT_EQ(sizeof(DenseSet<size_t, 0, 255>), 32u);
 }
 
 TEST(DenseSetTest, initialization) {
   enum class T : size_t {
-    One = 1,
-    Two = 2,
-    Three = 3,
-    Four = 4,
-    Five = 5,
-    kMaxValue = Five,
+    kOne = 1,
+    kTwo = 2,
+    kThree = 3,
+    kFour = 4,
+    kFive = 5,
+    kMaxValue = kFive,
   };
-  using DS = DenseSet<T, T::kMaxValue>;
+  using DS = DenseSet<T>;
 
   DS s;
   EXPECT_TRUE(s.empty());
   EXPECT_EQ(s.size(), 0u);
   EXPECT_EQ(DS(s.begin(), s.end()), s);
-  s.insert(T::Two);
-  s.insert(T::Four);
-  s.insert(T::One);
+  s.insert(T::kTwo);
+  s.insert(T::kFour);
+  s.insert(T::kOne);
   EXPECT_EQ(s.size(), 3u);
   EXPECT_EQ(DS(s.begin(), s.end()), s);
   EXPECT_EQ(DS(s.cbegin(), s.cend()), s);
   EXPECT_EQ(DS(s.rbegin(), s.rend()), s);
   EXPECT_EQ(DS(s.crbegin(), s.crend()), s);
-  EXPECT_EQ(DS({T::Four, T::Two, T::One}), s);
+  EXPECT_EQ(DS({T::kFour, T::kTwo, T::kOne}), s);
 }
 
 TEST(DenseSetTest, initializer_list) {
@@ -63,35 +63,35 @@
 
   {
     constexpr size_t kMax = 10;
-    constexpr DenseSet<size_t, kMax> set{0, 1, kMax - 2, kMax - 1, kMax};
+    constexpr DenseSet<size_t, 0, kMax> set{0, 1, kMax - 2, kMax - 1, kMax};
     EXPECT_THAT(std::vector<size_t>(set.begin(), set.end()),
                 ::testing::ElementsAre(0, 1, kMax - 2, kMax - 1, kMax));
   }
 
   {
     constexpr size_t kMax = kMaxValueForConstexpr;
-    constexpr DenseSet<size_t, kMax> set{0, 1, kMax - 2, kMax - 1, kMax};
+    constexpr DenseSet<size_t, 0, kMax> set{0, 1, kMax - 2, kMax - 1, kMax};
     EXPECT_THAT(std::vector<size_t>(set.begin(), set.end()),
                 ::testing::ElementsAre(0, 1, kMax - 2, kMax - 1, kMax));
   }
 
   {
     constexpr size_t kMax = kMaxValueForConstexpr + 1;
-    DenseSet<size_t, kMax> set{0, 1, kMax - 2, kMax - 1, kMax};
+    DenseSet<size_t, 0, kMax> set{0, 1, kMax - 2, kMax - 1, kMax};
     EXPECT_THAT(std::vector<size_t>(set.begin(), set.end()),
                 ::testing::ElementsAre(0, 1, kMax - 2, kMax - 1, kMax));
   }
 
   {
     constexpr size_t kMax = kMaxValueForConstexpr + 2;
-    DenseSet<size_t, kMax> set{0, 1, kMax - 2, kMax - 1, kMax};
+    DenseSet<size_t, 0, kMax> set{0, 1, kMax - 2, kMax - 1, kMax};
     EXPECT_THAT(std::vector<size_t>(set.begin(), set.end()),
                 ::testing::ElementsAre(0, 1, kMax - 2, kMax - 1, kMax));
   }
 
   {
     constexpr size_t kMax = kMaxValueForConstexpr + 100;
-    DenseSet<size_t, kMax> set{0, 1, kMax - 2, kMax - 1, kMax};
+    DenseSet<size_t, 0, kMax> set{0, 1, kMax - 2, kMax - 1, kMax};
     EXPECT_THAT(std::vector<size_t>(set.begin(), set.end()),
                 ::testing::ElementsAre(0, 1, kMax - 2, kMax - 1, kMax));
   }
@@ -99,21 +99,21 @@
 
 TEST(DenseSetTest, data) {
   {
-    constexpr DenseSet<size_t, 23> set{0, 1, 2, 3, 4, 20, 23};
+    constexpr DenseSet<size_t, 0, 23> set{0, 1, 2, 3, 4, 20, 23};
     EXPECT_THAT(
         set.data(),
         ElementsAre((1ULL << 0) | (1ULL << 1) | (1ULL << 2) | (1ULL << 3) |
                     (1ULL << 4) | (1ULL << 20) | (1ULL << 23)));
   }
   {
-    constexpr DenseSet<size_t, 31> set{0, 1, 2, 3, 4, 20, 31};
+    constexpr DenseSet<size_t, 0, 31> set{0, 1, 2, 3, 4, 20, 31};
     EXPECT_THAT(
         set.data(),
         ElementsAre((1ULL << 0) | (1ULL << 1) | (1ULL << 2) | (1ULL << 3) |
                     (1ULL << 4) | (1ULL << 20) | (1ULL << 31)));
   }
   {
-    constexpr DenseSet<size_t, 63> set{0, 1, 63};
+    constexpr DenseSet<size_t, 0, 63> set{0, 1, 63};
     EXPECT_THAT(set.data(),
                 ElementsAre((1ULL << 0) | (1ULL << 1) | (1ULL << 63)));
   }
@@ -121,19 +121,20 @@
 
 TEST(DenseSetTest, iterators_begin_end) {
   enum class T : int {
-    One = 1,
-    Two = 2,
-    Three = 3,
-    Four = 4,
-    Five = 5,
-    kMaxValue = Five,
+    kMinusOne = -1,
+    kOne = 1,
+    kTwo = 2,
+    kThree = 3,
+    kFour = 4,
+    kFive = 5,
+    kMaxValue = kFive,
   };
-  using DS = DenseSet<T, T::kMaxValue>;
+  using DS = DenseSet<T, T::kMinusOne, T::kMaxValue>;
 
   DS s;
-  s.insert(T::Two);
-  s.insert(T::Four);
-  s.insert(T::One);
+  s.insert(T::kTwo);
+  s.insert(T::kFour);
+  s.insert(T::kOne);
   EXPECT_EQ(s.size(), 3u);
   EXPECT_EQ(std::distance(s.begin(), s.end()), 3);
 
@@ -143,9 +144,9 @@
     auto x2 = *it++;
     auto x3 = *it++;
     EXPECT_EQ(it, s.end());
-    EXPECT_EQ(x1, T::One);
-    EXPECT_EQ(x2, T::Two);
-    EXPECT_EQ(x3, T::Four);
+    EXPECT_EQ(x1, T::kOne);
+    EXPECT_EQ(x2, T::kTwo);
+    EXPECT_EQ(x3, T::kFour);
   }
 
   {
@@ -154,29 +155,30 @@
     auto x2 = *++it;
     auto x3 = *++it;
     EXPECT_NE(it, s.end());
-    EXPECT_EQ(x1, T::One);
-    EXPECT_EQ(x2, T::Two);
-    EXPECT_EQ(x3, T::Four);
+    EXPECT_EQ(x1, T::kOne);
+    EXPECT_EQ(x2, T::kTwo);
+    EXPECT_EQ(x3, T::kFour);
   }
 
-  EXPECT_THAT(s, ::testing::ElementsAre(T::One, T::Two, T::Four));
+  EXPECT_THAT(s, ::testing::ElementsAre(T::kOne, T::kTwo, T::kFour));
 }
 
 TEST(DenseSetTest, iterators_begin_end_reverse) {
-  enum class T : char {
-    One = 1,
-    Two = 2,
-    Three = 3,
-    Four = 4,
-    Five = 5,
-    kMaxValue = Five,
+  enum class T : int8_t {
+    kMinusOne = -1,
+    kOne = 1,
+    kTwo = 2,
+    kThree = 3,
+    kFour = 4,
+    kFive = 5,
+    kMaxValue = kFive
   };
-  using DS = DenseSet<T, T::kMaxValue>;
+  using DS = DenseSet<T, T::kMinusOne, T::kMaxValue>;
 
   DS s;
-  s.insert(T::Two);
-  s.insert(T::Four);
-  s.insert(T::One);
+  s.insert(T::kTwo);
+  s.insert(T::kFour);
+  s.insert(T::kOne);
   EXPECT_EQ(s.size(), 3u);
 
   {
@@ -186,9 +188,9 @@
     auto x2 = *it--;
     auto x1 = *it;
     EXPECT_EQ(it, s.begin());
-    EXPECT_EQ(x1, T::One);
-    EXPECT_EQ(x2, T::Two);
-    EXPECT_EQ(x3, T::Four);
+    EXPECT_EQ(x1, T::kOne);
+    EXPECT_EQ(x2, T::kTwo);
+    EXPECT_EQ(x3, T::kFour);
   }
 
   {
@@ -197,27 +199,28 @@
     auto x2 = *--it;
     auto x1 = *--it;
     EXPECT_EQ(it, s.begin());
-    EXPECT_EQ(x1, T::One);
-    EXPECT_EQ(x2, T::Two);
-    EXPECT_EQ(x3, T::Four);
+    EXPECT_EQ(x1, T::kOne);
+    EXPECT_EQ(x2, T::kTwo);
+    EXPECT_EQ(x3, T::kFour);
   }
 }
 
 TEST(DenseSetTest, iterators_rbegin_rend) {
   enum class T {
-    One = 1,
-    Two = 2,
-    Three = 3,
-    Four = 4,
-    Five = 5,
-    kMaxValue = Five
+    kMinusOne = -1,
+    kOne = 1,
+    kTwo = 2,
+    kThree = 3,
+    kFour = 4,
+    kFive = 5,
+    kMaxValue = kFive
   };
-  using DS = DenseSet<T, T::kMaxValue>;
+  using DS = DenseSet<T, T::kMinusOne, T::kMaxValue>;
 
   DS s;
-  s.insert(T::Two);
-  s.insert(T::Four);
-  s.insert(T::One);
+  s.insert(T::kTwo);
+  s.insert(T::kFour);
+  s.insert(T::kOne);
   EXPECT_EQ(s.size(), 3u);
   EXPECT_EQ(std::distance(s.rbegin(), s.rend()), 3);
 
@@ -227,9 +230,9 @@
     auto x2 = *it++;
     auto x1 = *it++;
     EXPECT_EQ(it, s.rend());
-    EXPECT_EQ(x1, T::One);
-    EXPECT_EQ(x2, T::Two);
-    EXPECT_EQ(x3, T::Four);
+    EXPECT_EQ(x1, T::kOne);
+    EXPECT_EQ(x2, T::kTwo);
+    EXPECT_EQ(x3, T::kFour);
   }
 
   {
@@ -238,62 +241,63 @@
     auto x2 = *++it;
     auto x1 = *++it;
     EXPECT_NE(it, s.rend());
-    EXPECT_EQ(x1, T::One);
-    EXPECT_EQ(x2, T::Two);
-    EXPECT_EQ(x3, T::Four);
+    EXPECT_EQ(x1, T::kOne);
+    EXPECT_EQ(x2, T::kTwo);
+    EXPECT_EQ(x3, T::kFour);
   }
 
   EXPECT_THAT(std::vector<T>(s.rbegin(), s.rend()),
-              ::testing::ElementsAre(T::Four, T::Two, T::One));
+              ::testing::ElementsAre(T::kFour, T::kTwo, T::kOne));
 }
 
 TEST(DenseSetTest, lookup) {
   enum class T {
-    One = 1,
-    Two = 2,
-    Three = 3,
-    Four = 4,
-    Five = 5,
-    kMaxValue = Five
+    kMinusOne = -1,
+    kOne = 1,
+    kTwo = 2,
+    kThree = 3,
+    kFour = 4,
+    kFive = 5,
+    kMaxValue = kFive
   };
-  using DS = DenseSet<T, T::kMaxValue>;
+  using DS = DenseSet<T, T::kMinusOne, T::kMaxValue>;
 
   DS s;
-  s.insert(T::Two);
-  s.insert(T::Four);
-  s.insert(T::One);
+  s.insert(T::kTwo);
+  s.insert(T::kFour);
+  s.insert(T::kOne);
 
   EXPECT_FALSE(s.contains(static_cast<T>(0)));
-  EXPECT_TRUE(s.contains(T::One));
-  EXPECT_TRUE(s.contains(T::Two));
-  EXPECT_FALSE(s.contains(T::Three));
-  EXPECT_TRUE(s.contains(T::Four));
-  EXPECT_FALSE(s.contains(T::Five));
+  EXPECT_TRUE(s.contains(T::kOne));
+  EXPECT_TRUE(s.contains(T::kTwo));
+  EXPECT_FALSE(s.contains(T::kThree));
+  EXPECT_TRUE(s.contains(T::kFour));
+  EXPECT_FALSE(s.contains(T::kFive));
 
   EXPECT_EQ(s.contains(static_cast<T>(0)), 0u);
-  EXPECT_EQ(s.contains(T::One), 1u);
-  EXPECT_EQ(s.contains(T::Two), 1u);
-  EXPECT_EQ(s.contains(T::Three), 0u);
-  EXPECT_EQ(s.contains(T::Four), 1u);
-  EXPECT_EQ(s.contains(T::Five), 0u);
+  EXPECT_EQ(s.contains(T::kOne), 1u);
+  EXPECT_EQ(s.contains(T::kTwo), 1u);
+  EXPECT_EQ(s.contains(T::kThree), 0u);
+  EXPECT_EQ(s.contains(T::kFour), 1u);
+  EXPECT_EQ(s.contains(T::kFive), 0u);
 
   EXPECT_EQ(s.find(static_cast<T>(0)), s.end());
-  EXPECT_NE(s.find(T::One), s.end());
-  EXPECT_NE(s.find(T::Two), s.end());
-  EXPECT_EQ(s.find(T::Three), s.end());
-  EXPECT_NE(s.find(T::Four), s.end());
-  EXPECT_EQ(s.find(T::Five), s.end());
+  EXPECT_NE(s.find(T::kOne), s.end());
+  EXPECT_NE(s.find(T::kTwo), s.end());
+  EXPECT_EQ(s.find(T::kThree), s.end());
+  EXPECT_NE(s.find(T::kFour), s.end());
+  EXPECT_EQ(s.find(T::kFive), s.end());
 
-  EXPECT_EQ(*s.find(T::One), T::One);
-  EXPECT_EQ(*s.find(T::Two), T::Two);
-  EXPECT_EQ(*s.find(T::Four), T::Four);
+  EXPECT_EQ(*s.find(T::kOne), T::kOne);
+  EXPECT_EQ(*s.find(T::kTwo), T::kTwo);
+  EXPECT_EQ(*s.find(T::kFour), T::kFour);
 
   EXPECT_NE(s.find(static_cast<T>(0)), s.lower_bound(static_cast<T>(0)));
-  EXPECT_EQ(s.find(T::One), s.lower_bound(T::One));
-  EXPECT_EQ(s.find(T::Two), s.lower_bound(T::Two));
-  EXPECT_NE(s.find(T::Three), s.lower_bound(T::Three));
-  EXPECT_EQ(s.find(T::Four), s.lower_bound(T::Four));
-  EXPECT_EQ(s.find(T::Five), s.lower_bound(T::Five));
+  EXPECT_EQ(s.find(T::kOne), s.lower_bound(T::kOne));
+  EXPECT_EQ(s.find(T::kTwo), s.lower_bound(T::kTwo));
+  EXPECT_NE(s.find(T::kThree), s.lower_bound(T::kThree));
+  EXPECT_EQ(s.find(T::kFour), s.lower_bound(T::kFour));
+  EXPECT_EQ(s.find(T::kFive), s.lower_bound(T::kFive));
 
   DS t;
   EXPECT_TRUE(t.empty());
@@ -323,20 +327,27 @@
 }
 
 TEST(DenseSetTest, iterators_lower_upper_bound) {
-  enum class T { One = 1, Two = 2, Three = 3, Four = 4, Five = 5 };
-  using DS = DenseSet<T, T::Five>;
+  enum class T {
+    kMinusOne = -1,
+    kOne = 1,
+    kTwo = 2,
+    kThree = 3,
+    kFour = 4,
+    kFive = 5
+  };
+  using DS = DenseSet<T, T::kMinusOne, T::kFive>;
 
   DS s;
-  s.insert(T::Two);
-  s.insert(T::Four);
-  s.insert(T::One);
+  s.insert(T::kTwo);
+  s.insert(T::kFour);
+  s.insert(T::kOne);
   EXPECT_EQ(s.size(), 3u);
 
   EXPECT_EQ(s.lower_bound(static_cast<T>(0)), s.begin());
-  EXPECT_EQ(s.lower_bound(T::One), s.begin());
+  EXPECT_EQ(s.lower_bound(T::kOne), s.begin());
 
-  EXPECT_EQ(s.upper_bound(T::Four), s.end());
-  EXPECT_EQ(s.upper_bound(T::Five), s.end());
+  EXPECT_EQ(s.upper_bound(T::kFour), s.end());
+  EXPECT_EQ(s.upper_bound(T::kFive), s.end());
 
   {
     auto it = s.lower_bound(static_cast<T>(0));
@@ -345,46 +356,46 @@
   }
 
   {
-    auto it = s.lower_bound(T::One);
-    auto jt = s.upper_bound(T::One);
+    auto it = s.lower_bound(T::kOne);
+    auto jt = s.upper_bound(T::kOne);
     auto x1 = *it++;
     EXPECT_EQ(it, jt);
-    EXPECT_EQ(x1, T::One);
+    EXPECT_EQ(x1, T::kOne);
   }
 
   {
-    auto it = s.lower_bound(T::Four);
-    auto jt = s.upper_bound(T::Four);
+    auto it = s.lower_bound(T::kFour);
+    auto jt = s.upper_bound(T::kFour);
     auto x3 = *it++;
     EXPECT_EQ(it, jt);
-    EXPECT_EQ(x3, T::Four);
+    EXPECT_EQ(x3, T::kFour);
   }
 
   {
-    auto it = s.lower_bound(T::Five);
-    auto jt = s.upper_bound(T::Five);
+    auto it = s.lower_bound(T::kFive);
+    auto jt = s.upper_bound(T::kFive);
     EXPECT_EQ(it, jt);
   }
 
   {
-    auto it = s.lower_bound(T::One);
-    auto jt = s.upper_bound(T::Five);
+    auto it = s.lower_bound(T::kOne);
+    auto jt = s.upper_bound(T::kFive);
     auto x1 = *it++;
     auto x2 = *it++;
     auto x3 = *it++;
     EXPECT_EQ(it, jt);
-    EXPECT_EQ(x1, T::One);
-    EXPECT_EQ(x2, T::Two);
-    EXPECT_EQ(x3, T::Four);
+    EXPECT_EQ(x1, T::kOne);
+    EXPECT_EQ(x2, T::kTwo);
+    EXPECT_EQ(x3, T::kFour);
   }
 
   {
-    auto it = s.lower_bound(T::Three);
-    auto jt = s.upper_bound(T::Four);
+    auto it = s.lower_bound(T::kThree);
+    auto jt = s.upper_bound(T::kFour);
     auto x3 = *it++;
     EXPECT_EQ(jt, s.end());
     EXPECT_EQ(it, jt);
-    EXPECT_EQ(x3, T::Four);
+    EXPECT_EQ(x3, T::kFour);
   }
 
   EXPECT_EQ(static_cast<size_t>(std::distance(s.begin(), s.end())), s.size());
@@ -392,43 +403,43 @@
 }
 
 TEST(DenseSetTest, max_size) {
-  const int One = 1;
-  const int Two = 2;
-  // const int Three = 3;
-  const int Four = 4;
-  // const int Five = 5;
+  const int kOne = 1;
+  const int kTwo = 2;
+  // const int kThree = 3;
+  const int kFour = 4;
+  // const int kFive = 5;
   const int kMaxValue = 5;
-  using DS = DenseSet<int, kMaxValue>;
+  using DS = DenseSet<int, 0, kMaxValue>;
 
   DS s;
   EXPECT_TRUE(s.empty());
   EXPECT_EQ(s.size(), 0u);
   EXPECT_EQ(s.max_size(), 6u);
-  s.insert(Two);
+  s.insert(kTwo);
   EXPECT_FALSE(s.empty());
   EXPECT_EQ(s.size(), 1u);
-  s.insert(Four);
+  s.insert(kFour);
   EXPECT_FALSE(s.empty());
   EXPECT_EQ(s.size(), 2u);
-  s.insert(One);
+  s.insert(kOne);
   EXPECT_FALSE(s.empty());
   EXPECT_EQ(s.size(), 3u);
   EXPECT_EQ(s.max_size(), 6u);
 }
 
 TEST(DenseSetTest, modifiers) {
-  const size_t One = 1;
-  const size_t Two = 2;
-  const size_t Three = 3;
-  const size_t Four = 4;
-  // const size_t Five = 5;
+  const size_t kOne = 1;
+  const size_t kTwo = 2;
+  const size_t kThree = 3;
+  const size_t kFour = 4;
+  // const size_t kFive = 5;
   const size_t kMaxValue = 5;
-  using DS = DenseSet<size_t, kMaxValue>;
+  using DS = DenseSet<size_t, 0, kMaxValue>;
 
   DS s;
-  s.insert(Two);
-  s.insert(Four);
-  s.insert(One);
+  s.insert(kTwo);
+  s.insert(kFour);
+  s.insert(kOne);
   EXPECT_EQ(s.size(), 3u);
 
   auto EXPECT_INSERTION = [](auto& set, auto value, bool took_place) {
@@ -438,58 +449,58 @@
 
   DS t;
   EXPECT_NE(s, t);
-  EXPECT_INSERTION(t, Two, true);
-  EXPECT_INSERTION(t, Two, false);
-  EXPECT_INSERTION(t, Four, true);
-  EXPECT_INSERTION(t, Four, false);
-  EXPECT_INSERTION(t, One, true);
-  EXPECT_INSERTION(t, One, false);
+  EXPECT_INSERTION(t, kTwo, true);
+  EXPECT_INSERTION(t, kTwo, false);
+  EXPECT_INSERTION(t, kFour, true);
+  EXPECT_INSERTION(t, kFour, false);
+  EXPECT_INSERTION(t, kOne, true);
+  EXPECT_INSERTION(t, kOne, false);
   EXPECT_EQ(s, t);
   EXPECT_EQ(t.size(), 3u);
 
-  EXPECT_INSERTION(t, Three, true);
-  EXPECT_INSERTION(t, Three, false);
-  EXPECT_EQ(t.erase(Three), 1u);
-  EXPECT_EQ(t.erase(Three), 0u);
+  EXPECT_INSERTION(t, kThree, true);
+  EXPECT_INSERTION(t, kThree, false);
+  EXPECT_EQ(t.erase(kThree), 1u);
+  EXPECT_EQ(t.erase(kThree), 0u);
   EXPECT_EQ(s, t);
   EXPECT_EQ(t.size(), 3u);
 
-  EXPECT_EQ(s.erase(One), 1u);
-  EXPECT_EQ(t.erase(Four), 1u);
+  EXPECT_EQ(s.erase(kOne), 1u);
+  EXPECT_EQ(t.erase(kFour), 1u);
   EXPECT_NE(s, t);
   EXPECT_EQ(s.size(), 2u);
   EXPECT_EQ(t.size(), 2u);
 
-  EXPECT_INSERTION(s, One, true);
-  EXPECT_INSERTION(t, Four, true);
+  EXPECT_INSERTION(s, kOne, true);
+  EXPECT_INSERTION(t, kFour, true);
   EXPECT_EQ(s, t);
   EXPECT_EQ(s.size(), 3u);
   EXPECT_EQ(t.size(), 3u);
 
-  EXPECT_EQ(s.erase(s.find(One)), s.find(Two));
-  EXPECT_EQ(t.erase(t.lower_bound(One), t.upper_bound(One)), t.find(Two));
-  EXPECT_FALSE(s.contains(One));
+  EXPECT_EQ(s.erase(s.find(kOne)), s.find(kTwo));
+  EXPECT_EQ(t.erase(t.lower_bound(kOne), t.upper_bound(kOne)), t.find(kTwo));
+  EXPECT_FALSE(s.contains(kOne));
   EXPECT_EQ(s, t);
   EXPECT_EQ(s.size(), 2u);
   EXPECT_EQ(t.size(), 2u);
 
-  EXPECT_INSERTION(s, One, true);
-  EXPECT_INSERTION(t, One, true);
+  EXPECT_INSERTION(s, kOne, true);
+  EXPECT_INSERTION(t, kOne, true);
   EXPECT_EQ(s, t);
   EXPECT_EQ(s.size(), 3u);
   EXPECT_EQ(t.size(), 3u);
 
-  EXPECT_EQ(s.erase(s.find(Two), s.end()), s.end());
-  EXPECT_EQ(t.erase(t.lower_bound(Two), t.upper_bound(Four)), t.end());
-  EXPECT_TRUE(s.contains(One));
+  EXPECT_EQ(s.erase(s.find(kTwo), s.end()), s.end());
+  EXPECT_EQ(t.erase(t.lower_bound(kTwo), t.upper_bound(kFour)), t.end());
+  EXPECT_TRUE(s.contains(kOne));
   EXPECT_EQ(s, t);
   EXPECT_EQ(s.size(), 1u);
   EXPECT_EQ(t.size(), 1u);
 
-  EXPECT_INSERTION(s, Two, true);
-  EXPECT_INSERTION(t, Two, true);
-  EXPECT_INSERTION(s, Four, true);
-  EXPECT_INSERTION(t, Four, true);
+  EXPECT_INSERTION(s, kTwo, true);
+  EXPECT_INSERTION(t, kTwo, true);
+  EXPECT_INSERTION(s, kFour, true);
+  EXPECT_INSERTION(t, kFour, true);
   EXPECT_EQ(s, t);
   EXPECT_EQ(s.size(), 3u);
   EXPECT_EQ(t.size(), 3u);
@@ -498,7 +509,7 @@
   EXPECT_EQ(s, DS());
   EXPECT_TRUE(s.empty());
 
-  s.insert(Three);
+  s.insert(kThree);
   s.insert_all(t);
   EXPECT_EQ(s.size(), 4u);
   EXPECT_EQ(t.size(), 3u);
@@ -506,20 +517,20 @@
   EXPECT_FALSE(s.contains_none(t));
   EXPECT_TRUE(s.contains_any(t));
   EXPECT_TRUE(s.contains_all(t));
-  EXPECT_TRUE(s.contains(Three));
+  EXPECT_TRUE(s.contains(kThree));
   EXPECT_FALSE(t.contains_none(s));
   EXPECT_TRUE(t.contains_any(s));
   EXPECT_FALSE(t.contains_all(s));
 
   s.erase_all(t);
   EXPECT_EQ(s.size(), 1u);
-  EXPECT_TRUE(s.contains(Three));
+  EXPECT_TRUE(s.contains(kThree));
   EXPECT_TRUE(s.contains_none(t));
   EXPECT_FALSE(s.contains_any(t));
   EXPECT_FALSE(s.contains_all(t));
 
   s.insert_all(t);
-  s.erase(Three);
+  s.erase(kThree);
   EXPECT_EQ(s.size(), 3u);
   EXPECT_EQ(s, t);
 
@@ -527,11 +538,11 @@
   EXPECT_TRUE(s.empty());
 
   EXPECT_INSERTION(s, *t.begin(), true);
-  EXPECT_TRUE(s.contains(One));
+  EXPECT_TRUE(s.contains(kOne));
   EXPECT_INSERTION(s, *std::next(t.begin()), true);
-  EXPECT_TRUE(s.contains(Two));
+  EXPECT_TRUE(s.contains(kTwo));
   EXPECT_INSERTION(s, *std::prev(t.end()), true);
-  EXPECT_TRUE(s.contains(Four));
+  EXPECT_TRUE(s.contains(kFour));
   EXPECT_EQ(s, t);
   EXPECT_EQ(s.size(), 3u);
   EXPECT_EQ(t.size(), 3u);
@@ -539,7 +550,7 @@
 
 TEST(DenseSetTest, std_set) {
   constexpr size_t kMaxValue = 50;
-  DenseSet<size_t, kMaxValue> dense_set;
+  DenseSet<size_t, 0, kMaxValue> dense_set;
   std::set<size_t> std_set;
 
   auto expect_equivalence = [&] {
diff --git a/components/bookmarks/browser/bookmark_model.h b/components/bookmarks/browser/bookmark_model.h
index 8258c2b..183c033 100644
--- a/components/bookmarks/browser/bookmark_model.h
+++ b/components/bookmarks/browser/bookmark_model.h
@@ -483,12 +483,12 @@
   // |owned_root_|. Once loading has completed, |owned_root_| is destroyed and
   // this is set to url_index_->root(). |owned_root_| is done as lots of
   // existing code assumes the root is non-null while loading.
-  raw_ptr<BookmarkNode, DanglingUntriaged> root_ = nullptr;
+  raw_ptr<BookmarkNode, DanglingAcrossTasks> root_ = nullptr;
 
-  raw_ptr<BookmarkPermanentNode, DanglingUntriaged> bookmark_bar_node_ =
+  raw_ptr<BookmarkPermanentNode, DanglingAcrossTasks> bookmark_bar_node_ =
       nullptr;
-  raw_ptr<BookmarkPermanentNode, DanglingUntriaged> other_node_ = nullptr;
-  raw_ptr<BookmarkPermanentNode, DanglingUntriaged> mobile_node_ = nullptr;
+  raw_ptr<BookmarkPermanentNode, DanglingAcrossTasks> other_node_ = nullptr;
+  raw_ptr<BookmarkPermanentNode, DanglingAcrossTasks> mobile_node_ = nullptr;
 
   // The maximum ID assigned to the bookmark nodes in the model.
   int64_t next_node_id_ = 1;
diff --git a/components/component_updater/installer_policies/BUILD.gn b/components/component_updater/installer_policies/BUILD.gn
index 983e308..39fb776 100644
--- a/components/component_updater/installer_policies/BUILD.gn
+++ b/components/component_updater/installer_policies/BUILD.gn
@@ -18,8 +18,8 @@
     "autofill_states_component_installer.h",
     "client_side_phishing_component_installer_policy.cc",
     "client_side_phishing_component_installer_policy.h",
-    "masked_domain_list_component_installer.cc",
-    "masked_domain_list_component_installer.h",
+    "masked_domain_list_component_installer_policy.cc",
+    "masked_domain_list_component_installer_policy.h",
     "origin_trials_component_installer.cc",
     "origin_trials_component_installer.h",
     "safety_tips_component_installer.cc",
@@ -63,7 +63,7 @@
   testonly = true
   sources = [
     "autofill_states_component_installer_unittest.cc",
-    "masked_domain_list_component_installer_unittest.cc",
+    "masked_domain_list_component_installer_policy_unittest.cc",
     "optimization_hints_component_installer_unittest.cc",
     "trust_token_key_commitments_component_installer_policy_unittest.cc",
   ]
diff --git a/components/component_updater/installer_policies/masked_domain_list_component_installer.cc b/components/component_updater/installer_policies/masked_domain_list_component_installer_policy.cc
similarity index 75%
rename from components/component_updater/installer_policies/masked_domain_list_component_installer.cc
rename to components/component_updater/installer_policies/masked_domain_list_component_installer_policy.cc
index 888d181..34b3c3d 100644
--- a/components/component_updater/installer_policies/masked_domain_list_component_installer.cc
+++ b/components/component_updater/installer_policies/masked_domain_list_component_installer_policy.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/component_updater/installer_policies/masked_domain_list_component_installer.h"
+#include "components/component_updater/installer_policies/masked_domain_list_component_installer_policy.h"
 
 #include <utility>
 
@@ -13,12 +13,10 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
 #include "base/logging.h"
-#include "base/no_destructor.h"
 #include "base/task/thread_pool.h"
 #include "base/version.h"
 #include "components/component_updater/component_installer.h"
 #include "services/network/public/cpp/features.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
 
 using component_updater::ComponentUpdateService;
 
@@ -28,7 +26,7 @@
     MaskedDomainListComponentInstallerPolicy::ListReadyRepeatingCallback;
 
 constexpr base::FilePath::CharType kMaskedDomainListFileName[] =
-    FILE_PATH_LITERAL("list.json");
+    FILE_PATH_LITERAL("list.pb");
 
 // The SHA256 of the SubjectPublicKeyInfo used to sign the extension.
 // The extension id is: cffplpkejcbdpfnfabnjikeicbedmifn
@@ -42,18 +40,12 @@
 constexpr base::FilePath::CharType kMaskedDomainListRelativeInstallDir[] =
     FILE_PATH_LITERAL("MaskedDomainListPreloaded");
 
-base::File OpenFile(const base::FilePath& pb_path) {
-  return base::File(pb_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
-}
-
-bool IsMaskedDomainListEnabled() {
-  // TODO(aakallam): move this to a more accessible location.
-  return base::FeatureList::IsEnabled(network::features::kMaskedDomainList);
-}
-
-base::TaskPriority GetTaskPriority() {
-  return IsMaskedDomainListEnabled() ? base::TaskPriority::USER_BLOCKING
-                                     : base::TaskPriority::BEST_EFFORT;
+std::string ReadFile(const base::FilePath& pb_path) {
+  std::string raw_list;
+  base::ScopedFILE file(FileToFILE(
+      base::File(pb_path, base::File::FLAG_OPEN | base::File::FLAG_READ), "r"));
+  CHECK(base::ReadStreamToString(file.get(), &raw_list));
+  return raw_list;
 }
 
 }  // namespace
@@ -75,6 +67,10 @@
   return true;
 }
 
+bool MaskedDomainListComponentInstallerPolicy::IsEnabled() {
+  return base::FeatureList::IsEnabled(network::features::kMaskedDomainList);
+}
+
 bool MaskedDomainListComponentInstallerPolicy::RequiresNetworkEncryption()
     const {
   // Update checks and pings associated with this component do not require
@@ -100,7 +96,7 @@
     const base::Version& version,
     const base::FilePath& install_dir,
     base::Value::Dict manifest) {
-  if (install_dir.empty() || !IsMaskedDomainListEnabled()) {
+  if (install_dir.empty() || !IsEnabled()) {
     return;
   }
 
@@ -108,8 +104,8 @@
           << version.GetString() << " in " << install_dir.value();
 
   base::ThreadPool::PostTaskAndReplyWithResult(
-      FROM_HERE, {base::MayBlock(), GetTaskPriority()},
-      base::BindOnce(&OpenFile, GetInstalledPath(install_dir)),
+      FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING},
+      base::BindOnce(&ReadFile, GetInstalledPath(install_dir)),
       base::BindOnce(on_list_ready_, version));
 }
 
@@ -142,22 +138,4 @@
   return update_client::InstallerAttributes();
 }
 
-void RegisterMaskedDomainListComponent(ComponentUpdateService* cus) {
-  if (!IsMaskedDomainListEnabled()) {
-    return;
-  }
-
-  VLOG(1) << "Registering Masked Domain List component.";
-
-  auto policy = std::make_unique<MaskedDomainListComponentInstallerPolicy>(
-      /*on_list_ready=*/base::BindRepeating(
-          [](base::Version version, base::File list_file) {
-            VLOG(1) << "Received Masked Domain List";
-            // TODO(aakallam): do something with the file
-          }));
-
-  base::MakeRefCounted<ComponentInstaller>(std::move(policy))
-      ->Register(cus, base::OnceClosure(), GetTaskPriority());
-}
-
 }  // namespace component_updater
diff --git a/components/component_updater/installer_policies/masked_domain_list_component_installer.h b/components/component_updater/installer_policies/masked_domain_list_component_installer_policy.h
similarity index 84%
rename from components/component_updater/installer_policies/masked_domain_list_component_installer.h
rename to components/component_updater/installer_policies/masked_domain_list_component_installer_policy.h
index b64d854..0ff4a3fb 100644
--- a/components/component_updater/installer_policies/masked_domain_list_component_installer.h
+++ b/components/component_updater/installer_policies/masked_domain_list_component_installer_policy.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_COMPONENT_UPDATER_INSTALLER_POLICIES_MASKED_DOMAIN_LIST_COMPONENT_INSTALLER_H_
-#define COMPONENTS_COMPONENT_UPDATER_INSTALLER_POLICIES_MASKED_DOMAIN_LIST_COMPONENT_INSTALLER_H_
+#ifndef COMPONENTS_COMPONENT_UPDATER_INSTALLER_POLICIES_MASKED_DOMAIN_LIST_COMPONENT_INSTALLER_POLICY_H_
+#define COMPONENTS_COMPONENT_UPDATER_INSTALLER_POLICIES_MASKED_DOMAIN_LIST_COMPONENT_INSTALLER_POLICY_H_
 
 #include <stdint.h>
 
@@ -32,7 +32,7 @@
     : public ComponentInstallerPolicy {
  public:
   using ListReadyRepeatingCallback =
-      base::RepeatingCallback<void(base::Version, base::File)>;
+      base::RepeatingCallback<void(base::Version, std::string)>;
 
   // |on_list_ready| will be called on the UI thread when the list is ready. It
   // is exposed here for testing.
@@ -45,14 +45,18 @@
   MaskedDomainListComponentInstallerPolicy operator=(
       const MaskedDomainListComponentInstallerPolicy&) = delete;
 
+  static bool IsEnabled();
+
+  static base::FilePath GetInstalledPath(const base::FilePath& base);
+
  private:
-  FRIEND_TEST_ALL_PREFIXES(MaskedDomainListComponentInstallerTest,
+  FRIEND_TEST_ALL_PREFIXES(MaskedDomainListComponentInstallerPolicyTest,
                            NonexistentFile);
-  FRIEND_TEST_ALL_PREFIXES(MaskedDomainListComponentInstallerTest,
+  FRIEND_TEST_ALL_PREFIXES(MaskedDomainListComponentInstallerPolicyTest,
                            NonexistentFile_OnComponentReady);
-  FRIEND_TEST_ALL_PREFIXES(MaskedDomainListComponentInstallerTest,
+  FRIEND_TEST_ALL_PREFIXES(MaskedDomainListComponentInstallerPolicyTest,
                            LoadsFile_OnComponentReady);
-  FRIEND_TEST_ALL_PREFIXES(MaskedDomainListComponentInstallerTest,
+  FRIEND_TEST_ALL_PREFIXES(MaskedDomainListComponentInstallerPolicyTest,
                            LoadsNewListWhenUpdated);
 
   // The following methods override ComponentInstallerPolicy.
@@ -72,8 +76,6 @@
   std::string GetName() const override;
   update_client::InstallerAttributes GetInstallerAttributes() const override;
 
-  static base::FilePath GetInstalledPath(const base::FilePath& base);
-
   ListReadyRepeatingCallback on_list_ready_;
 };
 
@@ -83,4 +85,4 @@
 
 }  // namespace component_updater
 
-#endif  // COMPONENTS_COMPONENT_UPDATER_INSTALLER_POLICIES_MASKED_DOMAIN_LIST_COMPONENT_INSTALLER_H_
+#endif  // COMPONENTS_COMPONENT_UPDATER_INSTALLER_POLICIES_MASKED_DOMAIN_LIST_COMPONENT_INSTALLER_POLICY_H_
diff --git a/components/component_updater/installer_policies/masked_domain_list_component_installer_policy_unittest.cc b/components/component_updater/installer_policies/masked_domain_list_component_installer_policy_unittest.cc
new file mode 100644
index 0000000..a2e46848
--- /dev/null
+++ b/components/component_updater/installer_policies/masked_domain_list_component_installer_policy_unittest.cc
@@ -0,0 +1,108 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/component_updater/installer_policies/masked_domain_list_component_installer_policy.h"
+
+#include "base/check.h"
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/logging.h"
+#include "base/test/repeating_test_future.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "base/version.h"
+#include "components/component_updater/mock_component_updater_service.h"
+#include "services/network/public/cpp/features.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace component_updater {
+
+namespace {
+using ::testing::_;
+
+}  // namespace
+
+class MaskedDomainListComponentInstallerPolicyTest : public ::testing::Test {
+ public:
+  MaskedDomainListComponentInstallerPolicyTest() {
+    CHECK(component_install_dir_.CreateUniqueTempDir());
+  }
+
+ protected:
+  base::test::TaskEnvironment env_;
+  base::test::ScopedFeatureList scoped_feature_list_;
+
+  base::ScopedTempDir component_install_dir_;
+};
+
+TEST_F(MaskedDomainListComponentInstallerPolicyTest,
+       LoadsFile_OnComponentReady) {
+  scoped_feature_list_.InitAndEnableFeature(
+      network::features::kMaskedDomainList);
+  const base::Version version = base::Version("0.0.1");
+  const std::string expectation = "some list contents";
+  base::test::RepeatingTestFuture<base::Version, std::string> future;
+  auto policy = MaskedDomainListComponentInstallerPolicy(future.GetCallback());
+
+  ASSERT_TRUE(base::WriteFile(
+      MaskedDomainListComponentInstallerPolicy::GetInstalledPath(
+          component_install_dir_.GetPath()),
+      expectation));
+
+  policy.ComponentReady(version, component_install_dir_.GetPath(),
+                        base::Value::Dict());
+
+  std::tuple<base::Version, std::string> got = future.Take();
+  EXPECT_TRUE(std::get<0>(got).IsValid());
+  EXPECT_EQ(std::get<0>(got), version);
+  EXPECT_EQ(std::get<1>(got), expectation);
+}
+
+TEST_F(MaskedDomainListComponentInstallerPolicyTest, LoadsNewListWhenUpdated) {
+  scoped_feature_list_.InitAndEnableFeature(
+      network::features::kMaskedDomainList);
+
+  base::test::RepeatingTestFuture<base::Version, std::string> future;
+  auto policy = MaskedDomainListComponentInstallerPolicy(future.GetCallback());
+
+  const base::Version version1 = base::Version("0.0.1");
+  const std::string list_v1 = "MDL v1";
+  base::ScopedTempDir dir_v1;
+  ASSERT_TRUE(
+      dir_v1.CreateUniqueTempDirUnderPath(component_install_dir_.GetPath()));
+  ASSERT_TRUE(base::WriteFile(
+      MaskedDomainListComponentInstallerPolicy::GetInstalledPath(
+          dir_v1.GetPath()),
+      list_v1));
+  policy.ComponentReady(version1, dir_v1.GetPath(), base::Value::Dict());
+
+  std::tuple<base::Version, std::string> got = future.Take();
+  EXPECT_TRUE(std::get<0>(got).IsValid());
+  EXPECT_EQ(std::get<0>(got), version1);
+  EXPECT_EQ(std::get<1>(got), list_v1);
+
+  // Install newer version of the component, which should be picked up
+  // when calling ComponentReady again.
+  const base::Version version2 = base::Version("0.0.2");
+  const std::string list_v2 = "MDL v2";
+  base::ScopedTempDir dir_v2;
+  ASSERT_TRUE(
+      dir_v2.CreateUniqueTempDirUnderPath(component_install_dir_.GetPath()));
+  ASSERT_TRUE(base::WriteFile(
+      MaskedDomainListComponentInstallerPolicy::GetInstalledPath(
+          dir_v2.GetPath()),
+      list_v2));
+  policy.ComponentReady(version2, dir_v2.GetPath(), base::Value::Dict());
+
+  std::tuple<base::Version, std::string> got2 = future.Take();
+  EXPECT_TRUE(std::get<0>(got2).IsValid());
+  EXPECT_EQ(std::get<0>(got2), version2);
+  EXPECT_EQ(std::get<1>(got2), list_v2);
+
+  env_.RunUntilIdle();
+}
+
+}  // namespace component_updater
diff --git a/components/component_updater/installer_policies/masked_domain_list_component_installer_unittest.cc b/components/component_updater/installer_policies/masked_domain_list_component_installer_unittest.cc
deleted file mode 100644
index a2fdf9b1..0000000
--- a/components/component_updater/installer_policies/masked_domain_list_component_installer_unittest.cc
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/component_updater/installer_policies/masked_domain_list_component_installer.h"
-
-#include "base/check.h"
-#include "base/files/file.h"
-#include "base/files/file_util.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/logging.h"
-#include "base/test/repeating_test_future.h"
-#include "base/test/scoped_feature_list.h"
-#include "base/test/task_environment.h"
-#include "base/version.h"
-#include "components/component_updater/mock_component_updater_service.h"
-#include "services/network/public/cpp/features.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace component_updater {
-
-namespace {
-using ::testing::_;
-
-std::string ReadToString(base::File file) {
-  std::string contents;
-  base::ScopedFILE scoped_file(base::FileToFILE(std::move(file), "r"));
-  return base::ReadStreamToString(scoped_file.get(), &contents) ? contents : "";
-}
-
-}  // namespace
-
-class MaskedDomainListComponentInstallerTest : public ::testing::Test {
- public:
-  MaskedDomainListComponentInstallerTest() {
-    CHECK(component_install_dir_.CreateUniqueTempDir());
-  }
-
- protected:
-  base::test::TaskEnvironment env_;
-  base::test::ScopedFeatureList scoped_feature_list_;
-
-  base::ScopedTempDir component_install_dir_;
-};
-
-TEST_F(MaskedDomainListComponentInstallerTest, FeatureDisabled) {
-  scoped_feature_list_.InitAndDisableFeature(
-      network::features::kMaskedDomainList);
-  auto service =
-      std::make_unique<component_updater::MockComponentUpdateService>();
-  EXPECT_CALL(*service, RegisterComponent(_)).Times(0);
-  RegisterMaskedDomainListComponent(service.get());
-
-  env_.RunUntilIdle();
-}
-
-TEST_F(MaskedDomainListComponentInstallerTest, FeatureEnabled) {
-  scoped_feature_list_.InitAndEnableFeature(
-      network::features::kMaskedDomainList);
-  auto service =
-      std::make_unique<component_updater::MockComponentUpdateService>();
-  EXPECT_CALL(*service, RegisterComponent(_)).Times(1);
-  RegisterMaskedDomainListComponent(service.get());
-
-  env_.RunUntilIdle();
-}
-
-TEST_F(MaskedDomainListComponentInstallerTest,
-       NonexistentFile_OnComponentReady) {
-  scoped_feature_list_.InitAndEnableFeature(
-      network::features::kMaskedDomainList);
-  ASSERT_TRUE(base::DeleteFile(
-      MaskedDomainListComponentInstallerPolicy::GetInstalledPath(
-          component_install_dir_.GetPath())));
-
-  base::test::RepeatingTestFuture<base::Version, base::File> future;
-  MaskedDomainListComponentInstallerPolicy(future.GetCallback())
-      .ComponentReady(base::Version(), component_install_dir_.GetPath(),
-                      base::Value::Dict());
-
-  std::tuple<base::Version, base::File> got = future.Take();
-  EXPECT_FALSE(std::get<0>(got).IsValid());
-  EXPECT_FALSE(std::get<1>(got).IsValid());
-}
-
-TEST_F(MaskedDomainListComponentInstallerTest, LoadsFile_OnComponentReady) {
-  scoped_feature_list_.InitAndEnableFeature(
-      network::features::kMaskedDomainList);
-  const base::Version version = base::Version("0.0.1");
-  const std::string expectation = "some list contents";
-  base::test::RepeatingTestFuture<base::Version, base::File> future;
-  auto policy = MaskedDomainListComponentInstallerPolicy(future.GetCallback());
-
-  ASSERT_TRUE(base::WriteFile(
-      MaskedDomainListComponentInstallerPolicy::GetInstalledPath(
-          component_install_dir_.GetPath()),
-      expectation));
-
-  policy.ComponentReady(version, component_install_dir_.GetPath(),
-                        base::Value::Dict());
-
-  std::tuple<base::Version, base::File> got = future.Take();
-  EXPECT_TRUE(std::get<0>(got).IsValid());
-  EXPECT_EQ(std::get<0>(got), version);
-  EXPECT_TRUE(std::get<1>(got).IsValid());
-  EXPECT_EQ(ReadToString(std::move(std::get<1>(got))), expectation);
-}
-
-TEST_F(MaskedDomainListComponentInstallerTest, LoadsNewListWhenUpdated) {
-  scoped_feature_list_.InitAndEnableFeature(
-      network::features::kMaskedDomainList);
-
-  base::test::RepeatingTestFuture<base::Version, base::File> future;
-  auto policy = MaskedDomainListComponentInstallerPolicy(future.GetCallback());
-
-  const base::Version version1 = base::Version("0.0.1");
-  const std::string list_v1 = "MDL v1";
-  base::ScopedTempDir dir_v1;
-  ASSERT_TRUE(
-      dir_v1.CreateUniqueTempDirUnderPath(component_install_dir_.GetPath()));
-  ASSERT_TRUE(base::WriteFile(
-      MaskedDomainListComponentInstallerPolicy::GetInstalledPath(
-          dir_v1.GetPath()),
-      list_v1));
-  policy.ComponentReady(version1, dir_v1.GetPath(), base::Value::Dict());
-
-  std::tuple<base::Version, base::File> got = future.Take();
-  EXPECT_TRUE(std::get<0>(got).IsValid());
-  EXPECT_EQ(std::get<0>(got), version1);
-  EXPECT_TRUE(std::get<1>(got).IsValid());
-  EXPECT_EQ(ReadToString(std::move(std::get<1>(got))), list_v1);
-
-  // Install newer version of the component, which should be picked up
-  // when calling ComponentReady again.
-  const base::Version version2 = base::Version("0.0.2");
-  const std::string list_v2 = "MDL v2";
-  base::ScopedTempDir dir_v2;
-  ASSERT_TRUE(
-      dir_v2.CreateUniqueTempDirUnderPath(component_install_dir_.GetPath()));
-  ASSERT_TRUE(base::WriteFile(
-      MaskedDomainListComponentInstallerPolicy::GetInstalledPath(
-          dir_v2.GetPath()),
-      list_v2));
-  policy.ComponentReady(version2, dir_v2.GetPath(), base::Value::Dict());
-
-  std::tuple<base::Version, base::File> got2 = future.Take();
-  EXPECT_TRUE(std::get<0>(got2).IsValid());
-  EXPECT_EQ(std::get<0>(got2), version2);
-  EXPECT_TRUE(std::get<1>(got2).IsValid());
-  EXPECT_EQ(ReadToString(std::move(std::get<1>(got2))), list_v2);
-
-  env_.RunUntilIdle();
-}
-
-}  // namespace component_updater
diff --git a/components/download/internal/background_service/scheduler/scheduler_impl.h b/components/download/internal/background_service/scheduler/scheduler_impl.h
index df20e2b4..53dcd9e 100644
--- a/components/download/internal/background_service/scheduler/scheduler_impl.h
+++ b/components/download/internal/background_service/scheduler/scheduler_impl.h
@@ -54,7 +54,7 @@
       const DeviceStatus& device_status);
 
   // Used to create platform dependent background tasks.
-  raw_ptr<TaskScheduler, DanglingUntriaged> task_scheduler_;
+  raw_ptr<TaskScheduler, DanglingAcrossTasks> task_scheduler_;
 
   // Download service configuration.
   raw_ptr<Configuration, DanglingUntriaged> config_;
diff --git a/components/feedback/redaction_tool/BUILD.gn b/components/feedback/redaction_tool/BUILD.gn
index 1ad1dfa..09bc571 100644
--- a/components/feedback/redaction_tool/BUILD.gn
+++ b/components/feedback/redaction_tool/BUILD.gn
@@ -4,11 +4,14 @@
 
 static_library("redaction_tool") {
   sources = [
+    "inprocess_metrics_recorder.cc",
+    "inprocess_metrics_recorder.h",
     "ip_address.cc",
     "ip_address.h",
     "pii_types.h",
     "redaction_tool.cc",
     "redaction_tool.h",
+    "redaction_tool_metrics_recorder.h",
     "url_canon.h",
     "url_canon_internal.cc",
     "url_canon_internal.h",
@@ -33,7 +36,12 @@
 
 source_set("unit_tests") {
   testonly = true
-  sources = [ "redaction_tool_unittest.cc" ]
+  sources = [
+    "inprocess_metrics_tester.cc",
+    "inprocess_metrics_tester.h",
+    "metrics_tester.h",
+    "redaction_tool_unittest.cc",
+  ]
   deps = [
     ":redaction_tool",
     "//base/test:test_support",
diff --git a/components/feedback/redaction_tool/inprocess_metrics_recorder.cc b/components/feedback/redaction_tool/inprocess_metrics_recorder.cc
new file mode 100644
index 0000000..772857f
--- /dev/null
+++ b/components/feedback/redaction_tool/inprocess_metrics_recorder.cc
@@ -0,0 +1,25 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/feedback/redaction_tool/inprocess_metrics_recorder.h"
+
+#include "base/metrics/histogram_macros.h"
+
+namespace redaction {
+
+std::unique_ptr<RedactionToolMetricsRecorder>
+RedactionToolMetricsRecorder::Create() {
+  return std::make_unique<InprocessMetricsRecorder>();
+}
+
+void InprocessMetricsRecorder::RecordPIIRedactedHistogram(PIIType pii_type) {
+  UMA_HISTOGRAM_ENUMERATION(kPIIRedactedHistogram, pii_type);
+}
+
+void InprocessMetricsRecorder::RecordCreditCardRedactionHistogram(
+    CreditCardDetection step) {
+  UMA_HISTOGRAM_ENUMERATION(kCreditCardRedactionHistogram, step);
+}
+
+}  // namespace redaction
diff --git a/components/feedback/redaction_tool/inprocess_metrics_recorder.h b/components/feedback/redaction_tool/inprocess_metrics_recorder.h
new file mode 100644
index 0000000..8aba68b
--- /dev/null
+++ b/components/feedback/redaction_tool/inprocess_metrics_recorder.h
@@ -0,0 +1,29 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_FEEDBACK_REDACTION_TOOL_INPROCESS_METRICS_RECORDER_H_
+#define COMPONENTS_FEEDBACK_REDACTION_TOOL_INPROCESS_METRICS_RECORDER_H_
+
+#include "components/feedback/redaction_tool/redaction_tool_metrics_recorder.h"
+
+namespace redaction {
+
+// Record the metrics and store them in a memory location of the program.
+// This is the default implementation for the `RedactionToolMetricsRecorder` in
+// Chromium.
+class InprocessMetricsRecorder : public RedactionToolMetricsRecorder {
+ public:
+  InprocessMetricsRecorder() = default;
+  InprocessMetricsRecorder(const InprocessMetricsRecorder&) = delete;
+  InprocessMetricsRecorder& operator=(const InprocessMetricsRecorder&) = delete;
+  ~InprocessMetricsRecorder() override = default;
+
+  // redaction::RedactionToolMetricsRecorder:
+  void RecordPIIRedactedHistogram(PIIType pii_type) override;
+  void RecordCreditCardRedactionHistogram(CreditCardDetection step) override;
+};
+
+}  // namespace redaction
+
+#endif
diff --git a/components/feedback/redaction_tool/inprocess_metrics_tester.cc b/components/feedback/redaction_tool/inprocess_metrics_tester.cc
new file mode 100644
index 0000000..3646b4d
--- /dev/null
+++ b/components/feedback/redaction_tool/inprocess_metrics_tester.cc
@@ -0,0 +1,25 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/feedback/redaction_tool/inprocess_metrics_tester.h"
+
+#include "components/feedback/redaction_tool/inprocess_metrics_recorder.h"
+
+namespace redaction {
+
+std::unique_ptr<MetricsTester> MetricsTester::Create() {
+  return std::make_unique<InprocessMetricsTester>();
+}
+
+size_t InprocessMetricsTester::GetBucketCount(base::StringPiece histogram_name,
+                                              int histogram_value) {
+  return histogram_tester_.GetBucketCount(histogram_name, histogram_value);
+}
+
+std::unique_ptr<RedactionToolMetricsRecorder>
+InprocessMetricsTester::SetupRecorder() {
+  return std::make_unique<InprocessMetricsRecorder>();
+}
+
+}  // namespace redaction
diff --git a/components/feedback/redaction_tool/inprocess_metrics_tester.h b/components/feedback/redaction_tool/inprocess_metrics_tester.h
new file mode 100644
index 0000000..8a2aef0
--- /dev/null
+++ b/components/feedback/redaction_tool/inprocess_metrics_tester.h
@@ -0,0 +1,33 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_FEEDBACK_REDACTION_TOOL_INPROCESS_METRICS_TESTER_H_
+#define COMPONENTS_FEEDBACK_REDACTION_TOOL_INPROCESS_METRICS_TESTER_H_
+
+#include "base/test/metrics/histogram_tester.h"
+#include "components/feedback/redaction_tool/metrics_tester.h"
+
+namespace redaction {
+
+// A class used for testing to retrieve bucket values for histograms.
+// This is the default implementation for the `MetricsTester` in Chromium.
+class InprocessMetricsTester : public MetricsTester {
+ public:
+  InprocessMetricsTester() = default;
+  InprocessMetricsTester(const InprocessMetricsTester&) = delete;
+  InprocessMetricsTester& operator=(const InprocessMetricsTester&) = delete;
+  ~InprocessMetricsTester() override = default;
+
+  // redaction::MetricsTester:
+  size_t GetBucketCount(base::StringPiece histogram_name,
+                        int histogram_value) override;
+  std::unique_ptr<RedactionToolMetricsRecorder> SetupRecorder() override;
+
+ private:
+  const base::HistogramTester histogram_tester_;
+};
+
+}  // namespace redaction
+
+#endif
diff --git a/components/feedback/redaction_tool/metrics_tester.h b/components/feedback/redaction_tool/metrics_tester.h
new file mode 100644
index 0000000..b9d0fb8
--- /dev/null
+++ b/components/feedback/redaction_tool/metrics_tester.h
@@ -0,0 +1,39 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_FEEDBACK_REDACTION_TOOL_METRICS_TESTER_H_
+#define COMPONENTS_FEEDBACK_REDACTION_TOOL_METRICS_TESTER_H_
+
+#include <memory>
+
+#include "base/strings/string_piece.h"
+#include "components/feedback/redaction_tool/redaction_tool_metrics_recorder.h"
+
+namespace redaction {
+
+// A helper class for testing metric collection on Chromium and ChromiumOS.
+class MetricsTester {
+ public:
+  // Create a new instance of the default implementation for this platform.
+  static std::unique_ptr<MetricsTester> Create();
+
+  MetricsTester() = default;
+  MetricsTester(const MetricsTester&) = delete;
+  MetricsTester& operator=(const MetricsTester&) = delete;
+  virtual ~MetricsTester() = default;
+
+  // Get the number of times a histogram value was recorded while this instance
+  // exists and the values are recorded with the recorder from
+  // `SetupRecorder()`.
+  virtual size_t GetBucketCount(base::StringPiece histogram_name,
+                                int histogram_value) = 0;
+
+  // Create a `RedactionToolMetricsRecorder` that is configured so it can return
+  // metric values in `GetBucketCount()`.
+  virtual std::unique_ptr<RedactionToolMetricsRecorder> SetupRecorder() = 0;
+};
+
+}  // namespace redaction
+
+#endif  // COMPONENTS_FEEDBACK_REDACTION_TOOL_METRICS_TESTER_H_
diff --git a/components/feedback/redaction_tool/redaction_tool.cc b/components/feedback/redaction_tool/redaction_tool.cc
index 4f130e78..912813c 100644
--- a/components/feedback/redaction_tool/redaction_tool.cc
+++ b/components/feedback/redaction_tool/redaction_tool.cc
@@ -10,7 +10,6 @@
 #include <vector>
 
 #include "base/files/file_path.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
@@ -529,26 +528,6 @@
 };
 constexpr size_t kNumUnredactedMacs = std::size(kUnredactedMacAddresses);
 
-void RecordPIIRedactedHistogram(const PIIType pii_type) {
-  UMA_HISTOGRAM_ENUMERATION("Feedback.RedactionTool", pii_type);
-}
-
-// These values are logged to UMA. Entries should not be renumbered and
-// numeric values should never be reused. Please keep in sync with
-// "CreditCardDetection" in //tools/metrics/histograms/enums.xml.
-enum class CreditCardDetection {
-  kRegexMatch = 1,
-  kTimestamp = 2,
-  kRepeatedChars = 3,
-  kDoesntValidate = 4,
-  kValidated = 5,
-  kMaxValue = kValidated,
-};
-
-void RecordCreditCardRedactionHistogram(CreditCardDetection step) {
-  UMA_HISTOGRAM_ENUMERATION("Feedback.RedactionTool.CreditCardMatch", step);
-}
-
 bool IsFeatureEnabled(const base::Feature& feature) {
   return base::FeatureList::GetInstance()
              ? base::FeatureList::IsEnabled(feature)
@@ -557,7 +536,15 @@
 }  // namespace
 
 RedactionTool::RedactionTool(const char* const* first_party_extension_ids)
-    : first_party_extension_ids_(first_party_extension_ids) {
+    : RedactionTool(first_party_extension_ids,
+                    RedactionToolMetricsRecorder::Create()) {}
+
+RedactionTool::RedactionTool(
+    const char* const* first_party_extension_ids,
+    std::unique_ptr<RedactionToolMetricsRecorder> metrics_recorder)
+    : first_party_extension_ids_(first_party_extension_ids),
+      metrics_recorder_(std::move(metrics_recorder)) {
+  CHECK(metrics_recorder_);
   DETACH_FROM_SEQUENCE(sequence_checker_);
   // Identity-map these, so we don't mangle them.
   for (const char* mac : kUnredactedMacAddresses) {
@@ -705,7 +692,7 @@
     }
     result.append(skipped);
     result += replacement_mac;
-    RecordPIIRedactedHistogram(PIIType::kMACAddress);
+    metrics_recorder_->RecordPIIRedactedHistogram(PIIType::kMACAddress);
   }
 
   result.append(text);
@@ -763,7 +750,7 @@
 
     result += replacement_hash;
 
-    RecordPIIRedactedHistogram(PIIType::kStableIdentifier);
+    metrics_recorder_->RecordPIIRedactedHistogram(PIIType::kStableIdentifier);
   }
 
   result.append(text);
@@ -830,7 +817,8 @@
     if (detected != nullptr) {
       (*detected)[PIIType::kAndroidAppStoragePath].emplace(app_specific);
     }
-    RecordPIIRedactedHistogram(PIIType::kAndroidAppStoragePath);
+    metrics_recorder_->RecordPIIRedactedHistogram(
+        PIIType::kAndroidAppStoragePath);
   }
 
   result.append(text);
@@ -867,20 +855,23 @@
   while (FindAndConsumeAndGetSkipped(&text, *cc_re, &skipped, &sequence,
                                      &post_sequence)) {
     result.append(skipped);
-    RecordCreditCardRedactionHistogram(CreditCardDetection::kRegexMatch);
+    metrics_recorder_->RecordCreditCardRedactionHistogram(
+        CreditCardDetection::kRegexMatch);
 
     // Timestamps in ms have a surprisingly high number of false positives.
     // Also log entries but those usually only match if there are several spaces
     // tying unrelated numbers together.
     if (post_sequence.find("ms") != re2::StringPiece::npos) {
-      RecordCreditCardRedactionHistogram(CreditCardDetection::kTimestamp);
+      metrics_recorder_->RecordCreditCardRedactionHistogram(
+          CreditCardDetection::kTimestamp);
       result.append(sequence);
       result.append(post_sequence);
       continue;
     }
 
     if (HasRepeatedChar(sequence, ' ') || HasRepeatedChar(sequence, '-')) {
-      RecordCreditCardRedactionHistogram(CreditCardDetection::kRepeatedChars);
+      metrics_recorder_->RecordCreditCardRedactionHistogram(
+          CreditCardDetection::kRepeatedChars);
       result.append(sequence);
       result.append(post_sequence);
       continue;
@@ -893,18 +884,21 @@
     if (cc_it != credit_cards_.cend()) {
       result += cc_it->second;
       result.append(post_sequence);
-      RecordCreditCardRedactionHistogram(CreditCardDetection::kValidated);
+      metrics_recorder_->RecordCreditCardRedactionHistogram(
+          CreditCardDetection::kValidated);
+      metrics_recorder_->RecordPIIRedactedHistogram(PIIType::kCreditCard);
       continue;
     }
 
     if (redaction::IsValidCreditCardNumber(number)) {
-      RecordCreditCardRedactionHistogram(CreditCardDetection::kValidated);
+      metrics_recorder_->RecordCreditCardRedactionHistogram(
+          CreditCardDetection::kValidated);
       const auto& [it, success] = credit_cards_.emplace(
           number,
           base::StrCat({"(CREDITCARD: ",
                         base::NumberToString(credit_cards_.size() + 1), ")"}));
       if (redact_credit_cards_) {
-        RecordPIIRedactedHistogram(PIIType::kCreditCard);
+        metrics_recorder_->RecordPIIRedactedHistogram(PIIType::kCreditCard);
         result += it->second;
       } else {
         result.append(sequence);
@@ -913,7 +907,8 @@
         (*detected)[PIIType::kCreditCard].insert(it->first);
       }
     } else {
-      RecordCreditCardRedactionHistogram(CreditCardDetection::kDoesntValidate);
+      metrics_recorder_->RecordCreditCardRedactionHistogram(
+          CreditCardDetection::kDoesntValidate);
       result.append(sequence);
     }
     result.append(post_sequence);
@@ -961,6 +956,7 @@
         previous_iban != ibans_.end()) {
       result += previous_iban->second;
       result.append(post_separating_char);
+      metrics_recorder_->RecordPIIRedactedHistogram(PIIType::kIBAN);
       continue;
     }
 
@@ -1027,7 +1023,7 @@
       (*detected)[PIIType::kIBAN].insert(it->first);
     }
 
-    RecordPIIRedactedHistogram(PIIType::kIBAN);
+    metrics_recorder_->RecordPIIRedactedHistogram(PIIType::kIBAN);
   }
 
   result.append(text);
@@ -1099,7 +1095,7 @@
     result.append(pre_matched_id);
     result += replacement_id;
     result.append(post_matched_id);
-    RecordPIIRedactedHistogram(pattern.pii_type);
+    metrics_recorder_->RecordPIIRedactedHistogram(pattern.pii_type);
   }
   result.append(text);
 
@@ -1181,46 +1177,46 @@
   re2::StringPiece skipped;
   re2::StringPiece matched_id;
   while (FindAndConsumeAndGetSkipped(&text, *re, &skipped, &matched_id)) {
+    result.append(skipped);
+
     if (IsUrlExempt(matched_id, first_party_extension_ids_)) {
-      result.append(skipped);
       result.append(matched_id);
       continue;
     }
-    std::string matched_id_as_string(matched_id);
-    std::string replacement_id;
-    if (identifier_space->count(matched_id_as_string) == 0) {
-      replacement_id = MaybeScrubIPAddress(matched_id_as_string);
-      if (replacement_id != matched_id_as_string) {
-        // Double-check overly opportunistic IPv4 address matching.
-        if ((strcmp("IPv4", pattern.alias) == 0) &&
-            ShouldSkipIPAddress(skipped)) {
-          result.append(skipped);
-          result.append(matched_id);
-          continue;
-        }
 
-        // The weird NumberToString trick is because Windows does not like
-        // to deal with %zu and a size_t in printf, nor does it support %llu.
-        replacement_id = base::StringPrintf(
-            "(%s: %s)",
-            replacement_id.empty() ? pattern.alias : replacement_id.c_str(),
-            base::NumberToString(identifier_space->size() + 1).c_str());
-        (*identifier_space)[matched_id_as_string] = replacement_id;
-        if (detected != nullptr) {
-          (*detected)[pattern.pii_type].insert(matched_id_as_string);
-        }
-      }
-    } else {
-      replacement_id = (*identifier_space)[matched_id_as_string];
-      if (detected != nullptr) {
-        (*detected)[pattern.pii_type].insert(matched_id_as_string);
-      }
+    const std::string matched_id_as_string(matched_id);
+    if (const auto previous_replacement =
+            identifier_space->find(matched_id_as_string);
+        previous_replacement != identifier_space->end()) {
+      metrics_recorder_->RecordPIIRedactedHistogram(pattern.pii_type);
+      result.append(previous_replacement->second);
+      continue;
     }
 
-    result.append(skipped);
-    result += replacement_id;
+    const std::string scrubbed_match =
+        MaybeScrubIPAddress(matched_id_as_string);
+    if (scrubbed_match == matched_id_as_string ||
+        // Double-check overly opportunistic IPv4 address matching.
+        ((strcmp("IPv4", pattern.alias) == 0) &&
+         ShouldSkipIPAddress(skipped))) {
+      result.append(matched_id);
+      continue;
+    }
 
-    RecordPIIRedactedHistogram(pattern.pii_type);
+    // The weird NumberToString trick is because Windows does not like
+    // to deal with %zu and a size_t in printf, nor does it support %llu.
+    const auto [redacted_pair, success] = identifier_space->insert_or_assign(
+        matched_id_as_string,
+        base::StringPrintf(
+            "(%s: %s)",
+            scrubbed_match.empty() ? pattern.alias : scrubbed_match.c_str(),
+            base::NumberToString(identifier_space->size() + 1).c_str()));
+    if (detected != nullptr) {
+      (*detected)[pattern.pii_type].insert(matched_id_as_string);
+    }
+
+    result += redacted_pair->second;
+    metrics_recorder_->RecordPIIRedactedHistogram(pattern.pii_type);
   }
   result.append(text);
 
@@ -1233,6 +1229,14 @@
     : redactor_(new RedactionTool(first_party_extension_ids)),
       task_runner_(task_runner) {}
 
+RedactionToolContainer::RedactionToolContainer(
+    scoped_refptr<base::SequencedTaskRunner> task_runner,
+    const char* const* first_party_extension_ids,
+    std::unique_ptr<RedactionToolMetricsRecorder> metrics_recorder)
+    : redactor_(new RedactionTool(first_party_extension_ids,
+                                  std::move(metrics_recorder))),
+      task_runner_(task_runner) {}
+
 RedactionToolContainer::~RedactionToolContainer() {
   task_runner_->DeleteSoon(FROM_HERE, std::move(redactor_));
 }
diff --git a/components/feedback/redaction_tool/redaction_tool.h b/components/feedback/redaction_tool/redaction_tool.h
index f35858b0..5e59b51 100644
--- a/components/feedback/redaction_tool/redaction_tool.h
+++ b/components/feedback/redaction_tool/redaction_tool.h
@@ -17,6 +17,7 @@
 #include "base/sequence_checker.h"
 #include "base/task/sequenced_task_runner.h"
 #include "components/feedback/redaction_tool/pii_types.h"
+#include "components/feedback/redaction_tool/redaction_tool_metrics_recorder.h"
 
 namespace re2 {
 class RE2;
@@ -57,6 +58,10 @@
   // party extension IDs whose URLs won't be redacted. It is OK to pass null for
   // that value if it's OK to redact those URLs or they won't be present.
   explicit RedactionTool(const char* const* first_party_extension_ids);
+  // The `metrics_recorder` is the instance of recorder that should be used on
+  // this instance instead of the default for the platform.
+  RedactionTool(const char* const* first_party_extension_ids,
+                std::unique_ptr<RedactionToolMetricsRecorder> metrics_recorder);
   ~RedactionTool();
 
   // Return a map of [PII-sensitive data type -> set of data] that are detected
@@ -192,6 +197,8 @@
 
   bool redact_credit_cards_ = false;
 
+  std::unique_ptr<RedactionToolMetricsRecorder> metrics_recorder_;
+
   SEQUENCE_CHECKER(sequence_checker_);
 };
 
@@ -205,6 +212,10 @@
   explicit RedactionToolContainer(
       scoped_refptr<base::SequencedTaskRunner> task_runner,
       const char* const* first_party_extension_ids);
+  explicit RedactionToolContainer(
+      scoped_refptr<base::SequencedTaskRunner> task_runner,
+      const char* const* first_party_extension_ids,
+      std::unique_ptr<RedactionToolMetricsRecorder> metrics_recorder);
 
   // Returns a pointer to the instance of this redactor. May only be called
   // on |task_runner_|.
diff --git a/components/feedback/redaction_tool/redaction_tool_metrics_recorder.h b/components/feedback/redaction_tool/redaction_tool_metrics_recorder.h
new file mode 100644
index 0000000..68996f34
--- /dev/null
+++ b/components/feedback/redaction_tool/redaction_tool_metrics_recorder.h
@@ -0,0 +1,54 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_FEEDBACK_REDACTION_TOOL_REDACTION_TOOL_METRICS_RECORDER_H_
+#define COMPONENTS_FEEDBACK_REDACTION_TOOL_REDACTION_TOOL_METRICS_RECORDER_H_
+
+#include <memory>
+
+#include "components/feedback/redaction_tool/pii_types.h"
+
+namespace redaction {
+
+// These values are logged to UMA. Entries should not be renumbered and
+// numeric values should never be reused. Please keep in sync with
+// "CreditCardDetection" in //tools/metrics/histograms/enums.xml.
+enum class CreditCardDetection {
+  kRegexMatch = 1,
+  kTimestamp = 2,
+  kRepeatedChars = 3,
+  kDoesntValidate = 4,
+  kValidated = 5,
+  kMaxValue = kValidated,
+};
+
+inline constexpr char kPIIRedactedHistogram[] = "Feedback.RedactionTool";
+inline constexpr char kCreditCardRedactionHistogram[] =
+    "Feedback.RedactionTool.CreditCardMatch";
+
+// This class is the platform independent interface to record histograms using
+// the platform specific libraries.
+class RedactionToolMetricsRecorder {
+ public:
+  // Create a new instance of the platform default implementation.
+  static std::unique_ptr<RedactionToolMetricsRecorder> Create();
+
+  RedactionToolMetricsRecorder() = default;
+  RedactionToolMetricsRecorder(const RedactionToolMetricsRecorder&) = delete;
+  RedactionToolMetricsRecorder& operator=(const RedactionToolMetricsRecorder&) =
+      delete;
+  virtual ~RedactionToolMetricsRecorder() = default;
+
+  // Record when a bit of PII of the type `pii_type` was redacted by the
+  // redaction tool.
+  virtual void RecordPIIRedactedHistogram(PIIType pii_type) = 0;
+
+  // Records the `step` that was reached when validating a series of numbers
+  // against credit card checks.
+  virtual void RecordCreditCardRedactionHistogram(CreditCardDetection step) = 0;
+};
+
+}  // namespace redaction
+
+#endif  // COMPONENTS_FEEDBACK_REDACTION_TOOL_REDACTION_TOOL_METRICS_RECORDER_H_
diff --git a/components/feedback/redaction_tool/redaction_tool_unittest.cc b/components/feedback/redaction_tool/redaction_tool_unittest.cc
index e5c6426..409505d 100644
--- a/components/feedback/redaction_tool/redaction_tool_unittest.cc
+++ b/components/feedback/redaction_tool/redaction_tool_unittest.cc
@@ -8,9 +8,10 @@
 #include <set>
 #include <utility>
 
+#include "base/location.h"
 #include "base/strings/string_util.h"
-#include "base/test/metrics/histogram_tester.h"
 #include "build/chromeos_buildflags.h"
+#include "components/feedback/redaction_tool/metrics_tester.h"
 #include "components/feedback/redaction_tool/pii_types.h"
 
 namespace redaction {
@@ -35,8 +36,22 @@
 const StringWithRedaction kStringsWithRedactions[] = {
     {"aaaaaaaa [SSID=123aaaaaa]aaaaa",  // SSID.
      "aaaaaaaa [SSID=(SSID: 1)]aaaaa", PIIType::kSSID},
+    {"chrome://resources/foo",  // Secure chrome resource, exempt.
+     "chrome://resources/foo", PIIType::kNone},
+    {"chrome://settings/crisper.js",  // Exempt settings URLs.
+     "chrome://settings/crisper.js", PIIType::kNone},
+    // Exempt first party extension.
+    {"chrome-extension://nkoccljplnhpfnfiajclkommnmllphnl/foobar.js",
+     "chrome-extension://nkoccljplnhpfnfiajclkommnmllphnl/foobar.js",
+     PIIType::kNone},
     {"aaaaaaaahttp://tets.comaaaaaaa",  // URL.
      "aaaaaaaa(URL: 1)", PIIType::kURL},
+    {"chrome://resources/f?user=bar",  // Potentially PII in parameter.
+     "(URL: 2)", PIIType::kURL},
+    {"chrome-extension://nkoccljplnhpfnfiajclkommnmllphnl/foobar.js?bar=x",
+     "(URL: 3)", PIIType::kURL},  // Potentially PII in parameter.
+    {"isolated-app://airugqztij5biqquuk3mfwpsaibuegaqcitgfchwuosuofdjabzqaaac/",
+     "(URL: 4)", PIIType::kURL},                  // URL
     {"u:object_r:system_data_file:s0:c512,c768",  // No PII, it is an SELinux
                                                   // context.
      "u:object_r:system_data_file:s0:c512,c768", PIIType::kNone},
@@ -172,20 +187,6 @@
      "(IPv6: 18)", PIIType::kIPAddress},
     {"aa:aa:aa:aa:aa:aa",  // MAC address (BSSID).
      "(MAC OUI=aa:aa:aa IFACE=1)", PIIType::kMACAddress},
-    {"chrome://resources/foo",  // Secure chrome resource, exempt.
-     "chrome://resources/foo", PIIType::kNone},
-    {"chrome://settings/crisper.js",  // Exempt settings URLs.
-     "chrome://settings/crisper.js", PIIType::kNone},
-    // Exempt first party extension.
-    {"chrome-extension://nkoccljplnhpfnfiajclkommnmllphnl/foobar.js",
-     "chrome-extension://nkoccljplnhpfnfiajclkommnmllphnl/foobar.js",
-     PIIType::kNone},
-    {"chrome://resources/f?user=bar",  // Potentially PII in parameter.
-     "(URL: 2)", PIIType::kURL},
-    {"chrome-extension://nkoccljplnhpfnfiajclkommnmllphnl/foobar.js?bar=x",
-     "(URL: 3)", PIIType::kURL},  // Potentially PII in parameter.
-    {"isolated-app://airugqztij5biqquuk3mfwpsaibuegaqcitgfchwuosuofdjabzqaaac/",
-     "(URL: 4)", PIIType::kURL},  // URL
     {"/root/27540283740a0897ab7c8de0f809add2bacde78f/foo",
      "/root/(HASH:2754 1)/foo", PIIType::kStableIdentifier},  // Hash string.
     {"B3mcFTkQAHofv94DDTUuVJGGEI/BbzsyDncplMCR2P4=", "(UID: 1)",
@@ -255,6 +256,12 @@
 };
 
 class RedactionToolTest : public testing::Test {
+ public:
+  RedactionToolTest()
+      : metrics_tester_(MetricsTester::Create()),
+        redactor_(kFakeFirstPartyExtensionIDs,
+                  metrics_tester_->SetupRecorder()) {}
+
  protected:
   std::string RedactMACAddresses(const std::string& input) {
     return redactor_.RedactMACAddresses(input, nullptr);
@@ -286,7 +293,21 @@
     return redactor_.RedactCustomPatternWithoutContext(input, pattern, nullptr);
   }
 
-  RedactionTool redactor_{kFakeFirstPartyExtensionIDs};
+  template <typename T>
+  void ExpectBucketCount(
+      const base::StringPiece histogram_name,
+      const T enum_value,
+      const size_t expected_count,
+      const base::Location location = base::Location::Current()) {
+    const size_t actual_count = metrics_tester_->GetBucketCount(
+        histogram_name, static_cast<int>(enum_value));
+
+    EXPECT_EQ(actual_count, expected_count)
+        << location.file_name() << ":" << location.line_number();
+  }
+
+  std::unique_ptr<MetricsTester> metrics_tester_;
+  RedactionTool redactor_;
 };
 
 TEST_F(RedactionToolTest, Redact) {
@@ -628,21 +649,18 @@
   redactor_.EnableCreditCardRedaction(true);
   std::string redaction_input;
   std::string redaction_output;
-  constexpr char kHistogramName[] = "Feedback.RedactionTool.CreditCardMatch";
-  enum class CreditCardDetection {
-    kRegexMatch = 1,
-    kTimestamp = 2,
-    kRepeatedChars = 3,
-    kDoesntValidate = 4,
-    kValidated = 5,
-  };
   using enum CreditCardDetection;
-  const base::HistogramTester histogram_tester;
-  histogram_tester.ExpectBucketCount(kHistogramName, kRegexMatch, 0);
-  histogram_tester.ExpectBucketCount(kHistogramName, kTimestamp, 0);
-  histogram_tester.ExpectBucketCount(kHistogramName, kRepeatedChars, 0);
-  histogram_tester.ExpectBucketCount(kHistogramName, kDoesntValidate, 0);
-  histogram_tester.ExpectBucketCount(kHistogramName, kValidated, 0);
+  ExpectBucketCount(kCreditCardRedactionHistogram, kRegexMatch, 0);
+  ExpectBucketCount(kCreditCardRedactionHistogram, kTimestamp, 0);
+  ExpectBucketCount(kCreditCardRedactionHistogram, kRepeatedChars, 0);
+  ExpectBucketCount(kCreditCardRedactionHistogram, kDoesntValidate, 0);
+  ExpectBucketCount(kCreditCardRedactionHistogram, kValidated, 0);
+
+  for (int enum_int = static_cast<int>(PIIType::kNone) + 1;
+       enum_int <= static_cast<int>(PIIType::kMaxValue); ++enum_int) {
+    const PIIType enum_value = static_cast<PIIType>(enum_int);
+    ExpectBucketCount(kPIIRedactedHistogram, enum_value, 0);
+  }
 
   for (const auto& s : kStringsWithRedactions) {
     redaction_input.append(s.pre_redaction).append("\n");
@@ -650,11 +668,29 @@
   }
   EXPECT_EQ(redaction_output, redactor_.Redact(redaction_input));
 
-  histogram_tester.ExpectBucketCount(kHistogramName, kRegexMatch, 16);
-  histogram_tester.ExpectBucketCount(kHistogramName, kTimestamp, 2);
-  histogram_tester.ExpectBucketCount(kHistogramName, kRepeatedChars, 1);
-  histogram_tester.ExpectBucketCount(kHistogramName, kDoesntValidate, 8);
-  histogram_tester.ExpectBucketCount(kHistogramName, kValidated, 5);
+  for (int enum_int = static_cast<int>(PIIType::kNone) + 1;
+       enum_int <= static_cast<int>(PIIType::kMaxValue); ++enum_int) {
+    const PIIType enum_value = static_cast<PIIType>(enum_int);
+    const size_t expected_count = base::ranges::count_if(
+        kStringsWithRedactions,
+        [enum_value](const StringWithRedaction& string_with_redaction) {
+          return string_with_redaction.pii_type == enum_value;
+        });
+    ExpectBucketCount(kPIIRedactedHistogram, enum_value, expected_count);
+  }
+  // This isn't handled by the redaction tool but rather in the
+  // `UiHierarchyDataCollector`. It's part of the enum for historical reasons.
+  ExpectBucketCount(kPIIRedactedHistogram, PIIType::kUIHierarchyWindowTitles,
+                    0);
+  // This isn't handled by the redaction tool but rather in Shill. It's part of
+  // the enum for historical reasons.
+  ExpectBucketCount(kPIIRedactedHistogram, PIIType::kEAP, 0);
+
+  ExpectBucketCount(kCreditCardRedactionHistogram, kRegexMatch, 16);
+  ExpectBucketCount(kCreditCardRedactionHistogram, kTimestamp, 2);
+  ExpectBucketCount(kCreditCardRedactionHistogram, kRepeatedChars, 1);
+  ExpectBucketCount(kCreditCardRedactionHistogram, kDoesntValidate, 8);
+  ExpectBucketCount(kCreditCardRedactionHistogram, kValidated, 5);
 }
 
 TEST_F(RedactionToolTest, RedactAndKeepSelected) {
diff --git a/components/gcm_driver/instance_id/instance_id_driver.h b/components/gcm_driver/instance_id/instance_id_driver.h
index eae2fa0d..a5dc8421 100644
--- a/components/gcm_driver/instance_id/instance_id_driver.h
+++ b/components/gcm_driver/instance_id/instance_id_driver.h
@@ -48,7 +48,7 @@
  private:
   // Owned by GCMProfileServiceFactory, which is a dependency of
   // InstanceIDProfileServiceFactory, which owns this.
-  raw_ptr<gcm::GCMDriver, DanglingUntriaged> gcm_driver_;
+  raw_ptr<gcm::GCMDriver, DanglingAcrossTasks> gcm_driver_;
 
   std::map<std::string, std::unique_ptr<InstanceID>> instance_id_map_;
 };
diff --git a/components/history/core/browser/expire_history_backend.h b/components/history/core/browser/expire_history_backend.h
index dfcab38..5d87bc4 100644
--- a/components/history/core/browser/expire_history_backend.h
+++ b/components/history/core/browser/expire_history_backend.h
@@ -275,9 +275,9 @@
   raw_ptr<HistoryBackendNotifier> notifier_;
 
   // Non-owning pointers to the databases we deal with (MAY BE NULL).
-  raw_ptr<HistoryDatabase, DanglingUntriaged>
+  raw_ptr<HistoryDatabase, DanglingAcrossTasks>
       main_db_;  // Main history database.
-  raw_ptr<favicon::FaviconDatabase, DanglingUntriaged> favicon_db_;
+  raw_ptr<favicon::FaviconDatabase, DanglingAcrossTasks> favicon_db_;
 
   // The threshold for "old" history where we will automatically delete it.
   base::TimeDelta expiration_threshold_;
@@ -304,7 +304,7 @@
   std::unique_ptr<ExpiringVisitsReader> auto_subframe_visits_reader_;
 
   // The HistoryBackendClient; may be null.
-  raw_ptr<HistoryBackendClient, DanglingUntriaged> backend_client_;
+  raw_ptr<HistoryBackendClient, DanglingAcrossTasks> backend_client_;
 
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
 
diff --git a/components/history/core/browser/sync/history_sync_bridge.h b/components/history/core/browser/sync/history_sync_bridge.h
index ec581a9..80df1e45 100644
--- a/components/history/core/browser/sync/history_sync_bridge.h
+++ b/components/history/core/browser/sync/history_sync_bridge.h
@@ -154,7 +154,7 @@
 
   // A non-owning pointer to the database, which is for storing sync metadata
   // and state. Can be null in case of unrecoverable database errors.
-  raw_ptr<HistorySyncMetadataDatabase, DanglingUntriaged>
+  raw_ptr<HistorySyncMetadataDatabase, DanglingAcrossTasks>
       sync_metadata_database_;
 
   // HistoryBackend uses SequencedTaskRunner, so this makes sure
diff --git a/components/history/core/browser/sync/typed_url_sync_bridge.h b/components/history/core/browser/sync/typed_url_sync_bridge.h
index 8c270e5..d83b85a0 100644
--- a/components/history/core/browser/sync/typed_url_sync_bridge.h
+++ b/components/history/core/browser/sync/typed_url_sync_bridge.h
@@ -245,7 +245,7 @@
 
   // A non-owning pointer to the database, which is for storing typed urls sync
   // metadata and state.
-  raw_ptr<TypedURLSyncMetadataDatabase, DanglingUntriaged>
+  raw_ptr<TypedURLSyncMetadataDatabase, DanglingAcrossTasks>
       sync_metadata_database_;
 
   // Since HistoryBackend use SequencedTaskRunner, so should use SequenceChecker
diff --git a/components/leveldb_proto/internal/proto_leveldb_wrapper.h b/components/leveldb_proto/internal/proto_leveldb_wrapper.h
index 8c85619..477b211 100644
--- a/components/leveldb_proto/internal/proto_leveldb_wrapper.h
+++ b/components/leveldb_proto/internal/proto_leveldb_wrapper.h
@@ -151,7 +151,7 @@
   // Used to run blocking tasks in-order, must be the TaskRunner that |db_|
   // relies on.
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
-  raw_ptr<LevelDB, DanglingUntriaged> db_ = nullptr;
+  raw_ptr<LevelDB, DanglingAcrossTasks> db_ = nullptr;
 
   // The identifier used when recording metrics to determine the source of the
   // LevelDB calls, likely the database client name.
diff --git a/components/media_device_salt/BUILD.gn b/components/media_device_salt/BUILD.gn
index 2c5b4e2..d1d7301 100644
--- a/components/media_device_salt/BUILD.gn
+++ b/components/media_device_salt/BUILD.gn
@@ -8,8 +8,6 @@
     "media_device_id_salt.h",
     "media_device_salt_service.cc",
     "media_device_salt_service.h",
-    "media_device_salt_service_factory.cc",
-    "media_device_salt_service_factory.h",
   ]
 
   deps = [
diff --git a/components/media_device_salt/media_device_salt_service_unittest.cc b/components/media_device_salt/media_device_salt_service_unittest.cc
index 8fbdb9b4..d4f1ad2 100644
--- a/components/media_device_salt/media_device_salt_service_unittest.cc
+++ b/components/media_device_salt/media_device_salt_service_unittest.cc
@@ -2,12 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/media_device_salt/media_device_salt_service_factory.h"
+#include "components/media_device_salt/media_device_salt_service.h"
 
 #include "base/test/test_future.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/media_device_salt/media_device_id_salt.h"
-#include "components/media_device_salt/media_device_salt_service.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "components/user_prefs/user_prefs.h"
 #include "content/public/test/browser_task_environment.h"
@@ -30,16 +29,10 @@
     ASSERT_TRUE(pref_service_.FindPreference(
         media_device_salt::prefs::kMediaDeviceIdSalt));
 
-    MediaDeviceSaltServiceFactory* factory =
-        MediaDeviceSaltServiceFactory::GetInstance();
-    ASSERT_TRUE(factory);
-
-    service_ = factory->GetForBrowserContext(&browser_context_);
-    ASSERT_TRUE(service_);
+    service_ = std::make_unique<MediaDeviceSaltService>(&pref_service_);
   }
 
   void TearDown() override {
-    service_ = nullptr;
     BrowserContextDependencyManager::GetInstance()
         ->DestroyBrowserContextServices(&browser_context_);
   }
@@ -60,7 +53,7 @@
   content::BrowserTaskEnvironment task_environment_;
   content::TestBrowserContext browser_context_;
   sync_preferences::TestingPrefServiceSyncable pref_service_;
-  raw_ptr<MediaDeviceSaltService> service_;
+  std::unique_ptr<MediaDeviceSaltService> service_;
 };
 
 TEST_F(MediaDeviceSaltServiceTest, GetAndResetSalt) {
diff --git a/components/metrics/metrics_state_manager.h b/components/metrics/metrics_state_manager.h
index c6aa6f0..77d8002 100644
--- a/components/metrics/metrics_state_manager.h
+++ b/components/metrics/metrics_state_manager.h
@@ -340,7 +340,7 @@
 
   // Weak pointer to an enabled state provider. Used to know whether the user
   // has consented to reporting, and if reporting should be done.
-  raw_ptr<EnabledStateProvider, DanglingUntriaged> enabled_state_provider_;
+  raw_ptr<EnabledStateProvider, DanglingAcrossTasks> enabled_state_provider_;
 
   // Specified options for controlling trial randomization.
   const EntropyParams entropy_params_;
diff --git a/components/omnibox/browser/location_bar_model_impl.h b/components/omnibox/browser/location_bar_model_impl.h
index 38fe02be..60f3b9b 100644
--- a/components/omnibox/browser/location_bar_model_impl.h
+++ b/components/omnibox/browser/location_bar_model_impl.h
@@ -53,7 +53,7 @@
   std::u16string GetFormattedURL(
       url_formatter::FormatUrlTypes format_types) const;
 
-  raw_ptr<LocationBarModelDelegate, DanglingUntriaged> delegate_;
+  raw_ptr<LocationBarModelDelegate, DanglingAcrossTasks> delegate_;
   const size_t max_url_display_chars_;
 };
 
diff --git a/components/omnibox/browser/shortcuts_backend.h b/components/omnibox/browser/shortcuts_backend.h
index bc39024..2bfd17c 100644
--- a/components/omnibox/browser/shortcuts_backend.h
+++ b/components/omnibox/browser/shortcuts_backend.h
@@ -166,7 +166,7 @@
   // Deletes all of the shortcuts.
   bool DeleteAllShortcuts();
 
-  raw_ptr<TemplateURLService, DanglingUntriaged> template_url_service_;
+  raw_ptr<TemplateURLService, DanglingAcrossTasks> template_url_service_;
   std::unique_ptr<SearchTermsData> search_terms_data_;
 
   CurrentState current_state_;
diff --git a/components/optimization_guide/core/hints_manager.h b/components/optimization_guide/core/hints_manager.h
index b3aaaaf..006d110 100644
--- a/components/optimization_guide/core/hints_manager.h
+++ b/components/optimization_guide/core/hints_manager.h
@@ -503,7 +503,7 @@
   raw_ptr<TopHostProvider, DanglingUntriaged> top_host_provider_ = nullptr;
 
   // The tab URL provider that can be queried. Not owned.
-  raw_ptr<TabUrlProvider, DanglingUntriaged> tab_url_provider_ = nullptr;
+  raw_ptr<TabUrlProvider, DanglingAcrossTasks> tab_url_provider_ = nullptr;
 
   // The timer used to schedule fetching hints from the remote Optimization
   // Guide Service.
diff --git a/components/password_manager/content/browser/content_password_manager_driver_factory.h b/components/password_manager/content/browser/content_password_manager_driver_factory.h
index e71dcb8..99dea60 100644
--- a/components/password_manager/content/browser/content_password_manager_driver_factory.h
+++ b/components/password_manager/content/browser/content_password_manager_driver_factory.h
@@ -72,8 +72,8 @@
   std::map<content::RenderFrameHost*, ContentPasswordManagerDriver>
       frame_driver_map_;
 
-  raw_ptr<PasswordManagerClient, DanglingUntriaged> password_client_;
-  raw_ptr<autofill::AutofillClient, DanglingUntriaged> autofill_client_;
+  raw_ptr<PasswordManagerClient, DanglingAcrossTasks> password_client_;
+  raw_ptr<autofill::AutofillClient, DanglingAcrossTasks> autofill_client_;
 
   WEB_CONTENTS_USER_DATA_KEY_DECL();
 };
diff --git a/components/password_manager/core/browser/affiliation/affiliation_service_impl.h b/components/password_manager/core/browser/affiliation/affiliation_service_impl.h
index a01dfa6..c6cd6d1 100644
--- a/components/password_manager/core/browser/affiliation/affiliation_service_impl.h
+++ b/components/password_manager/core/browser/affiliation/affiliation_service_impl.h
@@ -129,7 +129,7 @@
   // living on the backend thread. It will be deleted asynchronously during
   // shutdown on the backend thread, so it will outlive |this| along with all
   // its in-flight tasks.
-  raw_ptr<AffiliationBackend, DanglingUntriaged> backend_;
+  raw_ptr<AffiliationBackend, DanglingAcrossTasks> backend_;
 
   raw_ptr<PrefService> pref_service_;
 
diff --git a/components/password_manager/core/browser/password_reuse_manager_impl.h b/components/password_manager/core/browser/password_reuse_manager_impl.h
index 9407c86..b540880 100644
--- a/components/password_manager/core/browser/password_reuse_manager_impl.h
+++ b/components/password_manager/core/browser/password_reuse_manager_impl.h
@@ -111,7 +111,7 @@
   // living on the background thread. It will be deleted asynchronously during
   // shutdown on the background thread, so it will outlive |this| along with all
   // its in-flight tasks.
-  raw_ptr<PasswordReuseDetector, DanglingUntriaged> reuse_detector_ = nullptr;
+  raw_ptr<PasswordReuseDetector, DanglingAcrossTasks> reuse_detector_ = nullptr;
 
   // Notifies PasswordReuseManager about sign-in events.
   std::unique_ptr<PasswordStoreSigninNotifier> notifier_;
diff --git a/components/password_manager/core/browser/password_store.h b/components/password_manager/core/browser/password_store.h
index e70a7bf..a449867 100644
--- a/components/password_manager/core/browser/password_store.h
+++ b/components/password_manager/core/browser/password_store.h
@@ -216,7 +216,7 @@
 
   std::unique_ptr<AffiliatedMatchHelper> affiliated_match_helper_;
 
-  raw_ptr<PrefService, DanglingUntriaged> prefs_ = nullptr;
+  raw_ptr<PrefService, DanglingAcrossTasks> prefs_ = nullptr;
 
   InitStatus init_status_ = InitStatus::kUnknown;
 };
diff --git a/components/password_manager/core/browser/sync/password_sync_bridge.cc b/components/password_manager/core/browser/sync/password_sync_bridge.cc
index b547260..6b44bbd 100644
--- a/components/password_manager/core/browser/sync/password_sync_bridge.cc
+++ b/components/password_manager/core/browser/sync/password_sync_bridge.cc
@@ -287,9 +287,7 @@
           syncer::PASSWORDS);
       batch = std::make_unique<syncer::MetadataBatch>();
       sync_metadata_read_error = SyncMetadataReadError::kReadSuccessButCleared;
-    } else if (base::FeatureList::IsEnabled(
-                   syncer::kCacheBaseEntitySpecificsInMetadata) &&
-               SyncMetadataCacheContainsSupportedFields(
+    } else if (SyncMetadataCacheContainsSupportedFields(
                    batch->GetAllMetadata())) {
       // Caching entity specifics is meant to preserve fields not supported in a
       // given browser version during commits to the server. If the cache
diff --git a/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc b/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
index a03dd1f3..78e0413 100644
--- a/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
+++ b/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
@@ -925,9 +925,6 @@
 TEST_F(PasswordSyncBridgeTest,
        ShouldRemoveSyncMetadataWhenSpecificsCacheContainsSupportedFields) {
   base::HistogramTester histogram_tester;
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(
-      syncer::kCacheBaseEntitySpecificsInMetadata);
 
   ON_CALL(*mock_sync_metadata_store_sync(), GetAllSyncMetadata)
       .WillByDefault([&]() {
@@ -964,10 +961,6 @@
 TEST_F(
     PasswordSyncBridgeTest,
     ShouldNotRemoveSyncMetadataWhenSpecificsCacheContainsUnsupportedFieldsOnly) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(
-      syncer::kCacheBaseEntitySpecificsInMetadata);
-
   ON_CALL(*mock_sync_metadata_store_sync(), GetAllSyncMetadata)
       .WillByDefault([&]() {
         // Create entity with a cached unsupported field.
@@ -1125,10 +1118,6 @@
 
 TEST_F(PasswordSyncBridgeTest,
        ShouldNotRemoveSyncMetadataWhenSpecificsCacheIsEmpty) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(
-      syncer::kCacheBaseEntitySpecificsInMetadata);
-
   ON_CALL(*mock_sync_metadata_store_sync(), GetAllSyncMetadata)
       .WillByDefault([&]() {
         // Create entity with empty `possibly_trimmed_base_specifics`.
diff --git a/components/policy/core/common/cloud/cloud_policy_core.h b/components/policy/core/common/cloud/cloud_policy_core.h
index 1c4b484..1efb1cd 100644
--- a/components/policy/core/common/cloud/cloud_policy_core.h
+++ b/components/policy/core/common/cloud/cloud_policy_core.h
@@ -136,7 +136,7 @@
 
   std::string policy_type_;
   std::string settings_entity_id_;
-  raw_ptr<CloudPolicyStore, DanglingUntriaged> store_;
+  raw_ptr<CloudPolicyStore, DanglingAcrossTasks> store_;
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
   network::NetworkConnectionTrackerGetter network_connection_tracker_getter_;
   std::unique_ptr<CloudPolicyClient> client_;
diff --git a/components/policy/core/common/policy_statistics_collector.h b/components/policy/core/common/policy_statistics_collector.h
index 2376fcd..11796ed 100644
--- a/components/policy/core/common/policy_statistics_collector.h
+++ b/components/policy/core/common/policy_statistics_collector.h
@@ -80,7 +80,7 @@
   GetChromePolicyDetailsCallback get_details_;
   Schema chrome_schema_;
   raw_ptr<PolicyService> policy_service_;
-  raw_ptr<PrefService, DanglingUntriaged> prefs_;
+  raw_ptr<PrefService, DanglingAcrossTasks> prefs_;
 
   base::CancelableOnceClosure update_callback_;
 
diff --git a/components/prefs/pref_change_registrar.h b/components/prefs/pref_change_registrar.h
index 13134d6..8034a35 100644
--- a/components/prefs/pref_change_registrar.h
+++ b/components/prefs/pref_change_registrar.h
@@ -74,7 +74,7 @@
   using ObserverMap = std::map<std::string, NamedChangeCallback>;
 
   ObserverMap observers_;
-  raw_ptr<PrefService, DanglingUntriaged> service_;
+  raw_ptr<PrefService, DanglingAcrossTasks> service_;
 };
 
 #endif  // COMPONENTS_PREFS_PREF_CHANGE_REGISTRAR_H_
diff --git a/components/privacy_sandbox/privacy_sandbox_settings_impl.h b/components/privacy_sandbox/privacy_sandbox_settings_impl.h
index 14915b6..1a7e4a1c 100644
--- a/components/privacy_sandbox/privacy_sandbox_settings_impl.h
+++ b/components/privacy_sandbox/privacy_sandbox_settings_impl.h
@@ -160,7 +160,8 @@
   base::ObserverList<Observer>::Unchecked observers_;
 
   std::unique_ptr<Delegate> delegate_;
-  raw_ptr<HostContentSettingsMap, DanglingUntriaged> host_content_settings_map_;
+  raw_ptr<HostContentSettingsMap, DanglingAcrossTasks>
+      host_content_settings_map_;
   scoped_refptr<content_settings::CookieSettings> cookie_settings_;
   raw_ptr<PrefService, DanglingUntriaged> pref_service_;
   PrefChangeRegistrar pref_change_registrar_;
diff --git a/components/renderer_context_menu/context_menu_delegate.cc b/components/renderer_context_menu/context_menu_delegate.cc
index 79c9eb1..9970599 100644
--- a/components/renderer_context_menu/context_menu_delegate.cc
+++ b/components/renderer_context_menu/context_menu_delegate.cc
@@ -21,7 +21,7 @@
   ContextMenuDelegate* menu_delegate() { return menu_delegate_; }
 
  private:
-  raw_ptr<ContextMenuDelegate, DanglingUntriaged>
+  raw_ptr<ContextMenuDelegate, DanglingAcrossTasks>
       menu_delegate_;  // not owned by us.
 };
 
diff --git a/components/segmentation_platform/embedder/default_model/device_switcher_result_dispatcher.h b/components/segmentation_platform/embedder/default_model/device_switcher_result_dispatcher.h
index 78348b7..8e2ba09 100644
--- a/components/segmentation_platform/embedder/default_model/device_switcher_result_dispatcher.h
+++ b/components/segmentation_platform/embedder/default_model/device_switcher_result_dispatcher.h
@@ -66,7 +66,7 @@
   const raw_ptr<SegmentationPlatformService> segmentation_service_;
   const raw_ptr<syncer::SyncService> sync_service_;
   const raw_ptr<PrefService> prefs_;
-  const raw_ptr<FieldTrialRegister, DanglingUntriaged> field_trial_register_;
+  const raw_ptr<FieldTrialRegister, DanglingAcrossTasks> field_trial_register_;
   ClassificationResultCallback waiting_callback_;
   absl::optional<ClassificationResult> latest_result_;
 
diff --git a/components/segmentation_platform/internal/selection/segment_result_provider.cc b/components/segmentation_platform/internal/selection/segment_result_provider.cc
index b9de92a..bc871c9 100644
--- a/components/segmentation_platform/internal/selection/segment_result_provider.cc
+++ b/components/segmentation_platform/internal/selection/segment_result_provider.cc
@@ -75,7 +75,7 @@
  private:
   struct RequestState {
     std::unordered_map<DefaultModelManager::SegmentSource,
-                       raw_ptr<ModelProvider, DanglingUntriaged>>
+                       raw_ptr<ModelProvider, DanglingAcrossTasks>>
         model_providers;
     DefaultModelManager::SegmentInfoList available_segments;
     std::unique_ptr<GetResultOptions> options;
diff --git a/components/segmentation_platform/internal/signals/signal_filter_processor.h b/components/segmentation_platform/internal/signals/signal_filter_processor.h
index 3daf5b8..1f02420 100644
--- a/components/segmentation_platform/internal/signals/signal_filter_processor.h
+++ b/components/segmentation_platform/internal/signals/signal_filter_processor.h
@@ -55,7 +55,7 @@
   const raw_ptr<StorageService, DanglingUntriaged> storage_service_;
   const raw_ptr<UserActionSignalHandler> user_action_signal_handler_;
   const raw_ptr<HistogramSignalHandler> histogram_signal_handler_;
-  const raw_ptr<HistoryServiceObserver, DanglingUntriaged> history_observer_;
+  const raw_ptr<HistoryServiceObserver, DanglingAcrossTasks> history_observer_;
   const base::flat_set<SegmentId> segment_ids_;
 
   base::WeakPtrFactory<SignalFilterProcessor> weak_ptr_factory_{this};
diff --git a/components/sessions/core/session_id_generator.h b/components/sessions/core/session_id_generator.h
index 1b6b12d..996b7384 100644
--- a/components/sessions/core/session_id_generator.h
+++ b/components/sessions/core/session_id_generator.h
@@ -56,7 +56,7 @@
   void IncrementValueBy(int increment);
 
   SEQUENCE_CHECKER(sequence_checker_);
-  raw_ptr<PrefService, DanglingUntriaged> local_state_;
+  raw_ptr<PrefService, DanglingAcrossTasks> local_state_;
   SessionID::id_type last_value_;
 
   // Used to override the random number generator for tests.
diff --git a/components/signin/internal/identity_manager/accounts_cookie_mutator_impl.h b/components/signin/internal/identity_manager/accounts_cookie_mutator_impl.h
index 031b5f6d..b0941415 100644
--- a/components/signin/internal/identity_manager/accounts_cookie_mutator_impl.h
+++ b/components/signin/internal/identity_manager/accounts_cookie_mutator_impl.h
@@ -86,10 +86,10 @@
   };
 
   raw_ptr<SigninClient> signin_client_;
-  raw_ptr<ProfileOAuth2TokenService, DanglingUntriaged> token_service_;
-  raw_ptr<GaiaCookieManagerService, DanglingUntriaged>
+  raw_ptr<ProfileOAuth2TokenService, DanglingAcrossTasks> token_service_;
+  raw_ptr<GaiaCookieManagerService, DanglingAcrossTasks>
       gaia_cookie_manager_service_;
-  raw_ptr<AccountTrackerService, DanglingUntriaged> account_tracker_service_;
+  raw_ptr<AccountTrackerService, DanglingAcrossTasks> account_tracker_service_;
 };
 
 }  // namespace signin
diff --git a/components/signin/internal/identity_manager/accounts_mutator_impl.h b/components/signin/internal/identity_manager/accounts_mutator_impl.h
index 97adc260..4b20a74 100644
--- a/components/signin/internal/identity_manager/accounts_mutator_impl.h
+++ b/components/signin/internal/identity_manager/accounts_mutator_impl.h
@@ -73,9 +73,9 @@
 #endif
 
  private:
-  raw_ptr<ProfileOAuth2TokenService, DanglingUntriaged> token_service_;
-  raw_ptr<AccountTrackerService, DanglingUntriaged> account_tracker_service_;
-  raw_ptr<PrimaryAccountManager, DanglingUntriaged> primary_account_manager_;
+  raw_ptr<ProfileOAuth2TokenService, DanglingAcrossTasks> token_service_;
+  raw_ptr<AccountTrackerService, DanglingAcrossTasks> account_tracker_service_;
+  raw_ptr<PrimaryAccountManager, DanglingAcrossTasks> primary_account_manager_;
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
   raw_ptr<PrefService> pref_service_;
 #endif
diff --git a/components/signin/internal/identity_manager/diagnostics_provider_impl.h b/components/signin/internal/identity_manager/diagnostics_provider_impl.h
index 6cf700c..d66acb7 100644
--- a/components/signin/internal/identity_manager/diagnostics_provider_impl.h
+++ b/components/signin/internal/identity_manager/diagnostics_provider_impl.h
@@ -38,9 +38,9 @@
   base::TimeDelta GetDelayBeforeMakingCookieRequests() const override;
 
  private:
-  raw_ptr<GaiaCookieManagerService, DanglingUntriaged>
+  raw_ptr<GaiaCookieManagerService, DanglingAcrossTasks>
       gaia_cookie_manager_service_;
-  raw_ptr<ProfileOAuth2TokenService, DanglingUntriaged>
+  raw_ptr<ProfileOAuth2TokenService, DanglingAcrossTasks>
       profile_oauth2_token_service_;
 };
 
diff --git a/components/signin/internal/identity_manager/primary_account_mutator_impl.h b/components/signin/internal/identity_manager/primary_account_mutator_impl.h
index e304308..ff87a8c 100644
--- a/components/signin/internal/identity_manager/primary_account_mutator_impl.h
+++ b/components/signin/internal/identity_manager/primary_account_mutator_impl.h
@@ -49,8 +49,9 @@
 
   // Pointers to the services used by the PrimaryAccountMutatorImpl. They
   // *must* outlive this instance.
-  raw_ptr<AccountTrackerService, DanglingUntriaged> account_tracker_ = nullptr;
-  raw_ptr<PrimaryAccountManager, DanglingUntriaged> primary_account_manager_ =
+  raw_ptr<AccountTrackerService, DanglingAcrossTasks> account_tracker_ =
+      nullptr;
+  raw_ptr<PrimaryAccountManager, DanglingAcrossTasks> primary_account_manager_ =
       nullptr;
   raw_ptr<PrefService> pref_service_ = nullptr;
   raw_ptr<SigninClient> signin_client_ = nullptr;
diff --git a/components/sqlite_proto/table_manager.h b/components/sqlite_proto/table_manager.h
index d8e9541..26cbfbc 100644
--- a/components/sqlite_proto/table_manager.h
+++ b/components/sqlite_proto/table_manager.h
@@ -73,7 +73,7 @@
   friend class base::RefCountedThreadSafe<TableManager>;
 
   scoped_refptr<base::SequencedTaskRunner> db_task_runner_;
-  raw_ptr<sql::Database, DanglingUntriaged> db_;
+  raw_ptr<sql::Database, DanglingAcrossTasks> db_;
 };
 
 }  // namespace sqlite_proto
diff --git a/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h b/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h
index 43faaaa..efdb4af 100644
--- a/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h
+++ b/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h
@@ -114,7 +114,7 @@
 
   // Must outlive this class. For root frame navigations, this member will be
   // nullptr until NotifyPageActivationWithRuleset is called.
-  raw_ptr<VerifiedRuleset::Handle, DanglingUntriaged> ruleset_handle_;
+  raw_ptr<VerifiedRuleset::Handle, DanglingAcrossTasks> ruleset_handle_;
 
   // Will be set to true when DEFER is called in WillProcessResponse.
   bool deferred_ = false;
diff --git a/components/subresource_filter/content/browser/ads_intervention_manager.h b/components/subresource_filter/content/browser/ads_intervention_manager.h
index a98d1f3..3983a98 100644
--- a/components/subresource_filter/content/browser/ads_intervention_manager.h
+++ b/components/subresource_filter/content/browser/ads_intervention_manager.h
@@ -103,7 +103,7 @@
  private:
   // The SubresourceFilterContentSettingsManager is guaranteed to outlive the
   // AdsInterventionManager. Both are bound to the profile.
-  raw_ptr<SubresourceFilterContentSettingsManager, DanglingUntriaged>
+  raw_ptr<SubresourceFilterContentSettingsManager, DanglingAcrossTasks>
       settings_manager_ = nullptr;
 
   raw_ptr<base::Clock, DanglingUntriaged> clock_;
diff --git a/components/subresource_filter/content/browser/verified_ruleset_dealer.h b/components/subresource_filter/content/browser/verified_ruleset_dealer.h
index 554086b5..cf1964cc1 100644
--- a/components/subresource_filter/content/browser/verified_ruleset_dealer.h
+++ b/components/subresource_filter/content/browser/verified_ruleset_dealer.h
@@ -116,7 +116,7 @@
 
  private:
   // Note: Raw pointer, |dealer_| already holds a reference to |task_runner_|.
-  raw_ptr<base::SequencedTaskRunner, DanglingUntriaged> task_runner_;
+  raw_ptr<base::SequencedTaskRunner, DanglingAcrossTasks> task_runner_;
   std::unique_ptr<VerifiedRulesetDealer, base::OnTaskRunnerDeleter> dealer_;
   SEQUENCE_CHECKER(sequence_checker_);
 };
diff --git a/components/supervised_user/core/browser/BUILD.gn b/components/supervised_user/core/browser/BUILD.gn
index 5d96032c..01b321b 100644
--- a/components/supervised_user/core/browser/BUILD.gn
+++ b/components/supervised_user/core/browser/BUILD.gn
@@ -141,8 +141,12 @@
   deps = [
     ":fetcher",
     "//base",
+    "//components/safe_search_api",
+    "//components/signin/public/identity_manager",
+    "//components/supervised_user/core/browser",
     "//components/supervised_user/core/browser/proto",
     "//net/traffic_annotation",
+    "//services/network/public/cpp",
     "//url",
   ]
 }
@@ -176,6 +180,8 @@
     "//base/test:test_support",
     "//components/prefs:test_support",
     "//components/resources:components_resources",
+    "//components/signin/public/base",
+    "//components/signin/public/identity_manager",
     "//components/signin/public/identity_manager:test_support",
     "//components/strings:components_strings_grit",
     "//components/supervised_user/core/browser/proto",
diff --git a/components/supervised_user/core/browser/child_account_service.cc b/components/supervised_user/core/browser/child_account_service.cc
index 22dfeb5..fd00935 100644
--- a/components/supervised_user/core/browser/child_account_service.cc
+++ b/components/supervised_user/core/browser/child_account_service.cc
@@ -192,7 +192,17 @@
     return;
   }
 
-  SetSupervisionStatusAndNotifyObservers(info.is_child_account ==
+  signin::Tribool is_child_account = info.is_child_account;
+#if BUILDFLAG(IS_IOS)
+  if (base::FeatureList::IsEnabled(
+          supervised_user::kEnableSupervisionOnDesktopAndIOS)) {
+    // AccountInfo::is_child_account is not set on iOS; use capabilities.
+    CHECK(is_child_account == signin::Tribool::kUnknown);
+    is_child_account = info.capabilities.is_subject_to_parental_controls();
+    CHECK(is_child_account != signin::Tribool::kUnknown);
+  }
+#endif  // BUILDFLAG(IS_IOS)
+  SetSupervisionStatusAndNotifyObservers(is_child_account ==
                                          signin::Tribool::kTrue);
 }
 
diff --git a/components/supervised_user/core/browser/kids_chrome_management_client.cc b/components/supervised_user/core/browser/kids_chrome_management_client.cc
index 5d21d20..8828278 100644
--- a/components/supervised_user/core/browser/kids_chrome_management_client.cc
+++ b/components/supervised_user/core/browser/kids_chrome_management_client.cc
@@ -312,34 +312,49 @@
     return;
   }
 
-  std::unique_ptr<network::SimpleURLLoader> simple_url_loader =
-      network::SimpleURLLoader::Create(std::move(req->resource_request),
-                                       req->traffic_annotation);
+  requests_loaders_[req] = network::SimpleURLLoader::Create(
+      std::move(req->resource_request), req->traffic_annotation);
+  network::SimpleURLLoader* simple_url_loader = requests_loaders_[req].get();
 
   simple_url_loader->AttachStringForUpload(request_data,
                                            kClassifyUrlDataContentType);
 
-  auto* const simple_url_loader_ptr = simple_url_loader.get();
-  simple_url_loader_ptr->DownloadToString(
+  // `this` is guaranteed to exist when the callback is called, because the
+  // KidsChromeManagementClient class owns `simple_url_loader`, and deleting the
+  // the simple_url_loader during the request will cause the callback not to be
+  // called.
+  // TODO(https://crbug.com/1444748): Write a test making sure that this cannot
+  // cause a UAF. The test needs to:
+  // - Start a ClassifyURL request.
+  // - Start a loader and pause it before completion.
+  // - Kill the KidsChromeManagementClient. Note that this will not work unless
+  //   DCHECKs are turned off, because we otherwise check that callback_ has
+  //   been run.
+  simple_url_loader->DownloadToString(
       url_loader_factory_.get(),
       base::BindOnce(&KidsChromeManagementClient::OnSimpleLoaderComplete,
-                     base::UnsafeDanglingUntriaged(this), it,
-                     std::move(simple_url_loader), token_info),
+                     base::Unretained(this), it, token_info),
       /*max_body_size*/ 128);
 }
 
 void KidsChromeManagementClient::OnSimpleLoaderComplete(
     KidsChromeRequestList::iterator it,
-    std::unique_ptr<network::SimpleURLLoader> simple_url_loader,
     signin::AccessTokenInfo token_info,
     std::unique_ptr<std::string> response_body) {
   int response_code = -1;
 
+  KidsChromeManagementRequest* req = it->get();
+
+  // Get back the SimpleURLLoader from the stored map.
+  CHECK(requests_loaders_[req]);
+  std::unique_ptr<network::SimpleURLLoader> simple_url_loader =
+      std::move(requests_loaders_[req]);
+  requests_loaders_.erase(req);
+
   if (simple_url_loader->ResponseInfo() &&
       simple_url_loader->ResponseInfo()->headers) {
     response_code = simple_url_loader->ResponseInfo()->headers->response_code();
 
-    KidsChromeManagementRequest* req = it->get();
     // Handle first HTTP_UNAUTHORIZED response by removing access token and
     // restarting the request from the beginning (fetching access token).
     if (response_code == net::HTTP_UNAUTHORIZED && !req->access_token_expired) {
diff --git a/components/supervised_user/core/browser/kids_chrome_management_client.h b/components/supervised_user/core/browser/kids_chrome_management_client.h
index 8e8191c..d7dc47a 100644
--- a/components/supervised_user/core/browser/kids_chrome_management_client.h
+++ b/components/supervised_user/core/browser/kids_chrome_management_client.h
@@ -92,7 +92,6 @@
 
   void OnSimpleLoaderComplete(
       KidsChromeRequestList::iterator kids_chrome_request,
-      std::unique_ptr<network::SimpleURLLoader> simple_url_loader,
       signin::AccessTokenInfo token_info,
       std::unique_ptr<std::string> response_body);
 
@@ -109,6 +108,13 @@
 
   // List of requests in execution.
   KidsChromeRequestList requests_in_progress_;
+
+  // Stores the SimpleURLLoaders currently running requests. They are stored in
+  // this map during OnAccessTokenFetchComplete and removed in
+  // OnSimpleLoaderComplete.
+  std::map<KidsChromeManagementRequest*,
+           std::unique_ptr<network::SimpleURLLoader>>
+      requests_loaders_;
 };
 
 #endif  // COMPONENTS_SUPERVISED_USER_CORE_BROWSER_KIDS_CHROME_MANAGEMENT_CLIENT_H_
diff --git a/components/supervised_user/core/browser/kids_chrome_management_test_utils.cc b/components/supervised_user/core/browser/kids_chrome_management_test_utils.cc
index a0d37c7..554a06ee 100644
--- a/components/supervised_user/core/browser/kids_chrome_management_test_utils.cc
+++ b/components/supervised_user/core/browser/kids_chrome_management_test_utils.cc
@@ -3,8 +3,67 @@
 // found in the LICENSE file.
 
 #include "components/supervised_user/core/browser/kids_chrome_management_test_utils.h"
+
+#include <utility>
+
+#include "base/check.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_piece.h"
+#include "base/task/single_thread_task_runner.h"
+#include "components/signin/public/identity_manager/identity_manager.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+
+using kids_chrome_management::ClassifyUrlResponse;
+
+namespace kids_management {
+
+KidsChromeManagementClientForTesting::KidsChromeManagementClientForTesting(
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+    signin::IdentityManager* identity_manager)
+    : KidsChromeManagementClient(url_loader_factory, identity_manager) {}
+
+KidsChromeManagementClientForTesting::~KidsChromeManagementClientForTesting() =
+    default;
+
+void KidsChromeManagementClientForTesting::ClassifyURL(
+    std::unique_ptr<kids_chrome_management::ClassifyUrlRequest> request_proto,
+    KidsChromeManagementClient::KidsChromeManagementCallback callback) {
+  // Drop the request if the response is not configured.
+  if (response_proto_) {
+    base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
+        FROM_HERE, base::BindOnce(std::move(callback),
+                                  std::move(response_proto_), error_code_));
+  }
+}
+
+void KidsChromeManagementClientForTesting::SetResponseWithError(
+    std::unique_ptr<ClassifyUrlResponse> response_proto,
+    KidsChromeManagementClient::ErrorCode error_code) {
+  response_proto_ = std::move(response_proto);
+  error_code_ = error_code;
+}
+
+ClassifyUrlResponse::DisplayClassification ConvertClassification(
+    safe_search_api::ClientClassification classification) {
+  switch (classification) {
+    case safe_search_api::ClientClassification::kAllowed:
+      return ClassifyUrlResponse::ALLOWED;
+    case safe_search_api::ClientClassification::kRestricted:
+      return ClassifyUrlResponse::RESTRICTED;
+    case safe_search_api::ClientClassification::kUnknown:
+      return ClassifyUrlResponse::UNKNOWN_DISPLAY_CLASSIFICATION;
+  }
+}
+
+std::unique_ptr<ClassifyUrlResponse> BuildResponseProto(
+    safe_search_api::ClientClassification classification) {
+  auto response_proto = std::make_unique<ClassifyUrlResponse>();
+  response_proto->set_display_classification(
+      ConvertClassification(classification));
+  return response_proto;
+}
+
+}  // namespace kids_management
 
 namespace supervised_user {
 
diff --git a/components/supervised_user/core/browser/kids_chrome_management_test_utils.h b/components/supervised_user/core/browser/kids_chrome_management_test_utils.h
index 1a66975..0d54bb72 100644
--- a/components/supervised_user/core/browser/kids_chrome_management_test_utils.h
+++ b/components/supervised_user/core/browser/kids_chrome_management_test_utils.h
@@ -5,9 +5,56 @@
 #ifndef COMPONENTS_SUPERVISED_USER_CORE_BROWSER_KIDS_CHROME_MANAGEMENT_TEST_UTILS_H_
 #define COMPONENTS_SUPERVISED_USER_CORE_BROWSER_KIDS_CHROME_MANAGEMENT_TEST_UTILS_H_
 
+#include <memory>
+
+#include "base/memory/scoped_refptr.h"
 #include "base/strings/string_piece.h"
+#include "components/safe_search_api/url_checker_client.h"
+#include "components/supervised_user/core/browser/kids_chrome_management_client.h"
 #include "components/supervised_user/core/browser/proto/kidschromemanagement_messages.pb.h"
 
+namespace network {
+class SharedURLLoaderFactory;
+}  // namespace network
+
+namespace signin {
+class IdentityManager;
+}  // namespace signin
+
+namespace kids_management {
+
+class KidsChromeManagementClientForTesting : public KidsChromeManagementClient {
+ public:
+  KidsChromeManagementClientForTesting(
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+      signin::IdentityManager* identity_manager);
+
+  ~KidsChromeManagementClientForTesting() override;
+
+  void ClassifyURL(
+      std::unique_ptr<kids_chrome_management::ClassifyUrlRequest> request_proto,
+      KidsChromeManagementClient::KidsChromeManagementCallback callback)
+      override;
+
+  void SetResponseWithError(
+      std::unique_ptr<kids_chrome_management::ClassifyUrlResponse>
+          response_proto,
+      KidsChromeManagementClient::ErrorCode error_code);
+
+ private:
+  std::unique_ptr<kids_chrome_management::ClassifyUrlResponse> response_proto_;
+  KidsChromeManagementClient::ErrorCode error_code_;
+};
+
+kids_chrome_management::ClassifyUrlResponse::DisplayClassification
+ConvertClassification(safe_search_api::ClientClassification classification);
+
+// Returns a fake response proto with a response according to |classification|.
+std::unique_ptr<kids_chrome_management::ClassifyUrlResponse> BuildResponseProto(
+    safe_search_api::ClientClassification classification);
+
+}  // namespace kids_management
+
 namespace supervised_user {
 
 void SetFamilyMemberAttributesForTesting(
diff --git a/components/supervised_user/core/browser/kids_management_url_checker_client_unittest.cc b/components/supervised_user/core/browser/kids_management_url_checker_client_unittest.cc
index db320da..c869429 100644
--- a/components/supervised_user/core/browser/kids_management_url_checker_client_unittest.cc
+++ b/components/supervised_user/core/browser/kids_management_url_checker_client_unittest.cc
@@ -10,11 +10,11 @@
 #include "base/functional/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
-#include "base/task/single_thread_task_runner.h"
 #include "base/test/task_environment.h"
 #include "base/values.h"
 #include "components/signin/public/identity_manager/identity_test_environment.h"
 #include "components/supervised_user/core/browser/kids_chrome_management_client.h"
+#include "components/supervised_user/core/browser/kids_chrome_management_test_utils.h"
 #include "components/supervised_user/core/browser/proto/kidschromemanagement_messages.pb.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/network/test/test_url_loader_factory.h"
@@ -23,58 +23,8 @@
 
 using testing::_;
 
-namespace {
-
 using kids_chrome_management::ClassifyUrlResponse;
 
-ClassifyUrlResponse::DisplayClassification ConvertClassification(
-    safe_search_api::ClientClassification classification) {
-  switch (classification) {
-    case safe_search_api::ClientClassification::kAllowed:
-      return ClassifyUrlResponse::ALLOWED;
-    case safe_search_api::ClientClassification::kRestricted:
-      return ClassifyUrlResponse::RESTRICTED;
-    case safe_search_api::ClientClassification::kUnknown:
-      return ClassifyUrlResponse::UNKNOWN_DISPLAY_CLASSIFICATION;
-  }
-}
-
-// Build fake response proto with a response according to |classification|.
-std::unique_ptr<ClassifyUrlResponse> BuildResponseProto(
-    safe_search_api::ClientClassification classification) {
-  auto response_proto = std::make_unique<ClassifyUrlResponse>();
-
-  response_proto->set_display_classification(
-      ConvertClassification(classification));
-  return response_proto;
-}
-
-class KidsChromeManagementClientForTesting : public KidsChromeManagementClient {
- public:
-  using KidsChromeManagementClient::KidsChromeManagementClient;
-
-  void ClassifyURL(
-      std::unique_ptr<kids_chrome_management::ClassifyUrlRequest> request_proto,
-      KidsChromeManagementClient::KidsChromeManagementCallback callback)
-      override {
-    base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
-        FROM_HERE, base::BindOnce(std::move(callback),
-                                  std::move(response_proto_), error_code_));
-  }
-
-  void SetupResponse(std::unique_ptr<ClassifyUrlResponse> response_proto,
-                     KidsChromeManagementClient::ErrorCode error_code) {
-    response_proto_ = std::move(response_proto);
-    error_code_ = error_code;
-  }
-
- private:
-  std::unique_ptr<ClassifyUrlResponse> response_proto_;
-  KidsChromeManagementClient::ErrorCode error_code_;
-};
-
-}  // namespace
-
 class KidsManagementURLCheckerClientTest : public testing::Test {
  public:
   KidsManagementURLCheckerClientTest() = default;
@@ -86,7 +36,7 @@
 
   void SetUp() override {
     test_kids_chrome_management_client_ =
-        std::make_unique<KidsChromeManagementClientForTesting>(
+        std::make_unique<kids_management::KidsChromeManagementClientForTesting>(
             base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
                 &test_url_loader_factory_),
             identity_test_env_.identity_manager());
@@ -97,7 +47,7 @@
  protected:
   void SetupClientResponse(std::unique_ptr<ClassifyUrlResponse> response_proto,
                            KidsChromeManagementClient::ErrorCode error_code) {
-    test_kids_chrome_management_client_->SetupResponse(
+    test_kids_chrome_management_client_->SetResponseWithError(
         std::move(response_proto), error_code);
   }
 
@@ -127,7 +77,7 @@
 
   network::TestURLLoaderFactory test_url_loader_factory_;
   signin::IdentityTestEnvironment identity_test_env_;
-  std::unique_ptr<KidsChromeManagementClientForTesting>
+  std::unique_ptr<kids_management::KidsChromeManagementClientForTesting>
       test_kids_chrome_management_client_;
   std::unique_ptr<KidsManagementURLCheckerClient> url_classifier_;
 };
@@ -141,7 +91,7 @@
 
     EXPECT_CALL(*this, OnCheckDone(url, classification));
 
-    SetupClientResponse(BuildResponseProto(classification),
+    SetupClientResponse(kids_management::BuildResponseProto(classification),
                         KidsChromeManagementClient::ErrorCode::kSuccess);
 
     CheckURL(url);
@@ -154,7 +104,7 @@
 
     EXPECT_CALL(*this, OnCheckDone(url, classification));
 
-    SetupClientResponse(BuildResponseProto(classification),
+    SetupClientResponse(kids_management::BuildResponseProto(classification),
                         KidsChromeManagementClient::ErrorCode::kSuccess);
     CheckURL(url);
   }
@@ -166,7 +116,7 @@
   safe_search_api::ClientClassification classification =
       safe_search_api::ClientClassification::kUnknown;
 
-  SetupClientResponse(BuildResponseProto(classification),
+  SetupClientResponse(kids_management::BuildResponseProto(classification),
                       KidsChromeManagementClient::ErrorCode::kTokenError);
 
   EXPECT_CALL(*this, OnCheckDone(url, classification));
@@ -180,7 +130,7 @@
     safe_search_api::ClientClassification classification =
         safe_search_api::ClientClassification::kUnknown;
 
-    SetupClientResponse(BuildResponseProto(classification),
+    SetupClientResponse(kids_management::BuildResponseProto(classification),
                         KidsChromeManagementClient::ErrorCode::kNetworkError);
 
     EXPECT_CALL(*this, OnCheckDone(url, classification));
@@ -194,7 +144,7 @@
     safe_search_api::ClientClassification classification =
         safe_search_api::ClientClassification::kUnknown;
 
-    SetupClientResponse(BuildResponseProto(classification),
+    SetupClientResponse(kids_management::BuildResponseProto(classification),
                         KidsChromeManagementClient::ErrorCode::kHttpError);
 
     EXPECT_CALL(*this, OnCheckDone(url, classification));
@@ -209,7 +159,7 @@
   safe_search_api::ClientClassification classification =
       safe_search_api::ClientClassification::kUnknown;
 
-  SetupClientResponse(BuildResponseProto(classification),
+  SetupClientResponse(kids_management::BuildResponseProto(classification),
                       KidsChromeManagementClient::ErrorCode::kServiceError);
 
   EXPECT_CALL(*this, OnCheckDone(url, classification));
diff --git a/components/supervised_user/core/browser/supervised_user_service.cc b/components/supervised_user/core/browser/supervised_user_service.cc
index f26156e..67d56759 100644
--- a/components/supervised_user/core/browser/supervised_user_service.cc
+++ b/components/supervised_user/core/browser/supervised_user_service.cc
@@ -19,6 +19,7 @@
 #include "build/build_config.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
+#include "components/signin/public/identity_manager/identity_manager.h"
 #include "components/supervised_user/core/browser/kids_chrome_management_client.h"
 #include "components/supervised_user/core/browser/supervised_user_service_observer.h"
 #include "components/supervised_user/core/browser/supervised_user_settings_service.h"
@@ -42,6 +43,7 @@
 // static
 void SupervisedUserService::RegisterProfilePrefs(
     user_prefs::PrefRegistrySyncable* registry) {
+  registry->RegisterStringPref(prefs::kSupervisedUserId, std::string());
   registry->RegisterDictionaryPref(prefs::kSupervisedUserManualHosts);
   registry->RegisterDictionaryPref(prefs::kSupervisedUserManualURLs);
   registry->RegisterIntegerPref(prefs::kDefaultSupervisedUserFilteringBehavior,
@@ -147,7 +149,6 @@
 }
 
 bool SupervisedUserService::IsURLFilteringEnabled() const {
-// TODO(b/271413641): Use capabilities to verify if filtering is enabled on iOS.
 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)
   return IsSubjectToParentalControls();
 #else
@@ -187,6 +188,7 @@
 }
 
 SupervisedUserService::SupervisedUserService(
+    signin::IdentityManager* identity_manager,
     KidsChromeManagementClient* kids_chrome_management_client,
     PrefService& user_prefs,
     SupervisedUserSettingsService& settings_service,
@@ -197,6 +199,7 @@
     : user_prefs_(user_prefs),
       settings_service_(settings_service),
       sync_service_(sync_service),
+      identity_manager_(identity_manager),
       kids_chrome_management_client_(kids_chrome_management_client),
       delegate_(nullptr),
       url_filter_(std::move(check_webstore_url_callback),
diff --git a/components/supervised_user/core/browser/supervised_user_service.h b/components/supervised_user/core/browser/supervised_user_service.h
index c0f8f22..4ac19c2 100644
--- a/components/supervised_user/core/browser/supervised_user_service.h
+++ b/components/supervised_user/core/browser/supervised_user_service.h
@@ -28,14 +28,18 @@
 class Version;
 }  // namespace base
 
-namespace user_prefs {
-class PrefRegistrySyncable;
-}  // namespace user_prefs
+namespace signin {
+class IdentityManager;
+}  // namespace signin
 
 namespace syncer {
 class SyncService;
 }  // namespace syncer
 
+namespace user_prefs {
+class PrefRegistrySyncable;
+}  // namespace user_prefs
+
 namespace supervised_user {
 class SupervisedUserSettingsService;
 
@@ -152,6 +156,7 @@
   // an instance of this service.
   // Public to allow visibility to iOS factory.
   SupervisedUserService(
+      signin::IdentityManager* identity_manager,
       KidsChromeManagementClient* kids_chrome_management_client,
       PrefService& user_prefs,
       supervised_user::SupervisedUserSettingsService& settings_service,
@@ -200,6 +205,8 @@
 
   const raw_ref<syncer::SyncService> sync_service_;
 
+  raw_ptr<signin::IdentityManager> identity_manager_;
+
   raw_ptr<KidsChromeManagementClient> kids_chrome_management_client_;
 
   bool active_ = false;
diff --git a/components/supervised_user/core/browser/supervised_user_service_unittest.cc b/components/supervised_user/core/browser/supervised_user_service_unittest.cc
index 274073f..9f8c057 100644
--- a/components/supervised_user/core/browser/supervised_user_service_unittest.cc
+++ b/components/supervised_user/core/browser/supervised_user_service_unittest.cc
@@ -22,6 +22,9 @@
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
 #include "components/prefs/testing_pref_service.h"
+#include "components/signin/public/base/consent_level.h"
+#include "components/signin/public/identity_manager/account_capabilities_test_mutator.h"
+#include "components/signin/public/identity_manager/account_info.h"
 #include "components/signin/public/identity_manager/identity_test_environment.h"
 #include "components/supervised_user/core/browser/kids_chrome_management_client.h"
 #include "components/supervised_user/core/browser/supervised_user_settings_service.h"
@@ -38,8 +41,8 @@
 
 namespace {
 
-constexpr char kExampleUrl0[] = "http://www.example0.com";
-constexpr char kExampleUrl1[] = "http://www.example1.com/123";
+const char kExampleUrl0[] = "http://www.example0.com";
+const char kExampleUrl1[] = "http://www.example1.com/123";
 
 }  // namespace
 
@@ -55,9 +58,9 @@
             base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
                 &test_url_loader_factory_),
             identity_test_env_.identity_manager()) {
-    // Specify if the user is supervised.
-    syncable_pref_service_.registry()->RegisterStringPref(
-        prefs::kSupervisedUserId, std::string());
+    settings_service_.Init(syncable_pref_service_.user_prefs_store());
+    SupervisedUserService::RegisterProfilePrefs(
+        syncable_pref_service_.registry());
     if (is_supervised) {
       syncable_pref_service_.SetString(prefs::kSupervisedUserId,
                                        kChildAccountSUID);
@@ -65,13 +68,9 @@
       syncable_pref_service_.ClearPref(prefs::kSupervisedUserId);
     }
 
-    settings_service_.Init(syncable_pref_service_.user_prefs_store());
-    SupervisedUserService::RegisterProfilePrefs(
-        syncable_pref_service_.registry());
-
     service_ = std::make_unique<SupervisedUserService>(
-        &kids_chrome_management_client_, syncable_pref_service_,
-        settings_service_, sync_service_,
+        identity_test_env_.identity_manager(), &kids_chrome_management_client_,
+        syncable_pref_service_, settings_service_, sync_service_,
         /*check_webstore_url_callback=*/
         base::BindRepeating([](const GURL& url) { return false; }),
         std::make_unique<FilterDelegateImpl>(),
diff --git a/components/sync/base/features.cc b/components/sync/base/features.cc
index c6817e8..61e60f8 100644
--- a/components/sync/base/features.cc
+++ b/components/sync/base/features.cc
@@ -8,10 +8,6 @@
 
 namespace syncer {
 
-BASE_FEATURE(kCacheBaseEntitySpecificsInMetadata,
-             "CacheBaseEntitySpecificsInMetadata",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 BASE_FEATURE(kDeferredSyncStartupCustomDelay,
              "DeferredSyncStartupCustomDelay",
              base::FEATURE_DISABLED_BY_DEFAULT);
@@ -43,10 +39,6 @@
              "SyncAutofillWalletUsageData",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-BASE_FEATURE(kSyncExtensionTypesThrottling,
-             "SyncExtensionTypesThrottling",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 BASE_FEATURE(kSyncSegmentationDataType,
              "SyncSegmentationDataType",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/components/sync/base/features.h b/components/sync/base/features.h
index 9fd4fe8..e6e9e09 100644
--- a/components/sync/base/features.h
+++ b/components/sync/base/features.h
@@ -10,11 +10,6 @@
 
 namespace syncer {
 
-// If enabled, EntitySpecifics will be cached in EntityMetadata in order to
-// prevent data loss caused by older clients dealing with unknown proto fields
-// (introduced later).
-BASE_DECLARE_FEATURE(kCacheBaseEntitySpecificsInMetadata);
-
 // Customizes the delay of a deferred sync startup.
 BASE_DECLARE_FEATURE(kDeferredSyncStartupCustomDelay);
 inline constexpr base::FeatureParam<int>
@@ -65,12 +60,6 @@
 // Controls whether to enable syncing of Autofill Wallet Usage Data.
 BASE_DECLARE_FEATURE(kSyncAutofillWalletUsageData);
 
-// Causes the sync engine to count a quota for commits of data types that can
-// be committed by extension JS API. If the quota is depleted, an extra long
-// nudge delay is applied to that data type. As a result, more changes are
-// likely to get combined into one commit message.
-BASE_DECLARE_FEATURE(kSyncExtensionTypesThrottling);
-
 // If enabled, Segmentation data type will be synced.
 BASE_DECLARE_FEATURE(kSyncSegmentationDataType);
 
diff --git a/components/sync/engine/cycle/data_type_tracker.cc b/components/sync/engine/cycle/data_type_tracker.cc
index cb84d7bc46..a3c8e60 100644
--- a/components/sync/engine/cycle/data_type_tracker.cc
+++ b/components/sync/engine/cycle/data_type_tracker.cc
@@ -201,8 +201,7 @@
   // Sanity check the hardcode value for kMinLocalChangeNudgeDelay.
   DCHECK_GE(local_change_nudge_delay_, kMinLocalChangeNudgeDelay);
 
-  if (CanGetCommitsFromExtensions(type) &&
-      base::FeatureList::IsEnabled(kSyncExtensionTypesThrottling)) {
+  if (CanGetCommitsFromExtensions(type)) {
     quota_ = std::make_unique<CommitQuota>(kInitialTokensForExtensionTypes,
                                            kRefillIntervalForExtensionTypes);
   }
diff --git a/components/sync/model/client_tag_based_model_type_processor.cc b/components/sync/model/client_tag_based_model_type_processor.cc
index eba17dc..2d27b92 100644
--- a/components/sync/model/client_tag_based_model_type_processor.cc
+++ b/components/sync/model/client_tag_based_model_type_processor.cc
@@ -1382,10 +1382,7 @@
     const std::string& storage_key) const {
   DCHECK(entity_tracker_);
   DCHECK(!storage_key.empty());
-  if (!base::FeatureList::IsEnabled(
-          syncer::kCacheBaseEntitySpecificsInMetadata)) {
-    return sync_pb::EntitySpecifics::default_instance();
-  }
+
   ProcessorEntity* entity =
       entity_tracker_->GetEntityForStorageKey(storage_key);
   if (entity == nullptr) {
diff --git a/components/sync/model/client_tag_based_model_type_processor_unittest.cc b/components/sync/model/client_tag_based_model_type_processor_unittest.cc
index 8f80c03..1b515c1 100644
--- a/components/sync/model/client_tag_based_model_type_processor_unittest.cc
+++ b/components/sync/model/client_tag_based_model_type_processor_unittest.cc
@@ -660,8 +660,6 @@
 
 // Test that an initial sync handles local and remote items properly.
 TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldMergeLocalAndRemoteChanges) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(kCacheBaseEntitySpecificsInMetadata);
   ModelReadyToSync();
   OnSyncStarting();
 
@@ -700,8 +698,6 @@
 
 TEST_F(ClientTagBasedModelTypeProcessorTest,
        ShouldExposePossiblyTrimmedRemoteSpecifics) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(kCacheBaseEntitySpecificsInMetadata);
   ModelReadyToSync();
   OnSyncStarting();
 
@@ -996,8 +992,6 @@
 // Creates a new item locally.
 // Thoroughly tests the data generated by a local item creation.
 TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldCommitLocalCreation) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(kCacheBaseEntitySpecificsInMetadata);
   base::HistogramTester histogram_tester;
   InitializeToReadyState();
   ASSERT_EQ(0U, worker()->GetNumPendingCommits());
@@ -1057,8 +1051,6 @@
 // hash.
 TEST_F(ClientTagBasedModelTypeProcessorTest,
        CommitShouldOverwriteExistingItem) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(kCacheBaseEntitySpecificsInMetadata);
   base::HistogramTester histogram_tester;
   // Provide custom client tags for this test.
   bridge()->SetSupportsGetClientTag(false);
diff --git a/components/sync/model/client_tag_based_remote_update_handler_unittest.cc b/components/sync/model/client_tag_based_remote_update_handler_unittest.cc
index 9b17ee2..1e85594 100644
--- a/components/sync/model/client_tag_based_remote_update_handler_unittest.cc
+++ b/components/sync/model/client_tag_based_remote_update_handler_unittest.cc
@@ -127,9 +127,6 @@
 
 // Thoroughly tests the data generated by a server item creation.
 TEST_F(ClientTagBasedRemoteUpdateHandlerTest, ShouldProcessRemoteCreation) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(kCacheBaseEntitySpecificsInMetadata);
-
   ProcessSingleUpdate(GenerateUpdate(kKey1, kValue1));
   EXPECT_EQ(1u, db()->data_count());
   EXPECT_EQ(1u, db()->metadata_count());
@@ -179,9 +176,6 @@
 
 TEST_F(ClientTagBasedRemoteUpdateHandlerTest,
        ShouldNotClearTrimmedSpecificsOnNoopRemoteUpdates) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(kCacheBaseEntitySpecificsInMetadata);
-
   const std::string kUnknownField = "unknown_field";
 
   // Initial update containing unsupported fields.
@@ -236,9 +230,6 @@
 }
 
 TEST_F(ClientTagBasedRemoteUpdateHandlerTest, ShouldProcessRemoteUpdates) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(kCacheBaseEntitySpecificsInMetadata);
-
   ProcessSingleUpdate(GenerateUpdate(kKey1, kValue1));
   ASSERT_EQ(1U, ProcessorEntityCount());
   ASSERT_EQ(1U, db()->data_change_count());
diff --git a/components/sync/model/forwarding_model_type_controller_delegate.h b/components/sync/model/forwarding_model_type_controller_delegate.h
index c10615ef..c65999d 100644
--- a/components/sync/model/forwarding_model_type_controller_delegate.h
+++ b/components/sync/model/forwarding_model_type_controller_delegate.h
@@ -41,7 +41,7 @@
   void ClearMetadataWhileStopped() override;
 
  private:
-  const raw_ptr<ModelTypeControllerDelegate, DanglingUntriaged> other_;
+  const raw_ptr<ModelTypeControllerDelegate, DanglingAcrossTasks> other_;
 };
 
 }  // namespace syncer
diff --git a/components/sync/model/processor_entity.cc b/components/sync/model/processor_entity.cc
index 59c6b68f..f1f42afd 100644
--- a/components/sync/model/processor_entity.cc
+++ b/components/sync/model/processor_entity.cc
@@ -171,10 +171,8 @@
   metadata_.set_modification_time(
       TimeToProtoTime(update.entity.modification_time));
   UpdateSpecificsHash(update.entity.specifics);
-  if (base::FeatureList::IsEnabled(kCacheBaseEntitySpecificsInMetadata)) {
-    *metadata_.mutable_possibly_trimmed_base_specifics() =
-        std::move(trimmed_specifics);
-  }
+  *metadata_.mutable_possibly_trimmed_base_specifics() =
+      std::move(trimmed_specifics);
 }
 
 void ProcessorEntity::RecordForcedRemoteUpdate(
@@ -202,12 +200,11 @@
   // it remembers specifics hash before the modifications.
   IncrementSequenceNumber(modification_time);
   UpdateSpecificsHash(data->specifics);
-  if (base::FeatureList::IsEnabled(kCacheBaseEntitySpecificsInMetadata)) {
-    *metadata_.mutable_possibly_trimmed_base_specifics() =
-        std::move(trimmed_specifics);
-  }
-  if (!data->creation_time.is_null())
+  *metadata_.mutable_possibly_trimmed_base_specifics() =
+      std::move(trimmed_specifics);
+  if (!data->creation_time.is_null()) {
     metadata_.set_creation_time(TimeToProtoTime(data->creation_time));
+  }
   metadata_.set_modification_time(TimeToProtoTime(modification_time));
   metadata_.set_is_deleted(false);
 
diff --git a/components/sync/model/processor_entity_tracker_unittest.cc b/components/sync/model/processor_entity_tracker_unittest.cc
index f59b6e1..405d4b7 100644
--- a/components/sync/model/processor_entity_tracker_unittest.cc
+++ b/components/sync/model/processor_entity_tracker_unittest.cc
@@ -325,9 +325,6 @@
 }
 
 TEST_F(ProcessorEntityTrackerTest, ShouldUpdateSpecificsCacheOnLocalCreation) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(kCacheBaseEntitySpecificsInMetadata);
-
   std::unique_ptr<EntityData> entity_data = std::make_unique<EntityData>(
       GenerateEntityData(kStorageKey1, kClientTagHash1));
   sync_pb::EntitySpecifics specifics_for_caching;
@@ -343,9 +340,6 @@
 }
 
 TEST_F(ProcessorEntityTrackerTest, ShouldUpdateSpecificsCacheOnRemoteCreation) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(kCacheBaseEntitySpecificsInMetadata);
-
   sync_pb::EntitySpecifics specifics_for_caching;
   specifics_for_caching.mutable_preference()->set_name("name");
   specifics_for_caching.mutable_preference()->set_value("value");
diff --git a/components/sync/model/processor_entity_unittest.cc b/components/sync/model/processor_entity_unittest.cc
index 7822478..4dd9cf63 100644
--- a/components/sync/model/processor_entity_unittest.cc
+++ b/components/sync/model/processor_entity_unittest.cc
@@ -676,8 +676,6 @@
 }
 
 TEST_F(ProcessorEntityTest, UpdatesSpecificsCacheOnRemoteUpdates) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(kCacheBaseEntitySpecificsInMetadata);
   std::unique_ptr<ProcessorEntity> entity = CreateNew();
   const base::Time mtime = base::Time::Now();
   UpdateResponseData update =
@@ -691,9 +689,6 @@
 }
 
 TEST_F(ProcessorEntityTest, UpdatesSpecificsCacheOnLocalUpdates) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(kCacheBaseEntitySpecificsInMetadata);
-
   std::unique_ptr<ProcessorEntity> entity = CreateNew();
   sync_pb::EntitySpecifics specifics_for_caching =
       GenerateSpecifics(kName, kValue2);
diff --git a/components/sync/nigori/cryptographer_impl.cc b/components/sync/nigori/cryptographer_impl.cc
index 70d7be8..c886274 100644
--- a/components/sync/nigori/cryptographer_impl.cc
+++ b/components/sync/nigori/cryptographer_impl.cc
@@ -66,10 +66,6 @@
   *proto.mutable_key_bag() = key_bag_.ToProto();
   proto.set_default_key_name(default_encryption_key_name_);
   *proto.mutable_cross_user_sharing_keys() = cross_user_sharing_keys_.ToProto();
-  // TODO(crbug/1445056): once NigoriKeyBag is properly forked and encrypted
-  // remove the additional copy.
-  proto.mutable_key_bag()->mutable_cross_user_sharing_private_key()->CopyFrom(
-      proto.cross_user_sharing_keys().private_key());
   return proto;
 }
 
diff --git a/components/sync/nigori/nigori_key_bag.cc b/components/sync/nigori/nigori_key_bag.cc
index 7d38119..91d27c4 100644
--- a/components/sync/nigori/nigori_key_bag.cc
+++ b/components/sync/nigori/nigori_key_bag.cc
@@ -10,6 +10,7 @@
 #include "base/logging.h"
 #include "base/notreached.h"
 #include "components/sync/engine/nigori/nigori.h"
+#include "components/sync/protocol/nigori_local_data.pb.h"
 #include "components/sync/protocol/nigori_specifics.pb.h"
 
 namespace syncer {
@@ -48,7 +49,8 @@
 }
 
 // static
-NigoriKeyBag NigoriKeyBag::CreateFromProto(const sync_pb::NigoriKeyBag& proto) {
+NigoriKeyBag NigoriKeyBag::CreateFromProto(
+    const sync_pb::LocalNigoriKeyBag& proto) {
   NigoriKeyBag output;
   for (const sync_pb::NigoriKey& key : proto.key()) {
     if (output.AddKeyFromProto(key).empty()) {
@@ -64,8 +66,8 @@
 
 NigoriKeyBag::~NigoriKeyBag() = default;
 
-sync_pb::NigoriKeyBag NigoriKeyBag::ToProto() const {
-  sync_pb::NigoriKeyBag output;
+sync_pb::LocalNigoriKeyBag NigoriKeyBag::ToProto() const {
+  sync_pb::LocalNigoriKeyBag output;
   for (const auto& [key_name, nigori] : nigori_map_) {
     *output.add_key() = NigoriToProto(*nigori, key_name);
   }
diff --git a/components/sync/nigori/nigori_key_bag.h b/components/sync/nigori/nigori_key_bag.h
index 052a3a1..ab74b93 100644
--- a/components/sync/nigori/nigori_key_bag.h
+++ b/components/sync/nigori/nigori_key_bag.h
@@ -14,7 +14,7 @@
 namespace sync_pb {
 class EncryptedData;
 class NigoriKey;
-class NigoriKeyBag;
+class LocalNigoriKeyBag;
 }  // namespace sync_pb
 
 namespace syncer {
@@ -27,7 +27,8 @@
  public:
   static NigoriKeyBag CreateEmpty();
   // Deserialization from proto.
-  static NigoriKeyBag CreateFromProto(const sync_pb::NigoriKeyBag& key_bag);
+  static NigoriKeyBag CreateFromProto(
+      const sync_pb::LocalNigoriKeyBag& key_bag);
 
   NigoriKeyBag(NigoriKeyBag&& other);
   ~NigoriKeyBag();
@@ -35,7 +36,7 @@
   NigoriKeyBag& operator=(NigoriKeyBag&&) = default;
 
   // Serialization to proto.
-  sync_pb::NigoriKeyBag ToProto() const;
+  sync_pb::LocalNigoriKeyBag ToProto() const;
 
   // Makes a deep copy of |*this|.
   NigoriKeyBag Clone() const;
diff --git a/components/sync/nigori/nigori_key_bag_unittest.cc b/components/sync/nigori/nigori_key_bag_unittest.cc
index c5b52889..86c6f810 100644
--- a/components/sync/nigori/nigori_key_bag_unittest.cc
+++ b/components/sync/nigori/nigori_key_bag_unittest.cc
@@ -8,6 +8,7 @@
 
 #include "components/sync/engine/nigori/key_derivation_params.h"
 #include "components/sync/engine/nigori/nigori.h"
+#include "components/sync/protocol/nigori_local_data.pb.h"
 #include "components/sync/protocol/nigori_specifics.pb.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -66,7 +67,7 @@
 }
 
 TEST(NigoriKeyBagTest, ShouldConvertEmptyToProto) {
-  EXPECT_EQ(sync_pb::NigoriKeyBag().SerializeAsString(),
+  EXPECT_EQ(sync_pb::LocalNigoriKeyBag().SerializeAsString(),
             NigoriKeyBag::CreateEmpty().ToProto().SerializeAsString());
 }
 
@@ -74,7 +75,7 @@
   NigoriKeyBag key_bag = NigoriKeyBag::CreateEmpty();
   const std::string key_name = key_bag.AddKey(CreateTestNigori("password1"));
 
-  sync_pb::NigoriKeyBag proto = key_bag.ToProto();
+  sync_pb::LocalNigoriKeyBag proto = key_bag.ToProto();
   ASSERT_THAT(proto.key(), SizeIs(1));
   // Callers of ToProto() rely on the deprecated name field being populated,
   // since it gets exposed to the sync protocol, and hence subject to backward
@@ -86,7 +87,7 @@
 }
 
 TEST(NigoriKeyBagTest, ShouldCreateEmptyFromProto) {
-  EXPECT_THAT(NigoriKeyBag::CreateFromProto(sync_pb::NigoriKeyBag()),
+  EXPECT_THAT(NigoriKeyBag::CreateFromProto(sync_pb::LocalNigoriKeyBag()),
               SizeIs(0));
 }
 
@@ -112,7 +113,7 @@
   const std::string key_name2 =
       original_key_bag.AddKey(CreateTestNigori("password2"));
 
-  sync_pb::NigoriKeyBag malformed_proto = original_key_bag.ToProto();
+  sync_pb::LocalNigoriKeyBag malformed_proto = original_key_bag.ToProto();
   ASSERT_THAT(malformed_proto.key(), SizeIs(2));
   malformed_proto.mutable_key(1)->set_encryption_key("malformed-key");
 
@@ -149,7 +150,7 @@
   const std::string actual_key_name_in_proto =
       NigoriKeyBag::CreateEmpty().AddKey(CreateTestNigori("password2"));
 
-  sync_pb::NigoriKeyBag proto = original_key_bag.ToProto();
+  sync_pb::LocalNigoriKeyBag proto = original_key_bag.ToProto();
   proto.mutable_key(0)->set_deprecated_name(actual_key_name_in_proto);
 
   NigoriKeyBag restored_key_bag = NigoriKeyBag::CreateFromProto(proto);
diff --git a/components/sync/nigori/nigori_state.cc b/components/sync/nigori/nigori_state.cc
index 1fdba73..477d9f6 100644
--- a/components/sync/nigori/nigori_state.cc
+++ b/components/sync/nigori/nigori_state.cc
@@ -58,8 +58,14 @@
   sync_pb::CryptographerData proto = cryptographer.ToProto();
   DCHECK(!proto.key_bag().key().empty());
 
+  sync_pb::NigoriKeyBag keys_for_encryption;
+
+  keys_for_encryption.mutable_key()->CopyFrom(proto.key_bag().key());
+  keys_for_encryption.mutable_cross_user_sharing_private_key()->CopyFrom(
+      proto.cross_user_sharing_keys().private_key());
+
   // Encrypt the bag with the default Nigori.
-  return cryptographer.Encrypt(proto.key_bag(), encrypted);
+  return cryptographer.Encrypt(keys_for_encryption, encrypted);
 }
 
 // Writes deprecated per-type encryption fields. Can be removed once <M82
diff --git a/components/sync/nigori/nigori_sync_bridge_impl.cc b/components/sync/nigori/nigori_sync_bridge_impl.cc
index 40c5f5d8..022472d 100644
--- a/components/sync/nigori/nigori_sync_bridge_impl.cc
+++ b/components/sync/nigori/nigori_sync_bridge_impl.cc
@@ -812,8 +812,11 @@
   const std::string new_default_key_name = state_.pending_keys->key_name();
   DCHECK(key_bag.HasKey(new_default_key_name));
 
-  NigoriKeyBag new_key_bag =
-      NigoriKeyBag::CreateFromProto(decrypted_pending_keys);
+  NigoriKeyBag new_key_bag = NigoriKeyBag::CreateEmpty();
+  base::ranges::for_each(decrypted_pending_keys.key(),
+                         [&new_key_bag](sync_pb::NigoriKey key) {
+                           new_key_bag.AddKeyFromProto(key);
+                         });
 
   if (!new_key_bag.HasKey(new_default_key_name)) {
     // Protocol violation.
diff --git a/components/sync/protocol/nigori_local_data.proto b/components/sync/protocol/nigori_local_data.proto
index b1bbfb2..2a3004e 100644
--- a/components/sync/protocol/nigori_local_data.proto
+++ b/components/sync/protocol/nigori_local_data.proto
@@ -24,10 +24,14 @@
   repeated CrossUserSharingPrivateKey private_key = 1;
 }
 
+message LocalNigoriKeyBag {
+  // Used for encrypting within the sync account boundary.
+  repeated NigoriKey key = 2;
+}
+
 message CryptographerData {
   // Contains all known Nigori keys.
-  // TODO(crbug/1445056): fork the NigoriKeyBag into a local proto.
-  optional NigoriKeyBag key_bag = 1;
+  optional LocalNigoriKeyBag key_bag = 1;
 
   // Default key is the key, that should be used for encryption. Can be empty
   // in case we have pending keys (waiting for explicit passphrase, or client
diff --git a/components/sync/test/nigori_test_utils.cc b/components/sync/test/nigori_test_utils.cc
index 79fbbe5..9aa5317 100644
--- a/components/sync/test/nigori_test_utils.cc
+++ b/components/sync/test/nigori_test_utils.cc
@@ -6,6 +6,7 @@
 
 #include "base/base64.h"
 #include "base/check.h"
+#include "base/ranges/algorithm.h"
 #include "components/sync/base/time.h"
 #include "components/sync/engine/nigori/key_derivation_params.h"
 #include "components/sync/engine/nigori/nigori.h"
@@ -187,7 +188,10 @@
   sync_pb::NigoriKeyBag decrypted_keys;
   EXPECT_TRUE(decrypted_keys.ParseFromString(decrypted_keys_str));
 
-  NigoriKeyBag key_bag = NigoriKeyBag::CreateFromProto(decrypted_keys);
+  NigoriKeyBag key_bag = NigoriKeyBag::CreateEmpty();
+  base::ranges::for_each(
+      decrypted_keys.key(),
+      [&key_bag](sync_pb::NigoriKey key) { key_bag.AddKeyFromProto(key); });
 
   cryptographer->EmplaceKeysFrom(key_bag);
   return cryptographer;
diff --git a/components/sync_bookmarks/bookmark_model_type_processor.h b/components/sync_bookmarks/bookmark_model_type_processor.h
index e458039a..7ed4eca 100644
--- a/components/sync_bookmarks/bookmark_model_type_processor.h
+++ b/components/sync_bookmarks/bookmark_model_type_processor.h
@@ -156,13 +156,13 @@
   // The bookmark model we are processing local changes from and forwarding
   // remote changes to. It is set during ModelReadyToSync(), which is called
   // during startup, as part of the bookmark-loading process.
-  raw_ptr<bookmarks::BookmarkModel, DanglingUntriaged> bookmark_model_ =
+  raw_ptr<bookmarks::BookmarkModel, DanglingAcrossTasks> bookmark_model_ =
       nullptr;
 
   // Used to when processing remote updates to apply favicon information. It's
   // not set at start up because it's only avialable after the bookmark model
   // has been loaded.
-  raw_ptr<favicon::FaviconService, DanglingUntriaged> favicon_service_ =
+  raw_ptr<favicon::FaviconService, DanglingAcrossTasks> favicon_service_ =
       nullptr;
 
   // Used to suspend bookmark undo when processing remote changes.
diff --git a/components/user_prefs/user_prefs.h b/components/user_prefs/user_prefs.h
index 4efdacc..62702f3 100644
--- a/components/user_prefs/user_prefs.h
+++ b/components/user_prefs/user_prefs.h
@@ -36,7 +36,7 @@
   explicit UserPrefs(PrefService* prefs);
 
   // Non-owning; owned by embedder.
-  raw_ptr<PrefService, DanglingUntriaged> prefs_;
+  raw_ptr<PrefService, DanglingAcrossTasks> prefs_;
 };
 
 }  // namespace user_prefs
diff --git a/components/viz/common/BUILD.gn b/components/viz/common/BUILD.gn
index 8093228..ca605c3 100644
--- a/components/viz/common/BUILD.gn
+++ b/components/viz/common/BUILD.gn
@@ -47,8 +47,6 @@
   defines = [ "VIZ_RESOURCE_FORMAT_IMPLEMENTATION" ]
 
   sources = [
-    "resources/resource_format_utils.cc",
-    "resources/resource_format_utils.h",
     "resources/resource_sizes.h",
     "resources/shared_image_format_utils.cc",
     "resources/shared_image_format_utils.h",
diff --git a/components/viz/common/resources/bitmap_allocation.cc b/components/viz/common/resources/bitmap_allocation.cc
index 150f175..f5352bf93 100644
--- a/components/viz/common/resources/bitmap_allocation.cc
+++ b/components/viz/common/resources/bitmap_allocation.cc
@@ -13,7 +13,6 @@
 #include "base/memory/read_only_shared_memory_region.h"
 #include "base/process/memory.h"
 #include "build/build_config.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/resource_sizes.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 #include "ui/gfx/geometry/size.h"
diff --git a/components/viz/common/resources/resource_format_utils.cc b/components/viz/common/resources/resource_format_utils.cc
deleted file mode 100644
index eb983f5..0000000
--- a/components/viz/common/resources/resource_format_utils.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2016 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/common/resources/resource_format_utils.h"
-
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#include <GLES2/gl2extchromium.h>
-
-#include <ostream>
-
-#include "base/check_op.h"
-#include "base/logging.h"
-#include "base/notreached.h"
-#include "build/chromeos_buildflags.h"
-#include "ui/gfx/buffer_types.h"
-
-namespace viz {
-
-}  // namespace viz
diff --git a/components/viz/common/resources/resource_format_utils.h b/components/viz/common/resources/resource_format_utils.h
deleted file mode 100644
index 7a41e31..0000000
--- a/components/viz/common/resources/resource_format_utils.h
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2016 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_COMMON_RESOURCES_RESOURCE_FORMAT_UTILS_H_
-#define COMPONENTS_VIZ_COMMON_RESOURCES_RESOURCE_FORMAT_UTILS_H_
-
-#include "components/viz/common/resources/resource_format.h"
-#include "components/viz/common/viz_resource_format_export.h"
-
-namespace viz {
-
-}  // namespace viz
-
-#endif  // COMPONENTS_VIZ_COMMON_RESOURCES_RESOURCE_FORMAT_UTILS_H_
diff --git a/components/viz/common/resources/resource_format_utils_unittest.cc b/components/viz/common/resources/resource_format_utils_unittest.cc
index b5d3c0e..eca486e 100644
--- a/components/viz/common/resources/resource_format_utils_unittest.cc
+++ b/components/viz/common/resources/resource_format_utils_unittest.cc
@@ -4,7 +4,6 @@
 
 #include <vector>
 
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/components/viz/common/resources/shared_bitmap.cc b/components/viz/common/resources/shared_bitmap.cc
index 5410068..02ade0b 100644
--- a/components/viz/common/resources/shared_bitmap.cc
+++ b/components/viz/common/resources/shared_bitmap.cc
@@ -10,7 +10,6 @@
 #include "base/numerics/safe_math.h"
 #include "base/rand_util.h"
 #include "base/strings/string_number_conversions.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 
 namespace viz {
 
diff --git a/components/viz/common/resources/shared_image_format_utils.cc b/components/viz/common/resources/shared_image_format_utils.cc
index ff052085..d963b5d 100644
--- a/components/viz/common/resources/shared_image_format_utils.cc
+++ b/components/viz/common/resources/shared_image_format_utils.cc
@@ -12,7 +12,6 @@
 #include "base/logging.h"
 #include "base/notreached.h"
 #include "components/viz/common/resources/resource_format.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 
 namespace viz {
 
diff --git a/components/viz/service/display/display_resource_provider_software.cc b/components/viz/service/display/display_resource_provider_software.cc
index 6881ba15..d5bd2c73 100644
--- a/components/viz/service/display/display_resource_provider_software.cc
+++ b/components/viz/service/display/display_resource_provider_software.cc
@@ -7,7 +7,6 @@
 #include <memory>
 #include <vector>
 
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/service/display/shared_bitmap_manager.h"
 #include "third_party/skia/include/core/SkImage.h"
 
diff --git a/components/viz/service/display/display_resource_provider_software_unittest.cc b/components/viz/service/display/display_resource_provider_software_unittest.cc
index cfcbef86..dcc8f33 100644
--- a/components/viz/service/display/display_resource_provider_software_unittest.cc
+++ b/components/viz/service/display/display_resource_provider_software_unittest.cc
@@ -23,7 +23,6 @@
 #include "components/viz/client/client_resource_provider.h"
 #include "components/viz/common/resources/bitmap_allocation.h"
 #include "components/viz/common/resources/release_callback.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/returned_resource.h"
 #include "components/viz/common/resources/shared_bitmap.h"
 #include "components/viz/service/display/shared_bitmap_manager.h"
diff --git a/components/viz/service/display/resolved_frame_data.h b/components/viz/service/display/resolved_frame_data.h
index 6edf2d9..e4632c4 100644
--- a/components/viz/service/display/resolved_frame_data.h
+++ b/components/viz/service/display/resolved_frame_data.h
@@ -43,7 +43,7 @@
   FixedPassData& operator=(FixedPassData&& other);
   ~FixedPassData();
 
-  raw_ptr<CompositorRenderPass, DanglingUntriaged> render_pass = nullptr;
+  raw_ptr<CompositorRenderPass, DanglingAcrossTasks> render_pass = nullptr;
   // DrawQuads in |render_pass| that can contribute additional damage (eg.
   // surface and render passes) that need to be visited during the prewalk phase
   // of aggregation. Stored in front-to-back order like in |render_pass|.
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc
index 192afb7..bac1aba 100644
--- a/components/viz/service/display/skia_renderer.cc
+++ b/components/viz/service/display/skia_renderer.cc
@@ -40,7 +40,6 @@
 #include "components/viz/common/quads/tile_draw_quad.h"
 #include "components/viz/common/quads/yuv_video_draw_quad.h"
 #include "components/viz/common/resources/platform_color.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
 #include "components/viz/common/skia_helper.h"
 #include "components/viz/service/debugger/viz_debugger.h"
diff --git a/components/viz/service/display_embedder/output_presenter_fuchsia.cc b/components/viz/service/display_embedder/output_presenter_fuchsia.cc
index e16f1778..fb64272f 100644
--- a/components/viz/service/display_embedder/output_presenter_fuchsia.cc
+++ b/components/viz/service/display_embedder/output_presenter_fuchsia.cc
@@ -13,7 +13,6 @@
 #include "base/notreached.h"
 #include "components/viz/common/features.h"
 #include "components/viz/common/gpu/vulkan_context_provider.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/service/display_embedder/skia_output_surface_dependency.h"
 #include "gpu/command_buffer/service/external_semaphore.h"
 #include "ui/gfx/geometry/rect_conversions.h"
diff --git a/components/viz/service/display_embedder/skia_output_device_dcomp.cc b/components/viz/service/display_embedder/skia_output_device_dcomp.cc
index 6ad24cc..c506b5e 100644
--- a/components/viz/service/display_embedder/skia_output_device_dcomp.cc
+++ b/components/viz/service/display_embedder/skia_output_device_dcomp.cc
@@ -12,7 +12,6 @@
 #include "base/functional/callback_helpers.h"
 #include "base/memory/scoped_refptr.h"
 #include "components/viz/common/gpu/context_lost_reason.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/shared_image_format.h"
 #include "components/viz/service/display/dc_layer_overlay.h"
 #include "gpu/command_buffer/common/mailbox.h"
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl.cc b/components/viz/service/display_embedder/skia_output_surface_impl.cc
index e263e108..ba707bf0 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl.cc
@@ -24,7 +24,6 @@
 #include "components/viz/common/frame_sinks/begin_frame_source.h"
 #include "components/viz/common/frame_sinks/copy_output_request.h"
 #include "components/viz/common/frame_sinks/copy_output_util.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
 #include "components/viz/service/display/external_use_client.h"
 #include "components/viz/service/display/output_surface_client.h"
diff --git a/components/viz/service/hit_test/hit_test_aggregator.h b/components/viz/service/hit_test/hit_test_aggregator.h
index 4a6b09b8..60cde91 100644
--- a/components/viz/service/hit_test/hit_test_aggregator.h
+++ b/components/viz/service/hit_test/hit_test_aggregator.h
@@ -80,7 +80,7 @@
 
   const raw_ptr<HitTestAggregatorDelegate> delegate_;
 
-  const raw_ptr<LatestLocalSurfaceIdLookupDelegate, DanglingUntriaged>
+  const raw_ptr<LatestLocalSurfaceIdLookupDelegate, DanglingAcrossTasks>
       local_surface_id_lookup_delegate_;
 
   // This is the FrameSinkId for the corresponding root CompositorFrameSink.
diff --git a/components/viz/test/test_context_provider.cc b/components/viz/test/test_context_provider.cc
index 67bd6447..7edb9a5 100644
--- a/components/viz/test/test_context_provider.cc
+++ b/components/viz/test/test_context_provider.cc
@@ -19,7 +19,6 @@
 #include "base/notreached.h"
 #include "build/build_config.h"
 #include "components/viz/common/gpu/context_cache_controller.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
 #include "components/viz/test/test_gles2_interface.h"
 #include "components/viz/test/test_raster_interface.h"
diff --git a/components/viz/test/test_in_process_context_provider.cc b/components/viz/test/test_in_process_context_provider.cc
index 936519e..c6a5353 100644
--- a/components/viz/test/test_in_process_context_provider.cc
+++ b/components/viz/test/test_in_process_context_provider.cc
@@ -12,7 +12,6 @@
 #include "base/task/single_thread_task_runner.h"
 #include "base/types/optional_util.h"
 #include "components/viz/common/gpu/context_cache_controller.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
 #include "components/viz/service/gl/gpu_service_impl.h"
 #include "components/viz/test/test_gpu_service_holder.h"
diff --git a/components/viz/test/test_shared_bitmap_manager.cc b/components/viz/test/test_shared_bitmap_manager.cc
index fad1a30..025ce2db 100644
--- a/components/viz/test/test_shared_bitmap_manager.cc
+++ b/components/viz/test/test_shared_bitmap_manager.cc
@@ -11,7 +11,6 @@
 #include "base/memory/read_only_shared_memory_region.h"
 #include "base/notreached.h"
 #include "components/viz/common/resources/bitmap_allocation.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 
 namespace viz {
diff --git a/components/webapps/browser/banners/app_banner_manager.h b/components/webapps/browser/banners/app_banner_manager.h
index 64d5f6d..4abe842c 100644
--- a/components/webapps/browser/banners/app_banner_manager.h
+++ b/components/webapps/browser/banners/app_banner_manager.h
@@ -479,7 +479,7 @@
   InstallableStatusCode TerminationCode() const;
 
   // Fetches the data required to display a banner for the current page.
-  raw_ptr<InstallableManager, DanglingUntriaged> manager_;
+  raw_ptr<InstallableManager, DanglingAcrossTasks> manager_;
 
   // The manifest object. This is never null, it will instead be an empty
   // manifest so callers don't have to worry about null checks.
diff --git a/components/webdata/common/web_database_table.h b/components/webdata/common/web_database_table.h
index 9ecacb5d..9972493 100644
--- a/components/webdata/common/web_database_table.h
+++ b/components/webdata/common/web_database_table.h
@@ -55,8 +55,8 @@
   // class exists. Since lifetime of WebDatabaseTable objects slightly
   // exceeds that of WebDatabase, they should not be used in
   // ~WebDatabaseTable.
-  raw_ptr<sql::Database, DanglingUntriaged> db_;
-  raw_ptr<sql::MetaTable, DanglingUntriaged> meta_table_;
+  raw_ptr<sql::Database, DanglingAcrossTasks> db_;
+  raw_ptr<sql::MetaTable, DanglingAcrossTasks> meta_table_;
 };
 
 #endif  // COMPONENTS_WEBDATA_COMMON_WEB_DATABASE_TABLE_H_
diff --git a/content/browser/accessibility/browser_accessibility_com_win.cc b/content/browser/accessibility/browser_accessibility_com_win.cc
index 68dcc9b..b5b6eed 100644
--- a/content/browser/accessibility/browser_accessibility_com_win.cc
+++ b/content/browser/accessibility/browser_accessibility_com_win.cc
@@ -55,6 +55,18 @@
 BrowserAccessibilityComWin::WinAttributes::~WinAttributes() {}
 
 //
+// BrowserAccessibilityComWin::UpdateState
+//
+
+BrowserAccessibilityComWin::UpdateState::UpdateState(
+    std::unique_ptr<WinAttributes> old_win_attributes,
+    ui::AXLegacyHypertext old_hypertext)
+    : old_win_attributes(std::move(old_win_attributes)),
+      old_hypertext(std::move(old_hypertext)) {}
+
+BrowserAccessibilityComWin::UpdateState::~UpdateState() = default;
+
+//
 // BrowserAccessibilityComWin
 //
 BrowserAccessibilityComWin::BrowserAccessibilityComWin()
@@ -317,11 +329,13 @@
   if (!new_text)
     return E_INVALIDARG;
 
-  if (!old_win_attributes_)
+  if (!update_state_) {
     return E_FAIL;
+  }
 
   size_t start, old_len, new_len;
-  ComputeHypertextRemovedAndInserted(&start, &old_len, &new_len);
+  ComputeHypertextRemovedAndInserted(update_state_->old_hypertext, &start,
+                                     &old_len, &new_len);
   if (new_len == 0)
     return E_FAIL;
 
@@ -342,15 +356,17 @@
   if (!old_text)
     return E_INVALIDARG;
 
-  if (!old_win_attributes_)
+  if (!update_state_) {
     return E_FAIL;
+  }
 
   size_t start, old_len, new_len;
-  ComputeHypertextRemovedAndInserted(&start, &old_len, &new_len);
+  ComputeHypertextRemovedAndInserted(update_state_->old_hypertext, &start,
+                                     &old_len, &new_len);
   if (old_len == 0)
     return E_FAIL;
 
-  std::u16string old_hypertext = old_hypertext_.hypertext;
+  const std::u16string& old_hypertext = update_state_->old_hypertext.hypertext;
   std::u16string substr = old_hypertext.substr(start, old_len);
   old_text->text = SysAllocString(base::as_wcstr(substr));
   old_text->start = static_cast<LONG>(start);
@@ -1486,12 +1502,14 @@
 //
 
 void BrowserAccessibilityComWin::UpdateStep1ComputeWinAttributes() {
-  // Swap win_attributes_ to old_win_attributes_, allowing us to see
-  // exactly what changed and fire appropriate events. Note that
-  // old_win_attributes_ is cleared at the end of UpdateStep3FireEvents.
-  old_win_attributes_.swap(win_attributes_);
+  DCHECK(!update_state_);
+  DCHECK(win_attributes_);
 
-  old_hypertext_ = hypertext_;
+  // Move win_attributes_ and hypertext_ into update_state_, allowing us to see
+  // exactly what changed and fire appropriate events. Note that update_state_
+  // is destroyed at the end of UpdateStep3FireEvents.
+  update_state_ = std::make_unique<UpdateState>(std::move(win_attributes_),
+                                                std::move(hypertext_));
   hypertext_ = ui::AXLegacyHypertext();
 
   win_attributes_ = std::make_unique<WinAttributes>();
@@ -1514,26 +1532,34 @@
 }
 
 void BrowserAccessibilityComWin::UpdateStep2ComputeHypertext() {
+  DCHECK(update_state_);
   UpdateComputedHypertext();
 }
 
 void BrowserAccessibilityComWin::UpdateStep3FireEvents() {
+  DCHECK(update_state_);
+  DCHECK(update_state_->old_win_attributes);
+
   const bool ignored = owner()->IsIgnored();
 
+  const auto& old_win_attributes = *update_state_->old_win_attributes;
+
   // Suppress all of these events when the node is ignored, or when the ignored
   // state has changed on a node that isn't part of an active live region.
-  if (ignored || (old_win_attributes_->ignored != ignored &&
+  if (ignored || (old_win_attributes.ignored != ignored &&
                   !owner()->GetData().IsContainedInActiveLiveRegion() &&
                   !owner()->GetData().IsActiveLiveRegionRoot())) {
+    update_state_.reset();
     return;
   }
 
   // The rest of the events only fire on changes, not on new objects.
 
-  if (old_win_attributes_->ia_role != 0) {
+  if (old_win_attributes.ia_role != 0) {
     // Fire an event if the description, help, or value changes.
-    if (description() != old_win_attributes_->description)
+    if (description() != old_win_attributes.description) {
       FireNativeEvent(EVENT_OBJECT_DESCRIPTIONCHANGE);
+    }
 
     // Fire an event if this container object has scrolled.
     int sx = 0;
@@ -1550,10 +1576,11 @@
     // Do not fire removed/inserted when a name change event will be fired by
     // AXEventGenerator, as they are providing redundant information and will
     // lead to duplicate announcements.
-    if (name() == old_win_attributes_->name ||
+    if (name() == old_win_attributes.name ||
         GetNameFrom() == ax::mojom::NameFrom::kContents) {
       size_t start, old_len, new_len;
-      ComputeHypertextRemovedAndInserted(&start, &old_len, &new_len);
+      ComputeHypertextRemovedAndInserted(update_state_->old_hypertext, &start,
+                                         &old_len, &new_len);
       if (old_len > 0) {
         // In-process screen readers may call IAccessibleText::get_oldText
         // in reaction to this event to retrieve the text that was removed.
@@ -1567,8 +1594,7 @@
     }
   }
 
-  old_win_attributes_.reset(nullptr);
-  old_hypertext_ = ui::AXLegacyHypertext();
+  update_state_.reset();
 }
 
 BrowserAccessibilityManager* BrowserAccessibilityComWin::Manager() const {
diff --git a/content/browser/accessibility/browser_accessibility_com_win.h b/content/browser/accessibility/browser_accessibility_com_win.h
index 6168606..0966a3e4 100644
--- a/content/browser/accessibility/browser_accessibility_com_win.h
+++ b/content/browser/accessibility/browser_accessibility_com_win.h
@@ -432,9 +432,21 @@
 
   std::unique_ptr<WinAttributes> win_attributes_;
 
+  // Holds transient state needed only while processing a tree update.
+  struct UpdateState {
+    UpdateState(std::unique_ptr<WinAttributes> old_win_attributes,
+                ui::AXLegacyHypertext old_hypertext);
+    UpdateState(const UpdateState&) = delete;
+    UpdateState& operator=(const UpdateState&) = delete;
+    ~UpdateState();
+
+    std::unique_ptr<WinAttributes> old_win_attributes;
+    ui::AXLegacyHypertext old_hypertext;
+  };
+
   // Only valid during the scope of a IA2_EVENT_TEXT_REMOVED or
   // IA2_EVENT_TEXT_INSERTED event.
-  std::unique_ptr<WinAttributes> old_win_attributes_;
+  std::unique_ptr<UpdateState> update_state_;
 
   // The previous scroll position, so we can tell if this object scrolled.
   int previous_scroll_x_;
diff --git a/content/browser/attribution_reporting/attribution_internals_handler_impl.cc b/content/browser/attribution_reporting/attribution_internals_handler_impl.cc
index 6e85fef5..6e800e50 100644
--- a/content/browser/attribution_reporting/attribution_internals_handler_impl.cc
+++ b/content/browser/attribution_reporting/attribution_internals_handler_impl.cc
@@ -255,8 +255,14 @@
           ContentBrowserClient::AttributionReportingOperation::kAny,
           /*rfh=*/nullptr, /*source_origin=*/nullptr,
           /*destination_origin=*/nullptr, /*reporting_origin=*/nullptr);
+
+  // TODO(apaseltiner): This is a layering violation: The internals handler
+  // should query the manager for its configuration, not the command line,
+  // especially since `AttributionManager::SetDebugMode()` can cause its value
+  // to change after initialization.
   bool debug_mode = base::CommandLine::ForCurrentProcess()->HasSwitch(
       switches::kAttributionReportingDebugMode);
+
   std::move(callback).Run(attribution_reporting_enabled, debug_mode,
                           AttributionManager::GetSupport());
 }
diff --git a/content/browser/attribution_reporting/attribution_manager.h b/content/browser/attribution_reporting/attribution_manager.h
index 851bf3c..139d968e 100644
--- a/content/browser/attribution_reporting/attribution_manager.h
+++ b/content/browser/attribution_reporting/attribution_manager.h
@@ -16,6 +16,7 @@
 #include "content/public/browser/attribution_data_model.h"
 #include "content/public/browser/storage_partition.h"
 #include "services/network/public/mojom/attribution.mojom-forward.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace attribution_reporting {
 class SuitableOrigin;
@@ -116,6 +117,12 @@
                          BrowsingDataFilterBuilder* filter_builder,
                          bool delete_rate_limit_data,
                          base::OnceClosure done) = 0;
+
+  // If debug mode is enabled, noise and delays are disabled to facilitate
+  // testing, whether automated or manual. If `enabled` is `absl::nullopt`,
+  // falls back to `switches::kAttributionReportingDebugMode`.
+  virtual void SetDebugMode(absl::optional<bool> enabled,
+                            base::OnceClosure done) = 0;
 };
 
 }  // namespace content
diff --git a/content/browser/attribution_reporting/attribution_manager_impl.cc b/content/browser/attribution_reporting/attribution_manager_impl.cc
index 3674380..fd8c539 100644
--- a/content/browser/attribution_reporting/attribution_manager_impl.cc
+++ b/content/browser/attribution_reporting/attribution_manager_impl.cc
@@ -350,10 +350,8 @@
   }
 }
 
-std::unique_ptr<AttributionStorageDelegate> MakeStorageDelegate() {
-  bool debug_mode = base::CommandLine::ForCurrentProcess()->HasSwitch(
-      switches::kAttributionReportingDebugMode);
-
+std::unique_ptr<AttributionStorageDelegate> MakeStorageDelegate(
+    bool debug_mode) {
   if (debug_mode) {
     return std::make_unique<AttributionStorageDelegateImpl>(
         AttributionNoiseMode::kNone, AttributionDelayMode::kNone);
@@ -468,7 +466,8 @@
           user_data_directory,
           /*max_pending_events=*/1000,
           std::move(special_storage_policy),
-          MakeStorageDelegate(),
+          MakeStorageDelegate(base::CommandLine::ForCurrentProcess()->HasSwitch(
+              switches::kAttributionReportingDebugMode)),
           std::make_unique<AttributionCookieCheckerImpl>(storage_partition),
           std::make_unique<AttributionReportNetworkSender>(
               storage_partition->GetURLLoaderFactoryForBrowserProcess()),
@@ -1418,4 +1417,17 @@
                                : OsRegistrationResult::kRejectedByOs);
 }
 
+void AttributionManagerImpl::SetDebugMode(absl::optional<bool> enabled,
+                                          base::OnceClosure done) {
+  bool debug_mode =
+      enabled.value_or(base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kAttributionReportingDebugMode));
+
+  // TODO(apaseltiner): Observers should be notified when the debug mode changes
+  // so they can re-query its value.
+  attribution_storage_.AsyncCall(&AttributionStorage::SetDelegate)
+      .WithArgs(MakeStorageDelegate(debug_mode))
+      .Then(std::move(done));
+}
+
 }  // namespace content
diff --git a/content/browser/attribution_reporting/attribution_manager_impl.h b/content/browser/attribution_reporting/attribution_manager_impl.h
index d7a0ec4..2153e3a 100644
--- a/content/browser/attribution_reporting/attribution_manager_impl.h
+++ b/content/browser/attribution_reporting/attribution_manager_impl.h
@@ -139,6 +139,8 @@
       const attribution_reporting::SuitableOrigin& reporting_origin,
       attribution_reporting::mojom::SourceType,
       attribution_reporting::mojom::SourceRegistrationError) override;
+  void SetDebugMode(absl::optional<bool> enabled,
+                    base::OnceClosure done) override;
 
   void GetAllDataKeys(
       base::OnceCallback<void(std::set<DataKey>)> callback) override;
diff --git a/content/browser/attribution_reporting/attribution_storage.h b/content/browser/attribution_reporting/attribution_storage.h
index d8fe58c7..d68a8744 100644
--- a/content/browser/attribution_reporting/attribution_storage.h
+++ b/content/browser/attribution_reporting/attribution_storage.h
@@ -5,6 +5,7 @@
 #ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_ATTRIBUTION_STORAGE_H_
 #define CONTENT_BROWSER_ATTRIBUTION_REPORTING_ATTRIBUTION_STORAGE_H_
 
+#include <memory>
 #include <set>
 #include <vector>
 
@@ -20,6 +21,7 @@
 
 namespace content {
 
+class AttributionStorageDelegate;
 class AttributionTrigger;
 class CreateReportResult;
 class StorableSource;
@@ -118,6 +120,8 @@
                          base::Time delete_end,
                          StoragePartition::StorageKeyMatcherFunction filter,
                          bool delete_rate_limit_data = true) = 0;
+
+  virtual void SetDelegate(std::unique_ptr<AttributionStorageDelegate>) = 0;
 };
 
 }  // namespace content
diff --git a/content/browser/attribution_reporting/attribution_storage_delegate.h b/content/browser/attribution_reporting/attribution_storage_delegate.h
index 09f7b11..2ffc0bb 100644
--- a/content/browser/attribution_reporting/attribution_storage_delegate.h
+++ b/content/browser/attribution_reporting/attribution_storage_delegate.h
@@ -32,7 +32,9 @@
 class StoredSource;
 
 // Storage delegate that can supplied to extend basic attribution storage
-// functionality like annotating reports.
+// functionality like annotating reports. Users and subclasses must NOT assume
+// that the delegate has the same lifetime as the `AttributionManager` or
+// `AttributionStorage` classes.
 class CONTENT_EXPORT AttributionStorageDelegate {
  public:
   // Both bounds are inclusive.
diff --git a/content/browser/attribution_reporting/attribution_storage_sql.cc b/content/browser/attribution_reporting/attribution_storage_sql.cc
index 5098af8..4b70f2e 100644
--- a/content/browser/attribution_reporting/attribution_storage_sql.cc
+++ b/content/browser/attribution_reporting/attribution_storage_sql.cc
@@ -3135,4 +3135,12 @@
             /*delete_rate_limit_data=*/true);
 }
 
+void AttributionStorageSql::SetDelegate(
+    std::unique_ptr<AttributionStorageDelegate> delegate) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(delegate);
+  rate_limit_table_.SetDelegate(*delegate);
+  delegate_ = std::move(delegate);
+}
+
 }  // namespace content
diff --git a/content/browser/attribution_reporting/attribution_storage_sql.h b/content/browser/attribution_reporting/attribution_storage_sql.h
index e1c88b7..ec8cbd3 100644
--- a/content/browser/attribution_reporting/attribution_storage_sql.h
+++ b/content/browser/attribution_reporting/attribution_storage_sql.h
@@ -126,6 +126,7 @@
                  base::Time delete_end,
                  StoragePartition::StorageKeyMatcherFunction filter,
                  bool delete_rate_limit_data) override;
+  void SetDelegate(std::unique_ptr<AttributionStorageDelegate>) override;
 
   [[nodiscard]] attribution_reporting::mojom::StoreSourceResult
   CheckDestinationThrottler(const StorableSource& source);
diff --git a/content/browser/attribution_reporting/rate_limit_table.cc b/content/browser/attribution_reporting/rate_limit_table.cc
index eadc9f8..c358ba04 100644
--- a/content/browser/attribution_reporting/rate_limit_table.cc
+++ b/content/browser/attribution_reporting/rate_limit_table.cc
@@ -523,4 +523,9 @@
   }
 }
 
+void RateLimitTable::SetDelegate(const AttributionStorageDelegate& delegate) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  delegate_ = delegate;
+}
+
 }  // namespace content
diff --git a/content/browser/attribution_reporting/rate_limit_table.h b/content/browser/attribution_reporting/rate_limit_table.h
index 084dbe9..4c7e6f6f 100644
--- a/content/browser/attribution_reporting/rate_limit_table.h
+++ b/content/browser/attribution_reporting/rate_limit_table.h
@@ -120,6 +120,8 @@
   void AppendRateLimitDataKeys(sql::Database* db,
                                std::set<AttributionDataModel::DataKey>& keys);
 
+  void SetDelegate(const AttributionStorageDelegate&);
+
  private:
   [[nodiscard]] bool AddRateLimit(
       sql::Database* db,
@@ -148,7 +150,7 @@
   [[nodiscard]] bool DeleteExpiredRateLimits(sql::Database* db)
       VALID_CONTEXT_REQUIRED(sequence_checker_);
 
-  const raw_ref<const AttributionStorageDelegate> delegate_
+  raw_ref<const AttributionStorageDelegate> delegate_
       GUARDED_BY_CONTEXT(sequence_checker_);
 
   // Time at which `DeleteExpiredRateLimits()` was last called. Initialized to
diff --git a/content/browser/attribution_reporting/test/mock_attribution_manager.h b/content/browser/attribution_reporting/test/mock_attribution_manager.h
index d689645a..e285bd8 100644
--- a/content/browser/attribution_reporting/test/mock_attribution_manager.h
+++ b/content/browser/attribution_reporting/test/mock_attribution_manager.h
@@ -108,6 +108,11 @@
               (OsRegistration, GlobalRenderFrameHostId),
               (override));
 
+  MOCK_METHOD(void,
+              SetDebugMode,
+              (absl::optional<bool> enabled, base::OnceClosure done),
+              (override));
+
   void AddObserver(AttributionObserver*) override;
   void RemoveObserver(AttributionObserver*) override;
   AttributionDataHostManager* GetDataHostManager() override;
diff --git a/content/browser/child_process_security_policy_impl.cc b/content/browser/child_process_security_policy_impl.cc
index 2bfca65c..701cf15 100644
--- a/content/browser/child_process_security_policy_impl.cc
+++ b/content/browser/child_process_security_policy_impl.cc
@@ -719,7 +719,7 @@
   FileSystemMap filesystem_permissions_;
 
   raw_ptr<BrowserContext> browser_context_;
-  raw_ptr<ResourceContext, DanglingUntriaged> resource_context_;
+  raw_ptr<ResourceContext, DanglingAcrossTasks> resource_context_;
 };
 
 // IsolatedOriginEntry implementation.
diff --git a/content/browser/content_index/content_index_context_impl.h b/content/browser/content_index/content_index_context_impl.h
index d19aa6a..6098074 100644
--- a/content/browser/content_index/content_index_context_impl.h
+++ b/content/browser/content_index/content_index_context_impl.h
@@ -58,7 +58,7 @@
 
   ~ContentIndexContextImpl() override;
 
-  raw_ptr<ContentIndexProvider, DanglingUntriaged> provider_;
+  raw_ptr<ContentIndexProvider, DanglingAcrossTasks> provider_;
   ContentIndexDatabase content_index_database_;
 };
 
diff --git a/content/browser/content_index/content_index_database.h b/content/browser/content_index/content_index_database.h
index 8e44d794..af84d331 100644
--- a/content/browser/content_index/content_index_database.h
+++ b/content/browser/content_index/content_index_database.h
@@ -173,7 +173,7 @@
   void BlockOrigin(const url::Origin& origin);
   void UnblockOrigin(const url::Origin& origin);
 
-  raw_ptr<ContentIndexProvider, DanglingUntriaged> provider_;
+  raw_ptr<ContentIndexProvider, DanglingAcrossTasks> provider_;
 
   // A map from origins to how many times it's been blocked.
   base::flat_map<url::Origin, int> blocked_origins_;
diff --git a/content/browser/devtools/protocol/storage_handler.cc b/content/browser/devtools/protocol/storage_handler.cc
index 0df7060..6c71e05 100644
--- a/content/browser/devtools/protocol/storage_handler.cc
+++ b/content/browser/devtools/protocol/storage_handler.cc
@@ -18,6 +18,7 @@
 #include "components/services/storage/privileged/mojom/indexed_db_control.mojom.h"
 #include "components/services/storage/public/cpp/buckets/bucket_locator.h"
 #include "components/services/storage/public/mojom/cache_storage_control.mojom.h"
+#include "content/browser/attribution_reporting/attribution_manager.h"
 #include "content/browser/devtools/protocol/browser_handler.h"
 #include "content/browser/devtools/protocol/handler_helpers.h"
 #include "content/browser/devtools/protocol/network.h"
@@ -443,6 +444,7 @@
   SetInterestGroupTracking(false);
   shared_storage_observer_.reset();
   quota_manager_observer_.reset();
+  ResetAttributionReportingLocalTestingMode();
   return Response::Success();
 }
 
@@ -1607,5 +1609,41 @@
       base::NumberToString(bucket_locator.id.value()));
 }
 
+void StorageHandler::SetAttributionReportingLocalTestingMode(
+    bool enabled,
+    std::unique_ptr<SetAttributionReportingLocalTestingModeCallback> callback) {
+  if (!storage_partition_) {
+    callback->sendFailure(Response::InternalError());
+    return;
+  }
+
+  auto* manager = static_cast<StoragePartitionImpl*>(storage_partition_)
+                      ->GetAttributionManager();
+  if (!manager) {
+    callback->sendFailure(Response::InternalError());
+    return;
+  }
+
+  manager->SetDebugMode(
+      enabled,
+      base::BindOnce(
+          &SetAttributionReportingLocalTestingModeCallback::sendSuccess,
+          std::move(callback)));
+}
+
+void StorageHandler::ResetAttributionReportingLocalTestingMode() {
+  if (!storage_partition_) {
+    return;
+  }
+
+  auto* manager = static_cast<StoragePartitionImpl*>(storage_partition_)
+                      ->GetAttributionManager();
+  if (!manager) {
+    return;
+  }
+
+  manager->SetDebugMode(/*enabled=*/absl::nullopt, base::DoNothing());
+}
+
 }  // namespace protocol
 }  // namespace content
diff --git a/content/browser/devtools/protocol/storage_handler.h b/content/browser/devtools/protocol/storage_handler.h
index 803c971..44c3317 100644
--- a/content/browser/devtools/protocol/storage_handler.h
+++ b/content/browser/devtools/protocol/storage_handler.h
@@ -137,6 +137,11 @@
   DispatchResponse DeleteStorageBucket(
       std::unique_ptr<protocol::Storage::StorageBucket> bucket) override;
 
+  void SetAttributionReportingLocalTestingMode(
+      bool enabled,
+      std::unique_ptr<SetAttributionReportingLocalTestingModeCallback>)
+      override;
+
  private:
   // See definition for lifetime information.
   class CacheStorageObserver;
@@ -184,6 +189,8 @@
   Response FindStoragePartition(const Maybe<std::string>& browser_context_id,
                                 StoragePartition** storage_partition);
 
+  void ResetAttributionReportingLocalTestingMode();
+
   std::unique_ptr<Storage::Frontend> frontend_;
   StoragePartition* storage_partition_{nullptr};
   RenderFrameHostImpl* frame_host_ = nullptr;
diff --git a/content/browser/devtools/protocol_config.json b/content/browser/devtools/protocol_config.json
index 09e0729..80de7c9 100644
--- a/content/browser/devtools/protocol_config.json
+++ b/content/browser/devtools/protocol_config.json
@@ -100,7 +100,7 @@
             {
                 "domain": "Storage",
                 "exclude": ["runBounceTrackingMitigations"],
-                "async": ["getUsageAndQuota", "clearDataForOrigin", "clearDataForStorageKey", "getCookies", "setCookies", "clearCookies", "overrideQuotaForOrigin", "getTrustTokens", "clearTrustTokens", "getInterestGroupDetails", "getSharedStorageMetadata", "getSharedStorageEntries", "setSharedStorageEntry", "deleteSharedStorageEntry", "clearSharedStorageEntries", "resetSharedStorageBudget", "getStorageBucketList"]
+                "async": ["getUsageAndQuota", "clearDataForOrigin", "clearDataForStorageKey", "getCookies", "setCookies", "clearCookies", "overrideQuotaForOrigin", "getTrustTokens", "clearTrustTokens", "getInterestGroupDetails", "getSharedStorageMetadata", "getSharedStorageEntries", "setSharedStorageEntry", "deleteSharedStorageEntry", "clearSharedStorageEntries", "resetSharedStorageBudget", "getStorageBucketList", "setAttributionReportingLocalTestingMode"]
             },
             {
                 "domain": "SystemInfo",
diff --git a/content/browser/file_system_access/file_system_access_manager_impl.h b/content/browser/file_system_access/file_system_access_manager_impl.h
index 9ee18d60..73253dc8 100644
--- a/content/browser/file_system_access/file_system_access_manager_impl.h
+++ b/content/browser/file_system_access/file_system_access_manager_impl.h
@@ -545,7 +545,7 @@
   const scoped_refptr<ChromeBlobStorageContext> blob_context_;
   base::SequenceBound<storage::FileSystemOperationRunner> operation_runner_
       GUARDED_BY_CONTEXT(sequence_checker_);
-  raw_ptr<FileSystemAccessPermissionContext, DanglingUntriaged>
+  raw_ptr<FileSystemAccessPermissionContext, DanglingAcrossTasks>
       permission_context_ GUARDED_BY_CONTEXT(sequence_checker_);
 
   // All the mojo receivers for this FileSystemAccessManager itself. Keeps
diff --git a/content/browser/loader/navigation_url_loader_impl.h b/content/browser/loader/navigation_url_loader_impl.h
index 731783a..6f5e26f 100644
--- a/content/browser/loader/navigation_url_loader_impl.h
+++ b/content/browser/loader/navigation_url_loader_impl.h
@@ -233,7 +233,7 @@
   raw_ptr<NavigationURLLoaderDelegate, DanglingUntriaged> delegate_;
   raw_ptr<BrowserContext> browser_context_;
   raw_ptr<StoragePartitionImpl> storage_partition_;
-  raw_ptr<ServiceWorkerMainResourceHandle, DanglingUntriaged>
+  raw_ptr<ServiceWorkerMainResourceHandle, DanglingAcrossTasks>
       service_worker_handle_;
 
   std::unique_ptr<network::ResourceRequest> resource_request_;
diff --git a/content/browser/media/media_devices_util.cc b/content/browser/media/media_devices_util.cc
index 5537942..f05f41f1 100644
--- a/content/browser/media/media_devices_util.cc
+++ b/content/browser/media/media_devices_util.cc
@@ -176,6 +176,13 @@
     return;
   }
 
+  // Check that the frame is not in the prerendering state. Media playback is
+  // deferred while prerendering. So this check should pass and ensures the
+  // condition to call GetPageUkmSourceId below as the data collection policy
+  // disallows recording UKMs while prerendering.
+  CHECK(!frame_host->IsInLifecycleState(
+      RenderFrameHost::LifecycleState::kPrerendering));
+
   net::SiteForCookies site_for_cookies = frame_host->ComputeSiteForCookies();
   url::Origin origin = frame_host->GetLastCommittedOrigin();
   bool has_focus = frame_host->GetView() && frame_host->GetView()->HasFocus();
diff --git a/content/browser/notifications/platform_notification_context_impl.h b/content/browser/notifications/platform_notification_context_impl.h
index bbd2aa78..64de8c4 100644
--- a/content/browser/notifications/platform_notification_context_impl.h
+++ b/content/browser/notifications/platform_notification_context_impl.h
@@ -334,7 +334,7 @@
       const scoped_refptr<base::SequencedTaskRunner>& task_runner);
 
   base::FilePath path_;
-  raw_ptr<BrowserContext, DanglingUntriaged> browser_context_;
+  raw_ptr<BrowserContext, DanglingAcrossTasks> browser_context_;
 
   scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
 
diff --git a/content/browser/notifications/platform_notification_service_proxy.h b/content/browser/notifications/platform_notification_service_proxy.h
index 26cf026..45e3642 100644
--- a/content/browser/notifications/platform_notification_service_proxy.h
+++ b/content/browser/notifications/platform_notification_service_proxy.h
@@ -116,8 +116,9 @@
       scoped_refptr<ServiceWorkerRegistration> registration);
 
   scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
-  raw_ptr<BrowserContext, DanglingUntriaged> browser_context_;
-  raw_ptr<PlatformNotificationService, DanglingUntriaged> notification_service_;
+  raw_ptr<BrowserContext, DanglingAcrossTasks> browser_context_;
+  raw_ptr<PlatformNotificationService, DanglingAcrossTasks>
+      notification_service_;
   base::WeakPtrFactory<PlatformNotificationServiceProxy> weak_ptr_factory_ui_{
       this};
   base::WeakPtrFactory<PlatformNotificationServiceProxy> weak_ptr_factory_io_{
diff --git a/content/browser/preloading/prerenderer_impl.cc b/content/browser/preloading/prerenderer_impl.cc
index 1ed8dd2..e4ba62388 100644
--- a/content/browser/preloading/prerenderer_impl.cc
+++ b/content/browser/preloading/prerenderer_impl.cc
@@ -139,7 +139,7 @@
     // For now, start the first candidate for a URL only if there are no
     // matching prerenders. We could be cleverer in the future.
     if (matching_prerenders.empty()) {
-      DCHECK_GT(matching_candidates.size(), 0u);
+      CHECK_GT(matching_candidates.size(), 0u);
       candidates_to_start.push_back(std::move(matching_candidates[0]));
     }
 
@@ -179,7 +179,11 @@
 
 bool PrerendererImpl::MaybePrerender(
     const blink::mojom::SpeculationCandidatePtr& candidate) {
-  DCHECK_EQ(candidate->action, blink::mojom::SpeculationAction::kPrerender);
+  CHECK_EQ(candidate->action, blink::mojom::SpeculationAction::kPrerender);
+
+  // Prerendering frames should not trigger any prerender request.
+  CHECK(!render_frame_host_->IsInLifecycleState(
+      RenderFrameHost::LifecycleState::kPrerendering));
 
   if (!registry_)
     return false;
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index c380910e..4bcf6c0a 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -11420,6 +11420,10 @@
 
 void RenderFrameHostImpl::BindVideoEncoderMetricsProviderReceiver(
     mojo::PendingReceiver<media::mojom::VideoEncoderMetricsProvider> receiver) {
+  // Ensure the frame is not in the prerendering state as we don't record UKM
+  // while prerendering. This is ensured as the BrowserInterfaceBinders defers
+  // binding until the frame's activation.
+  CHECK(!IsInLifecycleState(LifecycleState::kPrerendering));
   media::VideoEncoderMetricsProvider::Create(GetPageUkmSourceId(),
                                              std::move(receiver));
 }
diff --git a/content/browser/renderer_host/render_widget_host_browsertest.cc b/content/browser/renderer_host/render_widget_host_browsertest.cc
index 452f120..2cdfb07 100644
--- a/content/browser/renderer_host/render_widget_host_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_browsertest.cc
@@ -22,6 +22,7 @@
 #include "content/browser/renderer_host/render_widget_host_input_event_router.h"
 #include "content/browser/renderer_host/render_widget_host_view_base.h"
 #include "content/browser/web_contents/web_contents_impl.h"
+#include "content/common/content_navigation_policy.h"
 #include "content/public/browser/render_widget_host_observer.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -864,7 +865,9 @@
       </style>
       <div id='target'></div>)HTML";
 
+  LoadStopObserver load_stop_observer(shell()->web_contents());
   EXPECT_TRUE(NavigateToURL(shell(), GURL(kTestPageURL)));
+  load_stop_observer.Wait();
 
   const gfx::Size root_view_size = view()->GetVisibleViewportSize();
   const int kDisplayFeatureLength = 10;
@@ -872,9 +875,11 @@
   DisplayFeature emulated_display_feature{
       DisplayFeature::Orientation::kVertical, offset,
       /* mask_length */ kDisplayFeatureLength};
-  MockDisplayFeature mock_display_feature(view());
-  mock_display_feature.SetDisplayFeature(&emulated_display_feature);
-  host()->SynchronizeVisualProperties();
+  {
+    MockDisplayFeature mock_display_feature(view());
+    mock_display_feature.SetDisplayFeature(&emulated_display_feature);
+    host()->SynchronizeVisualProperties();
+  }
 
   EXPECT_EQ(
       base::NumberToString(emulated_display_feature.offset) + "px",
@@ -882,9 +887,24 @@
 
   // Ensure that the environment variables have the correct values in the new
   // document that is created on reloading the page.
-  LoadStopObserver load_stop_observer(shell()->web_contents());
+  LoadStopObserver load_stop_observer2(shell()->web_contents());
+  TestNavigationManager navigation_manager(shell()->web_contents(),
+                                           GURL(kTestPageURL));
   shell()->Reload();
-  load_stop_observer.Wait();
+  EXPECT_TRUE(navigation_manager.WaitForResponse());
+  if (ShouldCreateNewHostForAllFrames()) {
+    // When RenderDocument is enabled, a new RenderWidgetHost will be created
+    // after the reload, so we need to call SynchronizeVisualProperties() again.
+    RenderWidgetHostImpl* target_rwh = static_cast<RenderWidgetHostImpl*>(
+        navigation_manager.GetNavigationHandle()
+            ->GetRenderFrameHost()
+            ->GetRenderWidgetHost());
+    MockDisplayFeature mock_display_feature(target_rwh->GetView());
+    mock_display_feature.SetDisplayFeature(&emulated_display_feature);
+    target_rwh->SynchronizeVisualProperties();
+  }
+  EXPECT_TRUE(navigation_manager.WaitForNavigationFinished());
+  load_stop_observer2.Wait();
 
   EXPECT_EQ(
       base::NumberToString(emulated_display_feature.offset) + "px",
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index c01cc787..e811438 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -1623,7 +1623,9 @@
 
 ukm::SourceId RenderWidgetHostViewAura::GetClientSourceForMetrics() const {
   RenderFrameHostImpl* frame = GetFocusedFrame();
-  if (frame) {
+  // ukm::SourceId is not available while prerendering.
+  if (frame && !frame->IsInLifecycleState(
+                   RenderFrameHost::LifecycleState::kPrerendering)) {
     return frame->GetPageUkmSourceId();
   }
   return ukm::SourceId();
diff --git a/content/browser/webui/web_ui_url_loader_factory.cc b/content/browser/webui/web_ui_url_loader_factory.cc
index 0f189ba4..a911283 100644
--- a/content/browser/webui/web_ui_url_loader_factory.cc
+++ b/content/browser/webui/web_ui_url_loader_factory.cc
@@ -399,7 +399,7 @@
         scheme_(scheme),
         allowed_hosts_(std::move(allowed_hosts)) {}
 
-  raw_ptr<BrowserContext, DanglingUntriaged> browser_context_;
+  raw_ptr<BrowserContext, DanglingAcrossTasks> browser_context_;
   int const frame_tree_node_id_;
   const std::string scheme_;
   const base::flat_set<std::string> allowed_hosts_;  // if empty all allowed.
diff --git a/content/public/browser/browser_message_filter.h b/content/public/browser/browser_message_filter.h
index 5bb4d89..2fe2caf4 100644
--- a/content/public/browser/browser_message_filter.h
+++ b/content/public/browser/browser_message_filter.h
@@ -142,7 +142,7 @@
   // classes. Internal keeps a reference to this class, which is why there's a
   // weak pointer back. This class could outlive Internal based on what the
   // child class does in its OnDestruct method.
-  raw_ptr<Internal, DanglingUntriaged> internal_ = nullptr;
+  raw_ptr<Internal, DanglingAcrossTasks> internal_ = nullptr;
 
   raw_ptr<IPC::Sender> sender_ = nullptr;
   base::Process peer_process_;
diff --git a/content/public/test/browser_test_base.h b/content/public/test/browser_test_base.h
index 4b38c78d..cd4823f 100644
--- a/content/public/test/browser_test_base.h
+++ b/content/public/test/browser_test_base.h
@@ -305,7 +305,7 @@
 
   bool allow_network_access_to_host_resolutions_ = false;
 
-  raw_ptr<BrowserMainParts, DanglingUntriaged> browser_main_parts_ = nullptr;
+  raw_ptr<BrowserMainParts, DanglingAcrossTasks> browser_main_parts_ = nullptr;
 
 #if BUILDFLAG(IS_POSIX)
   bool handle_sigterm_;
diff --git a/dbus/bus.h b/dbus/bus.h
index 139a8ae2..c4278eef 100644
--- a/dbus/bus.h
+++ b/dbus/bus.h
@@ -729,7 +729,7 @@
   const ConnectionType connection_type_;
   scoped_refptr<base::SequencedTaskRunner> dbus_task_runner_;
   base::WaitableEvent on_shutdown_;
-  raw_ptr<DBusConnection, DanglingUntriaged> connection_;
+  raw_ptr<DBusConnection, DanglingAcrossTasks> connection_;
 
   base::PlatformThreadId origin_thread_id_;
   scoped_refptr<base::SequencedTaskRunner> origin_task_runner_;
diff --git a/dbus/message.h b/dbus/message.h
index 2a265b39..4e70da9 100644
--- a/dbus/message.h
+++ b/dbus/message.h
@@ -140,7 +140,7 @@
   std::string ToStringInternal(const std::string& indent,
                                MessageReader* reader);
 
-  raw_ptr<DBusMessage, DanglingUntriaged> raw_message_;
+  raw_ptr<DBusMessage, DanglingAcrossTasks> raw_message_;
 };
 
 // MessageCall is a type of message used for calling a method via D-Bus.
diff --git a/docs/windows_build_instructions.md b/docs/windows_build_instructions.md
index 95911e9..9930541 100644
--- a/docs/windows_build_instructions.md
+++ b/docs/windows_build_instructions.md
@@ -133,9 +133,11 @@
 $ git config --global branch.autosetuprebase always
 ```
 
-Create a `chromium` directory for the checkout and change to it (you can call
-this whatever you like and put it wherever you like, as
-long as the full path has no spaces):
+Create a `chromium` directory for the checkout and change to it. You can call
+this whatever you like and put it wherever you like, as long as the full path
+has no spaces. However there are some performance benefits for Googlers in
+placing the directory under `C:\src\`
+(See [Why is my build slow?](https://chromium.googlesource.com/chromium/src/+/main/docs/windows_build_instructions.md#why-is-my-build-slow)).
 
 ```shell
 $ mkdir chromium && cd chromium
diff --git a/extensions/browser/api/declarative/rules_registry_service.h b/extensions/browser/api/declarative/rules_registry_service.h
index eb168af2..ec91182 100644
--- a/extensions/browser/api/declarative/rules_registry_service.h
+++ b/extensions/browser/api/declarative/rules_registry_service.h
@@ -170,7 +170,7 @@
 
   // Weak pointer into rule_registries_ to make it easier to handle content rule
   // conditions.
-  raw_ptr<ContentRulesRegistry, DanglingUntriaged> content_rules_registry_;
+  raw_ptr<ContentRulesRegistry, DanglingAcrossTasks> content_rules_registry_;
 
   // Listen to extension load, unloaded notification.
   base::ScopedObservation<ExtensionRegistry, ExtensionRegistryObserver>
diff --git a/extensions/browser/api/webcam_private/webcam_private_api_chromeos.cc b/extensions/browser/api/webcam_private/webcam_private_api_chromeos.cc
index e1b7bf3a..841c009 100644
--- a/extensions/browser/api/webcam_private/webcam_private_api_chromeos.cc
+++ b/extensions/browser/api/webcam_private/webcam_private_api_chromeos.cc
@@ -9,7 +9,6 @@
 #include "base/functional/bind.h"
 #include "base/lazy_instance.h"
 #include "components/media_device_salt/media_device_salt_service.h"
-#include "components/media_device_salt/media_device_salt_service_factory.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/media_device_id.h"
 #include "content/public/browser/resource_context.h"
@@ -17,6 +16,7 @@
 #include "extensions/browser/api/webcam_private/ip_webcam.h"
 #include "extensions/browser/api/webcam_private/v4l2_webcam.h"
 #include "extensions/browser/api/webcam_private/visca_webcam.h"
+#include "extensions/browser/extensions_browser_client.h"
 #include "extensions/browser/process_manager.h"
 #include "extensions/browser/process_manager_factory.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
@@ -114,12 +114,19 @@
     return;
   }
 
-  media_device_salt::MediaDeviceSaltService* salt_service =
-      media_device_salt::MediaDeviceSaltServiceFactory::GetInstance()
-          ->GetForBrowserContext(browser_context_);
-  salt_service->GetSalt(base::BindOnce(
-      &WebcamPrivateAPI::GetDeviceIdOnUIThread, weak_ptr_factory_.GetWeakPtr(),
-      extension_id, webcam_id, std::move(callback)));
+  if (media_device_salt::MediaDeviceSaltService* salt_service =
+          ExtensionsBrowserClient::Get()->GetMediaDeviceSaltService(
+              browser_context_)) {
+    salt_service->GetSalt(
+        base::BindOnce(&WebcamPrivateAPI::GetDeviceIdOnUIThread,
+                       weak_ptr_factory_.GetWeakPtr(), extension_id, webcam_id,
+                       std::move(callback)));
+  } else {
+    // If the embedder does not provide a salt service, use the browser
+    // context's unique ID as salt.
+    GetDeviceIdOnUIThread(extension_id, webcam_id, std::move(callback),
+                          browser_context_->UniqueId());
+  }
 }
 
 void WebcamPrivateAPI::GetDeviceIdOnUIThread(
@@ -208,12 +215,18 @@
     const std::string& extension_id,
     const std::string& device_id,
     base::OnceCallback<void(const std::string&)> webcam_id_callback) {
-  media_device_salt::MediaDeviceSaltService* salt_service =
-      media_device_salt::MediaDeviceSaltServiceFactory::GetInstance()
-          ->GetForBrowserContext(browser_context_);
-  salt_service->GetSalt(base::BindOnce(
-      &WebcamPrivateAPI::FinalizeGetWebcamId, weak_ptr_factory_.GetWeakPtr(),
-      extension_id, device_id, std::move(webcam_id_callback)));
+  if (media_device_salt::MediaDeviceSaltService* salt_service =
+          ExtensionsBrowserClient::Get()->GetMediaDeviceSaltService(
+              browser_context_)) {
+    salt_service->GetSalt(base::BindOnce(
+        &WebcamPrivateAPI::FinalizeGetWebcamId, weak_ptr_factory_.GetWeakPtr(),
+        extension_id, device_id, std::move(webcam_id_callback)));
+  } else {
+    // If the embedder does not provide a salt service, use the browser
+    // context's unique ID as salt.
+    FinalizeGetWebcamId(extension_id, device_id, std::move(webcam_id_callback),
+                        browser_context_->UniqueId());
+  }
 }
 
 void WebcamPrivateAPI::FinalizeGetWebcamId(
diff --git a/extensions/browser/content_verifier.h b/extensions/browser/content_verifier.h
index bb41a42..8a2ddff 100644
--- a/extensions/browser/content_verifier.h
+++ b/extensions/browser/content_verifier.h
@@ -211,7 +211,7 @@
   // Updated and accessed only on IO thread.
   bool shutdown_on_io_ = false;
 
-  const raw_ptr<content::BrowserContext, DanglingUntriaged> context_;
+  const raw_ptr<content::BrowserContext, DanglingAcrossTasks> context_;
 
   // Guards creation of |hash_helper_|, limiting number of creation to <= 1.
   // Accessed only on IO thread.
diff --git a/extensions/browser/extension_function_dispatcher.h b/extensions/browser/extension_function_dispatcher.h
index f7237b3..224f550 100644
--- a/extensions/browser/extension_function_dispatcher.h
+++ b/extensions/browser/extension_function_dispatcher.h
@@ -154,7 +154,7 @@
 
   raw_ptr<content::BrowserContext, DanglingUntriaged> browser_context_;
 
-  raw_ptr<Delegate, DanglingUntriaged> delegate_;
+  raw_ptr<Delegate, DanglingAcrossTasks> delegate_;
 
   // This map doesn't own either the keys or the values. When a RenderFrameHost
   // instance goes away, the corresponding entry in this map (if exists) will be
diff --git a/extensions/browser/extension_prefs.h b/extensions/browser/extension_prefs.h
index 9e25be7..055d02e 100644
--- a/extensions/browser/extension_prefs.h
+++ b/extensions/browser/extension_prefs.h
@@ -944,7 +944,7 @@
   base::FilePath install_directory_;
 
   // Weak pointer, owned by BrowserContext.
-  raw_ptr<ExtensionPrefValueMap, DanglingUntriaged> extension_pref_value_map_;
+  raw_ptr<ExtensionPrefValueMap, DanglingAcrossTasks> extension_pref_value_map_;
 
   raw_ptr<base::Clock> clock_;
 
diff --git a/extensions/browser/extensions_browser_client.cc b/extensions/browser/extensions_browser_client.cc
index 4cf9c169..25e577f 100644
--- a/extensions/browser/extensions_browser_client.cc
+++ b/extensions/browser/extensions_browser_client.cc
@@ -244,4 +244,10 @@
 void ExtensionsBrowserClient::CreatePasswordReuseDetectionManager(
     content::WebContents* web_contents) const {}
 
+media_device_salt::MediaDeviceSaltService*
+ExtensionsBrowserClient::GetMediaDeviceSaltService(
+    content::BrowserContext* context) {
+  return nullptr;
+}
+
 }  // namespace extensions
diff --git a/extensions/browser/extensions_browser_client.h b/extensions/browser/extensions_browser_client.h
index fbef1f4..d4e2981 100644
--- a/extensions/browser/extensions_browser_client.h
+++ b/extensions/browser/extensions_browser_client.h
@@ -70,6 +70,10 @@
 class CancelableTaskTracker;
 }  // namespace base
 
+namespace media_device_salt {
+class MediaDeviceSaltService;
+}  // namespace media_device_salt
+
 namespace extensions {
 
 class ComponentExtensionResourceManager;
@@ -516,6 +520,11 @@
   virtual void CreatePasswordReuseDetectionManager(
       content::WebContents* web_contents) const;
 
+  // Returns a service that provides persistent salts for generating media
+  // device IDs. Can be null if the embedder does not support persistent salts.
+  virtual media_device_salt::MediaDeviceSaltService* GetMediaDeviceSaltService(
+      content::BrowserContext* context);
+
  private:
   std::vector<std::unique_ptr<ExtensionsBrowserAPIProvider>> providers_;
 };
diff --git a/extensions/shell/browser/shell_content_browser_client.h b/extensions/shell/browser/shell_content_browser_client.h
index 60bb55e..d5cc865 100644
--- a/extensions/shell/browser/shell_content_browser_client.h
+++ b/extensions/shell/browser/shell_content_browser_client.h
@@ -157,7 +157,7 @@
   const Extension* GetExtension(content::SiteInstance* site_instance);
 
   // Owned by content::BrowserMainLoop.
-  raw_ptr<ShellBrowserMainParts, DanglingUntriaged> browser_main_parts_;
+  raw_ptr<ShellBrowserMainParts, DanglingAcrossTasks> browser_main_parts_;
 
   // Owned by ShellBrowserMainParts.
   raw_ptr<ShellBrowserMainDelegate, DanglingUntriaged> browser_main_delegate_;
diff --git a/gin/per_isolate_data.h b/gin/per_isolate_data.h
index eddf82a..7d7ee79 100644
--- a/gin/per_isolate_data.h
+++ b/gin/per_isolate_data.h
@@ -88,7 +88,7 @@
 
   // PerIsolateData doesn't actually own |isolate_|. Instead, the isolate is
   // owned by the IsolateHolder, which also owns the PerIsolateData.
-  raw_ptr<v8::Isolate, DanglingUntriaged> isolate_;
+  raw_ptr<v8::Isolate, DanglingAcrossTasks> isolate_;
   raw_ptr<v8::ArrayBuffer::Allocator, DanglingUntriaged> allocator_;
   ObjectTemplateMap object_templates_;
   FunctionTemplateMap function_templates_;
diff --git a/gin/public/isolate_holder.h b/gin/public/isolate_holder.h
index 10caab6..39f3c07b 100644
--- a/gin/public/isolate_holder.h
+++ b/gin/public/isolate_holder.h
@@ -143,7 +143,7 @@
   void SetUp(scoped_refptr<base::SingleThreadTaskRunner> task_runner);
 
   std::unique_ptr<v8::SnapshotCreator> snapshot_creator_;
-  raw_ptr<v8::Isolate, DanglingUntriaged> isolate_;
+  raw_ptr<v8::Isolate, DanglingAcrossTasks> isolate_;
   std::unique_ptr<PerIsolateData> isolate_data_;
   std::unique_ptr<V8IsolateMemoryDumpProvider> isolate_memory_dump_provider_;
   AccessMode access_mode_;
diff --git a/gpu/command_buffer/client/DEPS b/gpu/command_buffer/client/DEPS
index f1b9fd6a..ca1fa12 100644
--- a/gpu/command_buffer/client/DEPS
+++ b/gpu/command_buffer/client/DEPS
@@ -4,6 +4,5 @@
   "+components/nacl/common/buildflags.h",
   "+third_party/skia",
   "+components/viz/common/resources/resource_format.h",
-  "+components/viz/common/resources/resource_format_utils.h",
   "+components/viz/common/resources/shared_image_format.h",
 ]
diff --git a/gpu/command_buffer/client/raster_implementation_gles.cc b/gpu/command_buffer/client/raster_implementation_gles.cc
index 44adf17..f6250c6 100644
--- a/gpu/command_buffer/client/raster_implementation_gles.cc
+++ b/gpu/command_buffer/client/raster_implementation_gles.cc
@@ -17,7 +17,6 @@
 #include "cc/paint/paint_op_buffer_serializer.h"
 #include "cc/paint/transfer_cache_entry.h"
 #include "cc/paint/transfer_cache_serialize_helper.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "gpu/command_buffer/client/gl_helper.h"
 #include "gpu/command_buffer/client/gles2_implementation.h"
diff --git a/gpu/command_buffer/client/raster_implementation_gles_unittest.cc b/gpu/command_buffer/client/raster_implementation_gles_unittest.cc
index e61de24..0a5c9b2 100644
--- a/gpu/command_buffer/client/raster_implementation_gles_unittest.cc
+++ b/gpu/command_buffer/client/raster_implementation_gles_unittest.cc
@@ -15,7 +15,6 @@
 #include "base/containers/flat_map.h"
 #include "cc/paint/display_item_list.h"
 #include "cc/paint/image_provider.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "gpu/command_buffer/client/client_test_helper.h"
 #include "gpu/command_buffer/client/context_support.h"
diff --git a/gpu/command_buffer/common/DEPS b/gpu/command_buffer/common/DEPS
index a48b092..57d9fa0c 100644
--- a/gpu/command_buffer/common/DEPS
+++ b/gpu/command_buffer/common/DEPS
@@ -1,6 +1,5 @@
 include_rules = [
   "+components/viz/common/resources/resource_format.h",
-  "+components/viz/common/resources/resource_format_utils.h",
   "+third_party/skia/include",
 ]
 specific_include_rules = {
diff --git a/gpu/command_buffer/service/DEPS b/gpu/command_buffer/service/DEPS
index 3f5062f..a373fd73 100644
--- a/gpu/command_buffer/service/DEPS
+++ b/gpu/command_buffer/service/DEPS
@@ -10,7 +10,6 @@
   "+components/viz/common/gpu/vulkan_context_provider.h",
   "+components/viz/common/resources/resource_format.h",
   "+components/viz/common/resources/shared_image_format.h",
-  "+components/viz/common/resources/resource_format_utils.h",
   "+components/viz/common/resources/resource_sizes.h",
   "+components/viz/common/resources/shared_image_format.h",
   "+components/viz/common/resources/shared_image_format_utils.h",
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
index f352ac9..7cb4361 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
@@ -7,7 +7,6 @@
 
 #include "base/command_line.h"
 #include "base/strings/string_number_conversions.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "gpu/command_buffer/common/gles2_cmd_format.h"
 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
 #include "gpu/command_buffer/common/id_allocator.h"
diff --git a/gpu/command_buffer/service/gles2_external_framebuffer_unittest.cc b/gpu/command_buffer/service/gles2_external_framebuffer_unittest.cc
index 215e634..73d8c966 100644
--- a/gpu/command_buffer/service/gles2_external_framebuffer_unittest.cc
+++ b/gpu/command_buffer/service/gles2_external_framebuffer_unittest.cc
@@ -8,7 +8,6 @@
 #include "base/command_line.h"
 #include "build/build_config.h"
 #include "components/viz/common/resources/resource_format.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "gpu/command_buffer/common/mailbox.h"
 #include "gpu/command_buffer/common/shared_image_usage.h"
 #include "gpu/command_buffer/service/service_utils.h"
diff --git a/gpu/command_buffer/service/raster_decoder_unittest_base.cc b/gpu/command_buffer/service/raster_decoder_unittest_base.cc
index 06fc541..6723ae82 100644
--- a/gpu/command_buffer/service/raster_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/raster_decoder_unittest_base.cc
@@ -17,7 +17,6 @@
 #include "base/functional/callback_helpers.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
 #include "gpu/command_buffer/common/raster_cmd_format.h"
 #include "gpu/command_buffer/common/shared_image_usage.h"
diff --git a/gpu/command_buffer/service/shared_image/d3d_image_backing_factory_unittest.cc b/gpu/command_buffer/service/shared_image/d3d_image_backing_factory_unittest.cc
index 9957f3c..1b76778 100644
--- a/gpu/command_buffer/service/shared_image/d3d_image_backing_factory_unittest.cc
+++ b/gpu/command_buffer/service/shared_image/d3d_image_backing_factory_unittest.cc
@@ -15,7 +15,6 @@
 #include "base/test/test_timeouts.h"
 #include "cc/test/pixel_comparator.h"
 #include "cc/test/pixel_test_utils.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/shared_image_format.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
 #include "gpu/command_buffer/common/shared_image_usage.h"
diff --git a/gpu/command_buffer/service/shared_image/gl_ozone_image_representation.cc b/gpu/command_buffer/service/shared_image/gl_ozone_image_representation.cc
index 1caf040..614e715e 100644
--- a/gpu/command_buffer/service/shared_image/gl_ozone_image_representation.cc
+++ b/gpu/command_buffer/service/shared_image/gl_ozone_image_representation.cc
@@ -8,7 +8,6 @@
 #include "base/check.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/scoped_refptr.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "gpu/command_buffer/service/gl_utils.h"
 #include "gpu/command_buffer/service/memory_tracking.h"
 #include "gpu/command_buffer/service/shared_image/ozone_image_backing.h"
diff --git a/gpu/command_buffer/service/shared_image/iosurface_image_backing.mm b/gpu/command_buffer/service/shared_image/iosurface_image_backing.mm
index 6824784..472f5b0 100644
--- a/gpu/command_buffer/service/shared_image/iosurface_image_backing.mm
+++ b/gpu/command_buffer/service/shared_image/iosurface_image_backing.mm
@@ -9,7 +9,6 @@
 #include "base/memory/scoped_policy.h"
 #include "base/trace_event/memory_dump_manager.h"
 #include "components/viz/common/gpu/metal_context_provider.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/resource_sizes.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
 #include "gpu/command_buffer/common/shared_image_trace_utils.h"
diff --git a/gpu/command_buffer/service/shared_image/iosurface_image_backing_factory.mm b/gpu/command_buffer/service/shared_image/iosurface_image_backing_factory.mm
index 7b9a513..adfef30 100644
--- a/gpu/command_buffer/service/shared_image/iosurface_image_backing_factory.mm
+++ b/gpu/command_buffer/service/shared_image/iosurface_image_backing_factory.mm
@@ -6,7 +6,6 @@
 
 #include "base/memory/scoped_refptr.h"
 #include "build/build_config.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/resource_sizes.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
 #include "gpu/command_buffer/common/shared_image_usage.h"
diff --git a/gpu/command_buffer/service/shared_image/shared_image_format_service_utils.cc b/gpu/command_buffer/service/shared_image/shared_image_format_service_utils.cc
index 175ed6f..f3160fe 100644
--- a/gpu/command_buffer/service/shared_image/shared_image_format_service_utils.cc
+++ b/gpu/command_buffer/service/shared_image/shared_image_format_service_utils.cc
@@ -13,7 +13,6 @@
 #include "base/notreached.h"
 #include "build/buildflag.h"
 #include "components/viz/common/resources/resource_format.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
 
 namespace gpu {
diff --git a/gpu/command_buffer/service/shared_image/shared_image_format_service_utils_mac.mm b/gpu/command_buffer/service/shared_image/shared_image_format_service_utils_mac.mm
index 3346641..01161c3d 100644
--- a/gpu/command_buffer/service/shared_image/shared_image_format_service_utils_mac.mm
+++ b/gpu/command_buffer/service/shared_image/shared_image_format_service_utils_mac.mm
@@ -8,7 +8,6 @@
 
 #include "base/check_op.h"
 #include "base/logging.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 
 namespace gpu {
 
diff --git a/gpu/command_buffer/service/shared_image/shared_image_representation.cc b/gpu/command_buffer/service/shared_image/shared_image_representation.cc
index 9ba20c6..6e31238 100644
--- a/gpu/command_buffer/service/shared_image/shared_image_representation.cc
+++ b/gpu/command_buffer/service/shared_image/shared_image_representation.cc
@@ -7,7 +7,6 @@
 #include "base/debug/dump_without_crashing.h"
 #include "base/strings/stringprintf.h"
 #include "build/build_config.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
 #include "gpu/command_buffer/service/shared_context_state.h"
 #include "gpu/command_buffer/service/shared_image/shared_image_format_service_utils.h"
diff --git a/gpu/command_buffer/service/shared_image/shared_image_test_base.cc b/gpu/command_buffer/service/shared_image/shared_image_test_base.cc
index c8bc44e5..3ed3b2a9 100644
--- a/gpu/command_buffer/service/shared_image/shared_image_test_base.cc
+++ b/gpu/command_buffer/service/shared_image/shared_image_test_base.cc
@@ -9,7 +9,6 @@
 #include "base/command_line.h"
 #include "cc/test/pixel_comparator.h"
 #include "cc/test/pixel_test_utils.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
 #include "gpu/command_buffer/service/service_utils.h"
 #include "gpu/command_buffer/service/shared_image/shared_image_representation.h"
diff --git a/gpu/command_buffer/service/shared_image/skia_gl_image_representation.cc b/gpu/command_buffer/service/shared_image/skia_gl_image_representation.cc
index b135341..1365e90 100644
--- a/gpu/command_buffer/service/shared_image/skia_gl_image_representation.cc
+++ b/gpu/command_buffer/service/shared_image/skia_gl_image_representation.cc
@@ -6,7 +6,6 @@
 
 #include "base/check_op.h"
 #include "base/memory/ptr_util.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
 #include "gpu/command_buffer/service/shared_context_state.h"
 #include "gpu/command_buffer/service/shared_image/shared_image_format_service_utils.h"
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 fac11002..4a81c023 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
@@ -7,7 +7,6 @@
 #include <utility>
 
 #include "base/task/single_thread_task_runner.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/resource_sizes.h"
 #include "gpu/command_buffer/common/shared_image_usage.h"
 #include "gpu/command_buffer/service/abstract_texture_android.h"
diff --git a/gpu/command_buffer/service/shared_image/wrapped_sk_image_backing_factory_unittest.cc b/gpu/command_buffer/service/shared_image/wrapped_sk_image_backing_factory_unittest.cc
index 9cf60ef7d..00160b3 100644
--- a/gpu/command_buffer/service/shared_image/wrapped_sk_image_backing_factory_unittest.cc
+++ b/gpu/command_buffer/service/shared_image/wrapped_sk_image_backing_factory_unittest.cc
@@ -8,7 +8,6 @@
 #include "build/build_config.h"
 #include "cc/test/pixel_comparator.h"
 #include "cc/test/pixel_test_utils.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/shared_image_format.h"
 #include "gpu/command_buffer/common/mailbox.h"
 #include "gpu/command_buffer/common/shared_image_usage.h"
diff --git a/gpu/command_buffer/service/skia_utils.cc b/gpu/command_buffer/service/skia_utils.cc
index 537a0c1d..d9bbfb9f 100644
--- a/gpu/command_buffer/service/skia_utils.cc
+++ b/gpu/command_buffer/service/skia_utils.cc
@@ -8,7 +8,6 @@
 #include "base/logging.h"
 #include "build/build_config.h"
 #include "components/viz/common/resources/resource_format.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "gpu/command_buffer/service/feature_info.h"
 #include "gpu/command_buffer/service/shared_context_state.h"
 #include "gpu/config/gpu_finch_features.h"
diff --git a/gpu/command_buffer/service/transfer_buffer_manager.h b/gpu/command_buffer/service/transfer_buffer_manager.h
index c77fecf..3a01918 100644
--- a/gpu/command_buffer/service/transfer_buffer_manager.h
+++ b/gpu/command_buffer/service/transfer_buffer_manager.h
@@ -44,7 +44,7 @@
   typedef base::flat_map<int32_t, scoped_refptr<Buffer>> BufferMap;
   BufferMap registered_buffers_;
   size_t shared_memory_bytes_allocated_;
-  raw_ptr<MemoryTracker, DanglingUntriaged> memory_tracker_;
+  raw_ptr<MemoryTracker, DanglingAcrossTasks> memory_tracker_;
 };
 
 }  // namespace gpu
diff --git a/gpu/ipc/client/DEPS b/gpu/ipc/client/DEPS
index 919bf7a4..4bb85ef 100644
--- a/gpu/ipc/client/DEPS
+++ b/gpu/ipc/client/DEPS
@@ -18,7 +18,6 @@
     "+components/viz/test/test_gpu_memory_buffer_manager.h",
   ],
   "client_shared_image_interface.cc": [
-    "+components/viz/common/resources/resource_format_utils.h",
     "+components/viz/common/resources/shared_image_format.h",
     "+components/viz/common/resources/shared_image_format_utils.h",
   ]
diff --git a/gpu/ipc/service/DEPS b/gpu/ipc/service/DEPS
index 024b81c..4cbd6a9 100644
--- a/gpu/ipc/service/DEPS
+++ b/gpu/ipc/service/DEPS
@@ -6,7 +6,6 @@
   "+components/viz/common/gpu/vulkan_context_provider.h",
   "+components/viz/common/overlay_state/win/overlay_state_service.h",
   "+components/viz/common/resources/resource_format.h",
-  "+components/viz/common/resources/resource_format_utils.h",
   "+components/viz/common/resources/resource_sizes.h",
   "+components/viz/common/resources/shared_image_format.h",
   "+components/viz/common/resources/shared_image_format_utils.h",
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.cc b/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.cc
index 75c84e86..b9918b5 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.cc
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.cc
@@ -9,7 +9,6 @@
 #include "base/containers/contains.h"
 #include "base/logging.h"
 #include "build/build_config.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
 #include "gpu/command_buffer/service/ahardwarebuffer_utils.h"
 #include "gpu/ipc/common/gpu_memory_buffer_impl_android_hardware_buffer.h"
diff --git a/headless/lib/browser/headless_browser_impl.h b/headless/lib/browser/headless_browser_impl.h
index 64854082..ce26da4 100644
--- a/headless/lib/browser/headless_browser_impl.h
+++ b/headless/lib/browser/headless_browser_impl.h
@@ -121,14 +121,14 @@
 
   base::OnceCallback<void(HeadlessBrowser*)> on_start_callback_;
   absl::optional<HeadlessBrowser::Options> options_;
-  raw_ptr<HeadlessBrowserMainParts, DanglingUntriaged> browser_main_parts_ =
+  raw_ptr<HeadlessBrowserMainParts, DanglingAcrossTasks> browser_main_parts_ =
       nullptr;
   int exit_code_ = 0;
 
   base::flat_map<std::string, std::unique_ptr<HeadlessBrowserContextImpl>>
       browser_contexts_;
-  raw_ptr<HeadlessBrowserContext, DanglingUntriaged> default_browser_context_ =
-      nullptr;
+  raw_ptr<HeadlessBrowserContext, DanglingAcrossTasks>
+      default_browser_context_ = nullptr;
   scoped_refptr<content::DevToolsAgentHost> agent_host_;
   std::unique_ptr<HeadlessRequestContextManager>
       system_request_context_manager_;
diff --git a/headless/public/headless_web_contents.h b/headless/public/headless_web_contents.h
index f6896cd4..27f865ee 100644
--- a/headless/public/headless_web_contents.h
+++ b/headless/public/headless_web_contents.h
@@ -98,7 +98,7 @@
 
   explicit Builder(HeadlessBrowserContextImpl* browser_context);
 
-  raw_ptr<HeadlessBrowserContextImpl, DanglingUntriaged> browser_context_;
+  raw_ptr<HeadlessBrowserContextImpl, DanglingAcrossTasks> browser_context_;
 
   GURL initial_url_ = GURL("about:blank");
   gfx::Size window_size_;
diff --git a/headless/test/headless_browser_browsertest.cc b/headless/test/headless_browser_browsertest.cc
index a06f837..17c7797 100644
--- a/headless/test/headless_browser_browsertest.cc
+++ b/headless/test/headless_browser_browsertest.cc
@@ -431,8 +431,9 @@
   void OnTargetCrashed(const base::Value::Dict&) { FinishAsynchronousTest(); }
 
  protected:
-  raw_ptr<HeadlessBrowserContext, DanglingUntriaged> browser_context_ = nullptr;
-  raw_ptr<HeadlessWebContents, DanglingUntriaged> web_contents_ = nullptr;
+  raw_ptr<HeadlessBrowserContext, DanglingAcrossTasks> browser_context_ =
+      nullptr;
+  raw_ptr<HeadlessWebContents, DanglingAcrossTasks> web_contents_ = nullptr;
   SimpleDevToolsProtocolClient devtools_client_;
   base::FilePath crash_dumps_dir_;
 };
diff --git a/headless/test/headless_browser_context_browsertest.cc b/headless/test/headless_browser_context_browsertest.cc
index 7f240260..f3c5e83 100644
--- a/headless/test/headless_browser_context_browsertest.cc
+++ b/headless/test/headless_browser_context_browsertest.cc
@@ -122,8 +122,9 @@
   }
 
  private:
-  raw_ptr<HeadlessBrowserContext, DanglingUntriaged> browser_context_ = nullptr;
-  raw_ptr<HeadlessWebContents, DanglingUntriaged> web_contents2_ = nullptr;
+  raw_ptr<HeadlessBrowserContext, DanglingAcrossTasks> browser_context_ =
+      nullptr;
+  raw_ptr<HeadlessWebContents, DanglingAcrossTasks> web_contents2_ = nullptr;
   SimpleDevToolsProtocolClient devtools_client2_;
 };
 
diff --git a/headless/test/headless_browser_user_agent_metadata_browsertest.cc b/headless/test/headless_browser_user_agent_metadata_browsertest.cc
index f8f326f..b0127de 100644
--- a/headless/test/headless_browser_user_agent_metadata_browsertest.cc
+++ b/headless/test/headless_browser_user_agent_metadata_browsertest.cc
@@ -119,7 +119,7 @@
   }
 
  protected:
-  raw_ptr<HeadlessWebContents, DanglingUntriaged> web_contents_;
+  raw_ptr<HeadlessWebContents, DanglingAcrossTasks> web_contents_;
   SimpleDevToolsProtocolClient devtools_client_;
 
   // Get the version of the HeadlessChrome brand from the brand list.
@@ -411,7 +411,7 @@
   }
 
  protected:
-  raw_ptr<HeadlessWebContents, DanglingUntriaged> web_contents_;
+  raw_ptr<HeadlessWebContents, DanglingAcrossTasks> web_contents_;
   SimpleDevToolsProtocolClient devtools_client_;
   // HandleRequest will capture headers with this path in `got_headers_`.
   std::string capture_headers_for_path_;
diff --git a/headless/test/headless_devtooled_browsertest.h b/headless/test/headless_devtooled_browsertest.h
index dcefc63c..3ad2b482 100644
--- a/headless/test/headless_devtooled_browsertest.h
+++ b/headless/test/headless_devtooled_browsertest.h
@@ -52,8 +52,8 @@
 
   void RunTest();
 
-  raw_ptr<HeadlessBrowserContext, DanglingUntriaged> browser_context_;
-  raw_ptr<HeadlessWebContents, DanglingUntriaged> web_contents_;
+  raw_ptr<HeadlessBrowserContext, DanglingAcrossTasks> browser_context_;
+  raw_ptr<HeadlessWebContents, DanglingAcrossTasks> web_contents_;
   simple_devtools_protocol_client::SimpleDevToolsProtocolClient
       devtools_client_;
   simple_devtools_protocol_client::SimpleDevToolsProtocolClient
diff --git a/headless/test/headless_web_contents_browsertest.cc b/headless/test/headless_web_contents_browsertest.cc
index e3f4390f..7b34037 100644
--- a/headless/test/headless_web_contents_browsertest.cc
+++ b/headless/test/headless_web_contents_browsertest.cc
@@ -481,9 +481,9 @@
             base::Unretained(this)));
   }
 
-  raw_ptr<HeadlessBrowserContext, DanglingUntriaged> browser_context_ =
+  raw_ptr<HeadlessBrowserContext, DanglingAcrossTasks> browser_context_ =
       nullptr;  // Not owned.
-  raw_ptr<HeadlessWebContentsImpl, DanglingUntriaged> web_contents_ =
+  raw_ptr<HeadlessWebContentsImpl, DanglingAcrossTasks> web_contents_ =
       nullptr;  // Not owned.
 
   bool page_ready_ = false;
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index 7c3971c..df7d1fc 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -29471,11 +29471,14 @@
         '  },'
         '  "$build/siso": {'
         '    "configs": ['
-        '      "remote_all"'
+        '      "remote_all",'
+        '      "rewrapper_to_reproxy"'
         '    ],'
         '    "enable_cloud_profiler": true,'
         '    "enable_cloud_trace": true,'
-        '    "experiments": [],'
+        '    "experiments": ['
+        '      "use-reproxy"'
+        '    ],'
         '    "project": "rbe-chromium-untrusted"'
         '  },'
         '  "$recipe_engine/resultdb/test_presentation": {'
@@ -29598,8 +29601,7 @@
         '  },'
         '  "$build/siso": {'
         '    "configs": ['
-        '      "remote_all",'
-        '      "rewrapper_to_reproxy"'
+        '      "remote_all"'
         '    ],'
         '    "enable_cloud_profiler": true,'
         '    "enable_cloud_trace": true,'
diff --git a/infra/config/subprojects/chromium/ci/chromium.fyi.star b/infra/config/subprojects/chromium/ci/chromium.fyi.star
index 8afde2eb..d626c10 100644
--- a/infra/config/subprojects/chromium/ci/chromium.fyi.star
+++ b/infra/config/subprojects/chromium/ci/chromium.fyi.star
@@ -1494,6 +1494,9 @@
         category = "buildperf",
         short_name = "lnx",
     ),
+    # TODO(b/273407069): enable reproxy mode by default.
+    siso_configs = ["remote_all", "rewrapper_to_reproxy"],
+    siso_experiments = ["use-reproxy"],
 )
 
 build_perf_builder(
@@ -1525,8 +1528,6 @@
         category = "buildperf",
         short_name = "lnxss",
     ),
-    # TODO(b/273407069): enable reproxy mode by default.
-    siso_configs = ["remote_all", "rewrapper_to_reproxy"],
 )
 
 build_perf_builder(
diff --git a/ios/chrome/app/application_delegate/app_state_observer.h b/ios/chrome/app/application_delegate/app_state_observer.h
index 802976f..bb56723c 100644
--- a/ios/chrome/app/application_delegate/app_state_observer.h
+++ b/ios/chrome/app/application_delegate/app_state_observer.h
@@ -80,7 +80,7 @@
     willTransitionToInitStage:(InitStage)nextInitStage;
 
 // Called right after the app is transitioned out of to the
-// `previousInitStage`. he init stage of the app at that
+// `previousInitStage`. The init stage of the app at that
 // moment is `previousInitStage` + 1.
 - (void)appState:(AppState*)appState
     didTransitionFromInitStage:(InitStage)previousInitStage;
diff --git a/ios/chrome/browser/application_context/BUILD.gn b/ios/chrome/browser/application_context/BUILD.gn
index 088b2b6..fe483f7 100644
--- a/ios/chrome/browser/application_context/BUILD.gn
+++ b/ios/chrome/browser/application_context/BUILD.gn
@@ -37,13 +37,13 @@
     "//ios/chrome/browser/gcm",
     "//ios/chrome/browser/history",
     "//ios/chrome/browser/metrics",
-    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/policy",
     "//ios/chrome/browser/prefs",
     "//ios/chrome/browser/push_notification:push_notification_service",
     "//ios/chrome/browser/segmentation_platform",
     "//ios/chrome/browser/shared/model/application_context",
     "//ios/chrome/browser/shared/model/browser_state",
+    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/shared/model/prefs:browser_prefs",
     "//ios/chrome/browser/shared/model/prefs:pref_names",
     "//ios/chrome/browser/update_client",
diff --git a/ios/chrome/browser/autofill/BUILD.gn b/ios/chrome/browser/autofill/BUILD.gn
index d8f223a..85b8e208 100644
--- a/ios/chrome/browser/autofill/BUILD.gn
+++ b/ios/chrome/browser/autofill/BUILD.gn
@@ -59,9 +59,9 @@
     "//components/sync/service",
     "//components/variations/service",
     "//ios/chrome/browser/history",
-    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/shared/model/application_context",
     "//ios/chrome/browser/shared/model/browser_state",
+    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/shared/model/prefs:pref_names",
     "//ios/chrome/browser/shared/ui/util:util_swift",
     "//ios/chrome/browser/shared/ui/util/image",
@@ -192,9 +192,9 @@
     "//ios/chrome/app/application_delegate:app_state_header",
     "//ios/chrome/browser/infobars",
     "//ios/chrome/browser/passwords",
-    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/shared/coordinator/chrome_coordinator",
     "//ios/chrome/browser/shared/model/browser_state:test_support",
+    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/ssl",
     "//ios/chrome/browser/sync:sync",
     "//ios/chrome/browser/ui/autofill",
diff --git a/ios/chrome/browser/autofill/message/BUILD.gn b/ios/chrome/browser/autofill/message/BUILD.gn
index 46b11c99..283feb5 100644
--- a/ios/chrome/browser/autofill/message/BUILD.gn
+++ b/ios/chrome/browser/autofill/message/BUILD.gn
@@ -9,4 +9,4 @@
     "save_card_message_with_links.mm",
   ]
   deps = [ "//url:url" ]
-}
\ No newline at end of file
+}
diff --git a/ios/chrome/browser/browser_state/BUILD.gn b/ios/chrome/browser/browser_state/BUILD.gn
index 6b9c5705..15cb0c0 100644
--- a/ios/chrome/browser/browser_state/BUILD.gn
+++ b/ios/chrome/browser/browser_state/BUILD.gn
@@ -72,6 +72,8 @@
     "//components/proxy_config/ios",
     "//components/signin/ios/browser:active_state_manager",
     "//components/signin/public/identity_manager",
+    "//components/supervised_user/core/browser",
+    "//components/supervised_user/core/common",
     "//components/sync_preferences",
     "//components/user_prefs",
     "//components/variations/service",
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.mm b/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.mm
index b479209..7ff6a73 100644
--- a/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.mm
+++ b/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.mm
@@ -20,21 +20,25 @@
 #import "components/prefs/pref_service.h"
 #import "components/signin/ios/browser/active_state_manager.h"
 #import "components/signin/public/identity_manager/identity_manager.h"
+#import "components/supervised_user/core/browser/supervised_user_settings_service.h"
 #import "ios/chrome/browser/browser_state/chrome_browser_state_impl.h"
 #import "ios/chrome/browser/browser_state/constants.h"
 #import "ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.h"
 #import "ios/chrome/browser/browser_state_metrics/browser_state_metrics.h"
 #import "ios/chrome/browser/optimization_guide/optimization_guide_service.h"
 #import "ios/chrome/browser/optimization_guide/optimization_guide_service_factory.h"
-#import "ios/chrome/browser/shared/model/paths/paths.h"
 #import "ios/chrome/browser/push_notification/push_notification_browser_state_service_factory.h"
 #import "ios/chrome/browser/segmentation_platform/segmentation_platform_service_factory.h"
 #import "ios/chrome/browser/shared/model/application_context/application_context.h"
 #import "ios/chrome/browser/shared/model/browser_state/browser_state_info_cache.h"
+#import "ios/chrome/browser/shared/model/paths/paths.h"
 #import "ios/chrome/browser/shared/model/prefs/pref_names.h"
 #import "ios/chrome/browser/signin/account_consistency_service_factory.h"
 #import "ios/chrome/browser/signin/account_reconcilor_factory.h"
 #import "ios/chrome/browser/signin/identity_manager_factory.h"
+#import "ios/chrome/browser/supervised_user/child_account_service_factory.h"
+#import "ios/chrome/browser/supervised_user/supervised_user_service_factory.h"
+#import "ios/chrome/browser/supervised_user/supervised_user_settings_service_factory.h"
 #import "ios/chrome/browser/unified_consent/unified_consent_service_factory.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -229,6 +233,19 @@
       browser_state);
 
   PushNotificationBrowserStateServiceFactory::GetForBrowserState(browser_state);
+
+  // For //chrome/browser/profiles, SupervisedUserSettingsService is a
+  // SimpleKeyedService and is initialized before the creation of
+  // `ProfileKeyedService`s.
+
+  // For //ios, SupervisedUserSettingsService is a BrowserStateKeyedService and
+  // is initialized here.
+  SupervisedUserSettingsServiceFactory::GetForBrowserState(browser_state)
+      ->Init(browser_state->GetStatePath(),
+             browser_state->GetIOTaskRunner().get(),
+             /*load_synchronously=*/true);
+  ChildAccountServiceFactory::GetForBrowserState(browser_state)->Init();
+  SupervisedUserServiceFactory::GetForBrowserState(browser_state)->Init();
 }
 
 void ChromeBrowserStateManagerImpl::AddBrowserStateToCache(
diff --git a/ios/chrome/browser/browsing_data/BUILD.gn b/ios/chrome/browser/browsing_data/BUILD.gn
index 59af350..0b053e97 100644
--- a/ios/chrome/browser/browsing_data/BUILD.gn
+++ b/ios/chrome/browser/browsing_data/BUILD.gn
@@ -61,7 +61,6 @@
     "//ios/chrome/browser/language",
     "//ios/chrome/browser/optimization_guide",
     "//ios/chrome/browser/passwords",
-    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/reading_list:reading_list_remover",
     "//ios/chrome/browser/search_engines",
     "//ios/chrome/browser/sessions",
@@ -69,6 +68,7 @@
     "//ios/chrome/browser/sessions:session_service",
     "//ios/chrome/browser/shared/model/application_context",
     "//ios/chrome/browser/shared/model/browser_state",
+    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/signin",
     "//ios/chrome/browser/snapshots",
     "//ios/chrome/browser/sync",
diff --git a/ios/chrome/browser/crash_report/BUILD.gn b/ios/chrome/browser/crash_report/BUILD.gn
index 4625a3b..5d9ff31 100644
--- a/ios/chrome/browser/crash_report/BUILD.gn
+++ b/ios/chrome/browser/crash_report/BUILD.gn
@@ -37,9 +37,9 @@
     "//components/previous_session_info",
     "//components/upload_list",
     "//ios/chrome/app:tests_hook",
-    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/shared/model/application_context",
     "//ios/chrome/browser/shared/model/browser_state",
+    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/common",
     "//ios/chrome/common/app_group",
     "//ios/chrome/common/crash_report",
@@ -69,10 +69,10 @@
     "//ios/chrome/app/theme",
     "//ios/chrome/browser/infobars",
     "//ios/chrome/browser/infobars:public",
-    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/shared/coordinator/scene:scene_state_header",
     "//ios/chrome/browser/shared/model/browser",
     "//ios/chrome/browser/shared/model/browser_state",
+    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/shared/model/web_state_list",
     "//ios/chrome/browser/shared/public/features",
     "//ios/chrome/browser/shared/ui/symbols",
diff --git a/ios/chrome/browser/metrics/BUILD.gn b/ios/chrome/browser/metrics/BUILD.gn
index 2af0eac..a352efd 100644
--- a/ios/chrome/browser/metrics/BUILD.gn
+++ b/ios/chrome/browser/metrics/BUILD.gn
@@ -104,11 +104,11 @@
     "//ios/chrome/browser/default_browser:utils",
     "//ios/chrome/browser/history",
     "//ios/chrome/browser/ntp:features",
-    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/shared/coordinator/scene:scene_state_header",
     "//ios/chrome/browser/shared/model/application_context",
     "//ios/chrome/browser/shared/model/browser",
     "//ios/chrome/browser/shared/model/browser_state",
+    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/shared/model/prefs:pref_names",
     "//ios/chrome/browser/shared/model/url:constants",
     "//ios/chrome/browser/shared/model/web_state_list",
diff --git a/ios/chrome/browser/optimization_guide/BUILD.gn b/ios/chrome/browser/optimization_guide/BUILD.gn
index cac84cc1..cb47cfe 100644
--- a/ios/chrome/browser/optimization_guide/BUILD.gn
+++ b/ios/chrome/browser/optimization_guide/BUILD.gn
@@ -34,11 +34,11 @@
     "//components/variations",
     "//ios/chrome/browser/download/background_service",
     "//ios/chrome/browser/metrics:accessor",
-    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/push_notification:push_notification_client",
     "//ios/chrome/browser/shared/model/application_context",
     "//ios/chrome/browser/shared/model/browser",
     "//ios/chrome/browser/shared/model/browser_state",
+    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/shared/model/web_state_list",
     "//ios/web",
   ]
diff --git a/ios/chrome/browser/policy/BUILD.gn b/ios/chrome/browser/policy/BUILD.gn
index 5669dd8..f9091b6 100644
--- a/ios/chrome/browser/policy/BUILD.gn
+++ b/ios/chrome/browser/policy/BUILD.gn
@@ -85,12 +85,12 @@
     "//components/variations/service",
     "//components/version_info:version_info",
     "//ios/chrome/app/application_delegate:app_state_header",
-    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/shared/coordinator/scene:scene_state_browser_agent",
     "//ios/chrome/browser/shared/coordinator/scene:scene_state_header",
     "//ios/chrome/browser/shared/model/application_context",
     "//ios/chrome/browser/shared/model/browser",
     "//ios/chrome/browser/shared/model/browser_state",
+    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/shared/model/prefs:pref_names",
     "//ios/chrome/browser/shared/public/commands",
     "//ios/chrome/browser/signin",
@@ -213,7 +213,6 @@
     "//google_apis",
     "//ios/chrome/app/application_delegate:app_state_header",
     "//ios/chrome/browser/flags:system_flags",
-    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/prefs",
     "//ios/chrome/browser/shared/coordinator/scene:scene_state_browser_agent",
     "//ios/chrome/browser/shared/coordinator/scene:scene_state_header",
@@ -221,6 +220,7 @@
     "//ios/chrome/browser/shared/model/application_context",
     "//ios/chrome/browser/shared/model/browser/test:test_support",
     "//ios/chrome/browser/shared/model/browser_state:test_support",
+    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/shared/model/prefs:browser_prefs",
     "//ios/chrome/browser/shared/model/prefs:pref_names",
     "//ios/chrome/browser/shared/public/commands",
@@ -320,10 +320,10 @@
     "//components/policy/core/browser",
     "//components/policy/core/common",
     "//google_apis",
-    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/policy_url_blocking",
     "//ios/chrome/browser/shared/model/application_context",
     "//ios/chrome/browser/shared/model/browser_state",
+    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/test/app:test_support",
   ]
   frameworks = [ "Foundation.framework" ]
diff --git a/ios/chrome/browser/reading_list/BUILD.gn b/ios/chrome/browser/reading_list/BUILD.gn
index 95c644a7..19b1402 100644
--- a/ios/chrome/browser/reading_list/BUILD.gn
+++ b/ios/chrome/browser/reading_list/BUILD.gn
@@ -50,10 +50,10 @@
     "//ios/chrome/app/strings:ios_strings_grit",
     "//ios/chrome/browser/favicon",
     "//ios/chrome/browser/history",
-    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/shared/model/application_context",
     "//ios/chrome/browser/shared/model/browser",
     "//ios/chrome/browser/shared/model/browser_state",
+    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/shared/model/url:constants",
     "//ios/chrome/browser/shared/model/web_state_list",
     "//ios/chrome/browser/shared/public/commands",
@@ -141,8 +141,8 @@
     "//components/reading_list/core:test_support",
     "//components/sync/base",
     "//ios/chrome/browser/dom_distiller",
-    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/shared/model/browser_state:test_support",
+    "//ios/chrome/browser/shared/model/paths",
     "//ios/web",
     "//ios/web/public",
     "//ios/web/public/test",
diff --git a/ios/chrome/browser/segmentation_platform/BUILD.gn b/ios/chrome/browser/segmentation_platform/BUILD.gn
index 806e72d..007fc49 100644
--- a/ios/chrome/browser/segmentation_platform/BUILD.gn
+++ b/ios/chrome/browser/segmentation_platform/BUILD.gn
@@ -32,10 +32,10 @@
     "//ios/chrome/browser/history",
     "//ios/chrome/browser/metrics:accessor",
     "//ios/chrome/browser/optimization_guide",
-    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/shared/model/application_context",
     "//ios/chrome/browser/shared/model/browser",
     "//ios/chrome/browser/shared/model/browser_state",
+    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/shared/model/web_state_list",
     "//ios/chrome/browser/sync",
   ]
diff --git a/ios/chrome/browser/sessions/BUILD.gn b/ios/chrome/browser/sessions/BUILD.gn
index 3a976eab2..40b077c 100644
--- a/ios/chrome/browser/sessions/BUILD.gn
+++ b/ios/chrome/browser/sessions/BUILD.gn
@@ -196,9 +196,9 @@
     "//base/test:test_support",
     "//ios/chrome/browser/main",
     "//ios/chrome/browser/ntp",
-    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/shared/model/browser/test:test_support",
     "//ios/chrome/browser/shared/model/browser_state:test_support",
+    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/shared/model/url:constants",
     "//ios/chrome/browser/shared/model/web_state_list",
     "//ios/chrome/browser/shared/model/web_state_list/test:test_support",
diff --git a/ios/chrome/browser/shared/coordinator/scene/BUILD.gn b/ios/chrome/browser/shared/coordinator/scene/BUILD.gn
index ec4dbea..5381678 100644
--- a/ios/chrome/browser/shared/coordinator/scene/BUILD.gn
+++ b/ios/chrome/browser/shared/coordinator/scene/BUILD.gn
@@ -101,7 +101,6 @@
     "//ios/chrome/browser/main",
     "//ios/chrome/browser/ntp",
     "//ios/chrome/browser/ntp:features",
-    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/policy",
     "//ios/chrome/browser/policy:policy_util",
     "//ios/chrome/browser/promos_manager:factory",
@@ -114,6 +113,7 @@
     "//ios/chrome/browser/shared/coordinator/layout_guide:layout_guide_scene_agent",
     "//ios/chrome/browser/shared/model/application_context",
     "//ios/chrome/browser/shared/model/browser_state",
+    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/shared/model/prefs:pref_names",
     "//ios/chrome/browser/shared/model/url",
     "//ios/chrome/browser/shared/model/url:constants",
diff --git a/ios/chrome/browser/shared/coordinator/scene/OWNERS b/ios/chrome/browser/shared/coordinator/scene/OWNERS
new file mode 100644
index 0000000..b98e1d4
--- /dev/null
+++ b/ios/chrome/browser/shared/coordinator/scene/OWNERS
@@ -0,0 +1,2 @@
+edchin@chromium.org
+marq@chromium.org
diff --git a/ios/chrome/browser/shared/coordinator/scene/scene_delegate.mm b/ios/chrome/browser/shared/coordinator/scene/scene_delegate.mm
index 2aa8f61..80eceaf 100644
--- a/ios/chrome/browser/shared/coordinator/scene/scene_delegate.mm
+++ b/ios/chrome/browser/shared/coordinator/scene/scene_delegate.mm
@@ -50,6 +50,10 @@
 @synthesize sceneState = _sceneState;
 @synthesize sceneController = _sceneController;
 
+- (void)dealloc {
+  CHECK(!_sceneState);
+}
+
 - (SceneState*)sceneState {
   if (!_sceneState) {
     MainApplicationDelegate* appDelegate =
@@ -92,7 +96,7 @@
   return _window;
 }
 
-#pragma mark Connecting and Disconnecting the Scene
+#pragma mark - UISceneDelegate
 
 - (void)scene:(UIScene*)scene
     willConnectToSession:(UISceneSession*)session
@@ -107,6 +111,14 @@
   }
 }
 
+- (void)sceneDidDisconnect:(UIScene*)scene {
+  CHECK(_sceneState);
+  self.sceneState.activationLevel = SceneActivationLevelUnattached;
+  _sceneState = nil;
+}
+
+#pragma mark - private
+
 - (WindowActivityOrigin)originFromSession:(UISceneSession*)session
                                   options:(UISceneConnectionOptions*)options {
   WindowActivityOrigin origin = WindowActivityUnknownOrigin;
@@ -136,10 +148,6 @@
   return origin;
 }
 
-- (void)sceneDidDisconnect:(UIScene*)scene {
-  self.sceneState.activationLevel = SceneActivationLevelUnattached;
-}
-
 #pragma mark Transitioning to the Foreground
 
 - (void)sceneWillEnterForeground:(UIScene*)scene {
diff --git a/ios/chrome/browser/supervised_user/BUILD.gn b/ios/chrome/browser/supervised_user/BUILD.gn
index 276a49c4..a0e6e39 100644
--- a/ios/chrome/browser/supervised_user/BUILD.gn
+++ b/ios/chrome/browser/supervised_user/BUILD.gn
@@ -46,6 +46,7 @@
     "//services/network/public/cpp",
   ]
 }
+
 source_set("unit_tests") {
   configs += [ "//build/config/compiler:enable_arc" ]
   testonly = true
@@ -56,36 +57,27 @@
     "supervised_user_metrics_service_factory_unittest.mm",
     "supervised_user_service_factory_unittest.mm",
     "supervised_user_settings_service_factory_unittest.mm",
+    "supervised_user_url_filter_tab_helper_unittest.mm",
   ]
   deps = [
     ":supervised_user",
     "//base/test:test_support",
+    "//components/signin/public/identity_manager",
+    "//components/signin/public/identity_manager:test_support",
     "//components/supervised_user/core/browser",
     "//components/supervised_user/core/browser:list_family_members_service",
+    "//components/supervised_user/core/browser:test_support",
     "//components/supervised_user/core/common",
+    "//components/sync_preferences",
+    "//components/sync_preferences:test_support",
+    "//ios/chrome/browser/shared/model/application_context:application_context",
     "//ios/chrome/browser/shared/model/browser_state:test_support",
+    "//ios/chrome/browser/shared/model/prefs:browser_prefs",
+    "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/signin:test_support",
+    "//ios/chrome/test:test_support",
     "//ios/web/public/test",
+    "//services/network:test_support",
+    "//testing/gtest",
   ]
 }
-
-source_set("eg2_tests") {
-  configs += [
-    "//build/config/compiler:enable_arc",
-    "//build/config/ios:xctest_config",
-  ]
-  testonly = true
-  sources = [ "supervised_user_url_filter_egtest.mm" ]
-  deps = [
-    "//base",
-    "//components/strings",
-    "//components/strings:components_strings_grit",
-    "//components/supervised_user/core/common",
-    "//ios/chrome/browser/policy:eg_test_support+eg2",
-    "//ios/chrome/test/earl_grey:eg_test_support+eg2",
-    "//ios/testing/earl_grey:eg_test_support+eg2",
-    "//ios/web/public/test/http_server",
-    "//net:test_support",
-    "//ui/base",
-  ]
-  frameworks = [ "UIKit.framework" ]
-}
diff --git a/ios/chrome/browser/supervised_user/supervised_user_service_factory.mm b/ios/chrome/browser/supervised_user/supervised_user_service_factory.mm
index 3d0472d..f5571a9 100644
--- a/ios/chrome/browser/supervised_user/supervised_user_service_factory.mm
+++ b/ios/chrome/browser/supervised_user/supervised_user_service_factory.mm
@@ -13,6 +13,7 @@
 #import "ios/chrome/browser/first_run/first_run.h"
 #import "ios/chrome/browser/shared/model/application_context/application_context.h"
 #import "ios/chrome/browser/shared/model/browser_state/chrome_browser_state.h"
+#import "ios/chrome/browser/signin/identity_manager_factory.h"
 #import "ios/chrome/browser/supervised_user/kids_chrome_management_client_factory.h"
 #import "ios/chrome/browser/supervised_user/supervised_user_settings_service_factory.h"
 #import "ios/chrome/browser/sync/sync_service_factory.h"
@@ -75,6 +76,7 @@
     : BrowserStateKeyedServiceFactory(
           "SupervisedUserService",
           BrowserStateDependencyManager::GetInstance()) {
+  DependsOn(IdentityManagerFactory::GetInstance());
   DependsOn(KidsChromeManagementClientFactory::GetInstance());
   DependsOn(SyncServiceFactory::GetInstance());
   DependsOn(SupervisedUserSettingsServiceFactory::GetInstance());
@@ -98,6 +100,7 @@
   // TODO (b/279766165): Once have an active Settings Service instance, initialize
   // this service on ChromeBrowserStateManagerImpl::DoFinalInitForServices().
   return std::make_unique<supervised_user::SupervisedUserService>(
+      IdentityManagerFactory::GetForBrowserState(browser_state),
       KidsChromeManagementClientFactory::GetForBrowserState(browser_state),
       *user_prefs, *settings_service, *sync_service,
       // iOS does not support extensions, check_webstore_url_callback returns
diff --git a/ios/chrome/browser/supervised_user/supervised_user_url_filter_egtest.mm b/ios/chrome/browser/supervised_user/supervised_user_url_filter_egtest.mm
deleted file mode 100644
index 6e575c8..0000000
--- a/ios/chrome/browser/supervised_user/supervised_user_url_filter_egtest.mm
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import <string>
-
-#import "base/feature_list.h"
-#import "components/strings/grit/components_strings.h"
-#import "components/supervised_user/core/common/features.h"
-#import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
-#import "ios/chrome/test/earl_grey/chrome_matchers.h"
-#import "ios/chrome/test/earl_grey/chrome_test_case.h"
-#import "ios/testing/earl_grey/app_launch_configuration.h"
-#import "ios/testing/earl_grey/earl_grey_test.h"
-#import "net/base/net_errors.h"
-#import "net/test/embedded_test_server/embedded_test_server.h"
-#import "ui/base/l10n/l10n_util.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-// Tests the SupervisedUserURLFilter.
-@interface SupervisedUserURLFilterTestCase : ChromeTestCase
-@end
-
-@implementation SupervisedUserURLFilterTestCase
-
-- (AppLaunchConfiguration)appConfigurationForTestCase {
-  AppLaunchConfiguration config;
-  config.features_enabled.push_back(
-      supervised_user::kFilterWebsitesForSupervisedUsersOnDesktopAndIOS);
-  return config;
-}
-
-- (void)setUp {
-  [super setUp];
-  GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");
-}
-
-- (void)tearDown {
-  [super tearDown];
-}
-
-// Tests that a page load is blocked when the URL is filtered.
-- (void)testBlockedSiteDisplaysErrorOnPageLoad {
-  [ChromeEarlGrey loadURL:self.testServer->GetURL("/filtered")];
-  [ChromeEarlGrey
-      waitForWebStateContainingText:l10n_util::GetStringUTF8(
-                                        IDS_BLOCK_INTERSTITIAL_TITLE)];
-}
-
-// Tests that unfiltered sites are loaded normally.
-- (void)testUnfilteredSiteIsLoaded {
-  [ChromeEarlGrey loadURL:self.testServer->GetURL("/echo")];
-  // Expected text set by embedded_test_server handler.
-  [ChromeEarlGrey waitForWebStateContainingText:"Echo"];
-}
-
-@end
diff --git a/ios/chrome/browser/supervised_user/supervised_user_url_filter_tab_helper.mm b/ios/chrome/browser/supervised_user/supervised_user_url_filter_tab_helper.mm
index da5d26d..b09af6b5 100644
--- a/ios/chrome/browser/supervised_user/supervised_user_url_filter_tab_helper.mm
+++ b/ios/chrome/browser/supervised_user/supervised_user_url_filter_tab_helper.mm
@@ -4,15 +4,23 @@
 
 #import "ios/chrome/browser/supervised_user/supervised_user_url_filter_tab_helper.h"
 
+#import "base/functional/callback.h"
+#import "base/memory/weak_ptr.h"
 #import "base/strings/sys_string_conversions.h"
 #import "components/prefs/pref_service.h"
+#import "components/supervised_user/core/browser/kids_chrome_management_client.h"
 #import "components/supervised_user/core/browser/supervised_user_interstitial.h"
+#import "components/supervised_user/core/browser/supervised_user_service.h"
+#import "components/supervised_user/core/browser/supervised_user_url_filter.h"
+#import "components/supervised_user/core/common/features.h"
 #import "components/supervised_user/core/common/pref_names.h"
 #import "components/supervised_user/core/common/supervised_user_utils.h"
 #import "ios/chrome/browser/shared/model/application_context/application_context.h"
 #import "ios/chrome/browser/shared/model/browser_state/chrome_browser_state.h"
+#import "ios/chrome/browser/supervised_user/kids_chrome_management_client_factory.h"
 #import "ios/chrome/browser/supervised_user/supervised_user_error.h"
 #import "ios/chrome/browser/supervised_user/supervised_user_error_container.h"
+#import "ios/chrome/browser/supervised_user/supervised_user_service_factory.h"
 #import "ios/net/protocol_handler_util.h"
 #import "net/base/mac/url_conversions.h"
 #import "net/base/net_errors.h"
@@ -22,29 +30,40 @@
 #error "This file requires ARC support."
 #endif
 
+using PolicyDecision = web::WebStatePolicyDecider::PolicyDecision;
+
 namespace {
 
-const char kFilteredURLExample[] = "/filtered";
+void OnURLFilteringDone(
+    base::WeakPtr<web::WebState> weak_web_state,
+    GURL request_url,
+    bool is_main_frame,
+    web::WebStatePolicyDecider::PolicyDecisionCallback policy_decision_callback,
+    supervised_user::SupervisedUserURLFilter::FilteringBehavior
+        filtering_behavior,
+    supervised_user::FilteringBehaviorReason reason,
+    bool uncertain /*unused*/) {
+  // Allow navigation by default.
+  PolicyDecision decision = PolicyDecision::Allow();
+  web::WebState* web_state = weak_web_state.get();
 
-// Fake supervised user custodian information displayed in the interstitial.
-// They will be fetched by the child account service once it is migrated to
-// components.
-void CreateMockData(web::WebState* web_state) {
-  ChromeBrowserState* browser_state =
-      ChromeBrowserState::FromBrowserState(web_state->GetBrowserState());
+  if (!web_state) {
+    // Cancel the request if the corresponding `web_state` is destroyed.
+    decision = PolicyDecision::Cancel();
+  } else if (filtering_behavior == supervised_user::SupervisedUserURLFilter::
+                                       FilteringBehavior::BLOCK) {
+    SupervisedUserErrorContainer* container =
+        SupervisedUserErrorContainer::FromWebState(web_state);
+    CHECK(container);
+    container->SetSupervisedUserErrorInfo(
+        std::make_unique<SupervisedUserErrorContainer::SupervisedUserErrorInfo>(
+            request_url, is_main_frame,
+            // TODO(b/265761985): Update once we have this information.
+            /*is_already_requested=*/false, reason));
+    decision = CreateSupervisedUserInterstitialErrorDecision();
+  }
 
-  browser_state->GetPrefs()->SetString(prefs::kSupervisedUserCustodianEmail,
-                                       "primary@gmail.com");
-  browser_state->GetPrefs()->SetString(prefs::kSupervisedUserCustodianName,
-                                       "Primary Name");
-  browser_state->GetPrefs()->SetString(
-      prefs::kSupervisedUserSecondCustodianName, "Secondary Name");
-  browser_state->GetPrefs()->SetString(
-      prefs::kSupervisedUserSecondCustodianEmail, "secondary@gmail.com");
-  browser_state->GetPrefs()->SetString(
-      prefs::kSupervisedUserCustodianProfileImageURL, "thisurl.com");
-  browser_state->GetPrefs()->SetString(
-      prefs::kSupervisedUserSecondCustodianProfileImageURL, "otherurl.com");
+  std::move(policy_decision_callback).Run(decision);
 }
 
 }  // namespace
@@ -59,30 +78,34 @@
     NSURLRequest* request,
     web::WebStatePolicyDecider::RequestInfo request_info,
     web::WebStatePolicyDecider::PolicyDecisionCallback callback) {
-  // TODO(b/265761985): integrate with SupervisedUserService::GetURLFilter().
-  if ([request.URL.absoluteString containsString:@(kFilteredURLExample)]) {
-    supervised_user::FilteringBehaviorReason reason =
-        supervised_user::FilteringBehaviorReason::
-            DEFAULT;  // TODO(b/265761985): Extract reason from filtering.
-    // TODO(b/279765349): Remove once we have real data to populate the
-    // interstitial.
-    CreateMockData(web_state());
+  ChromeBrowserState* chrome_browser_state =
+      ChromeBrowserState::FromBrowserState(web_state()->GetBrowserState());
 
-    SupervisedUserErrorContainer* container =
-        SupervisedUserErrorContainer::FromWebState(web_state());
-    CHECK(container);
-    container->SetSupervisedUserErrorInfo(
-        std::make_unique<SupervisedUserErrorContainer::SupervisedUserErrorInfo>(
-            GURL(base::SysNSStringToUTF8(request.URL.absoluteString)),
-            request_info.target_frame_is_main,
-            // TODO(b/265761985): Update once we have this information.
-            /*is_already_requested=*/false, reason));
-
-    std::move(callback).Run(CreateSupervisedUserInterstitialErrorDecision());
+  // SupervisedUserService is not created for the off-the-record browser state.
+  if (chrome_browser_state->IsOffTheRecord()) {
+    std::move(callback).Run(PolicyDecision::Allow());
     return;
   }
 
-  std::move(callback).Run(web::WebStatePolicyDecider::PolicyDecision::Allow());
+  supervised_user::SupervisedUserService* supervised_user_service =
+      SupervisedUserServiceFactory::GetForBrowserState(chrome_browser_state);
+
+  if (!supervised_user_service->IsURLFilteringEnabled()) {
+    std::move(callback).Run(PolicyDecision::Allow());
+    return;
+  }
+
+  // Set up the callback taking filtering results, and perform URL filtering.
+  GURL request_url = net::GURLWithNSURL(request.URL);
+  supervised_user::SupervisedUserURLFilter::FilteringBehaviorCallback
+      filtering_behavior_callback = base::BindOnce(
+          &OnURLFilteringDone, web_state()->GetWeakPtr(), request_url,
+          request_info.target_frame_is_main, std::move(callback));
+
+  supervised_user_service->GetURLFilter()
+      ->GetFilteringBehaviorForURLWithAsyncChecks(
+          request_url, std::move(filtering_behavior_callback),
+          /*skip_manual_parent_filter=*/false);
 }
 
 WEB_STATE_USER_DATA_KEY_IMPL(SupervisedUserURLFilterTabHelper)
diff --git a/ios/chrome/browser/supervised_user/supervised_user_url_filter_tab_helper_unittest.mm b/ios/chrome/browser/supervised_user/supervised_user_url_filter_tab_helper_unittest.mm
new file mode 100644
index 0000000..ad08cf6
--- /dev/null
+++ b/ios/chrome/browser/supervised_user/supervised_user_url_filter_tab_helper_unittest.mm
@@ -0,0 +1,203 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/supervised_user/supervised_user_url_filter_tab_helper.h"
+
+#import "base/memory/scoped_refptr.h"
+#import "base/task/single_thread_task_runner.h"
+#import "base/test/scoped_feature_list.h"
+#import "components/signin/public/identity_manager/account_capabilities_test_mutator.h"
+#import "components/signin/public/identity_manager/identity_manager.h"
+#import "components/signin/public/identity_manager/identity_test_utils.h"
+#import "components/supervised_user/core/browser/kids_chrome_management_client.h"
+#import "components/supervised_user/core/browser/kids_chrome_management_test_utils.h"
+#import "components/supervised_user/core/browser/supervised_user_service.h"
+#import "components/supervised_user/core/browser/supervised_user_settings_service.h"
+#import "components/supervised_user/core/common/features.h"
+#import "components/sync_preferences/pref_service_mock_factory.h"
+#import "components/sync_preferences/pref_service_syncable.h"
+#import "ios/chrome/browser/shared/model/application_context/application_context.h"
+#import "ios/chrome/browser/shared/model/browser_state/test_chrome_browser_state.h"
+#import "ios/chrome/browser/shared/model/browser_state/test_chrome_browser_state_manager.h"
+#import "ios/chrome/browser/shared/model/prefs/browser_prefs.h"
+#import "ios/chrome/browser/signin/identity_manager_factory.h"
+#import "ios/chrome/browser/signin/identity_test_environment_browser_state_adaptor.h"
+#import "ios/chrome/browser/supervised_user/child_account_service_factory.h"
+#import "ios/chrome/browser/supervised_user/supervised_user_error_container.h"
+#import "ios/chrome/browser/supervised_user/supervised_user_service_factory.h"
+#import "ios/chrome/browser/supervised_user/supervised_user_settings_service_factory.h"
+#import "ios/chrome/test/testing_application_context.h"
+#import "ios/web/public/navigation/web_state_policy_decider.h"
+#import "ios/web/public/test/fakes/fake_web_state.h"
+#import "ios/web/public/test/web_task_environment.h"
+#import "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#import "services/network/test/test_url_loader_factory.h"
+#import "testing/gtest/include/gtest/gtest.h"
+#import "testing/platform_test.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+
+const char kTestEmail[] = "test@gmail.com";
+
+}  // namespace
+
+class SupervisedUserURLFilterTabHelperTest : public PlatformTest {
+ protected:
+  SupervisedUserURLFilterTabHelperTest() {
+    TestChromeBrowserState::Builder builder;
+    builder.AddTestingFactory(
+        IdentityManagerFactory::GetInstance(),
+        base::BindRepeating(IdentityTestEnvironmentBrowserStateAdaptor::
+                                BuildIdentityManagerForTests));
+
+    chrome_browser_state_ = builder.Build();
+    web_state_.SetBrowserState(chrome_browser_state_.get());
+    SupervisedUserURLFilterTabHelper::CreateForWebState(&web_state_);
+    SupervisedUserErrorContainer::CreateForWebState(&web_state_);
+
+    kids_chrome_management_client_ =
+        std::make_unique<kids_management::KidsChromeManagementClientForTesting>(
+            base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+                &test_url_loader_factory_),
+            IdentityManagerFactory::GetForBrowserState(
+                chrome_browser_state_.get()));
+  }
+
+  void SetUp() override {
+    scoped_feature_list_.InitWithFeatures(
+        {supervised_user::kEnableSupervisionOnDesktopAndIOS,
+         supervised_user::kFilterWebsitesForSupervisedUsersOnDesktopAndIOS},
+        {});
+  }
+
+  // Signs the user into `email` as the primary Chrome account and sets the
+  // given parental control capabilities on this account.
+  void SignIn(const std::string& email, bool is_subject_to_parental_controls) {
+    AccountInfo account = signin::MakePrimaryAccountAvailable(
+        IdentityManagerFactory::GetForBrowserState(chrome_browser_state_.get()),
+        email, signin::ConsentLevel::kSignin);
+    AccountCapabilitiesTestMutator mutator(&account.capabilities);
+    mutator.set_is_subject_to_parental_controls(
+        is_subject_to_parental_controls);
+    signin::UpdateAccountInfoForAccount(
+        IdentityManagerFactory::GetForBrowserState(chrome_browser_state_.get()),
+        account);
+
+    // Initialize supervised_user services.
+    SupervisedUserSettingsServiceFactory::GetForBrowserState(
+        chrome_browser_state_.get())
+        ->Init(chrome_browser_state_->GetStatePath(),
+               chrome_browser_state_->GetIOTaskRunner().get(),
+               /*load_synchronously=*/true);
+    ChildAccountServiceFactory::GetForBrowserState(chrome_browser_state_.get())
+        ->Init();
+
+    supervised_user::SupervisedUserService* supervised_user_service =
+        SupervisedUserServiceFactory::GetForBrowserState(
+            chrome_browser_state_.get());
+    supervised_user_service->Init();
+
+    EXPECT_EQ(supervised_user_service->IsSubjectToParentalControls(),
+              is_subject_to_parental_controls);
+
+    // Set up the AsyncURLChecker with KidsChromeManagementClientForTesting.
+    supervised_user_service->GetURLFilter()->InitAsyncURLChecker(
+        kids_chrome_management_client_.get());
+  }
+
+  // Calls `ShouldAllowRequest` for a request with the given `url_string` and
+  // whether whether the navigation target frame is the main frame.
+  // Returns true if the URL request is blocked.
+  bool IsURLBlocked(NSString* url_string, bool target_frame_is_main) {
+    // Prepare the mock client response.
+    std::unique_ptr<kids_chrome_management::ClassifyUrlResponse>
+        response_proto = kids_management::BuildResponseProto(classification_);
+    kids_chrome_management_client_->SetResponseWithError(
+        std::move(response_proto),
+        KidsChromeManagementClient::ErrorCode::kSuccess);
+
+    // Set up for `ShouldAllowRequest`.
+    const web::WebStatePolicyDecider::RequestInfo request_info(
+        ui::PageTransition::PAGE_TRANSITION_LINK, target_frame_is_main,
+        /*target_frame_is_cross_origin=*/false,
+        /*has_user_gesture=*/false);
+    __block bool callback_called = false;
+    __block web::WebStatePolicyDecider::PolicyDecision request_policy =
+        web::WebStatePolicyDecider::PolicyDecision::Allow();
+    base::RunLoop run_loop;
+    auto quit_closure = run_loop.QuitClosure();
+    auto callback =
+        base::BindOnce(^(web::WebStatePolicyDecider::PolicyDecision decision) {
+          request_policy = decision;
+          callback_called = true;
+          std::move(quit_closure).Run();
+        });
+    web_state_.ShouldAllowRequest(
+        [NSURLRequest requestWithURL:[NSURL URLWithString:url_string]],
+        request_info, std::move(callback));
+    run_loop.Run();
+    EXPECT_TRUE(callback_called);
+
+    return request_policy.ShouldCancelNavigation();
+  }
+
+  // Returns true if the URL request is blocked for any navigation target frame.
+  bool IsURLBlocked(NSString* url_string) {
+    bool is_url_blocked_main_frame =
+        IsURLBlocked(url_string, /*target_frame_is_main=*/true);
+    bool is_url_blocked_sub_frame =
+        IsURLBlocked(url_string, /*target_frame_is_main=*/false);
+    EXPECT_EQ(is_url_blocked_main_frame, is_url_blocked_sub_frame);
+    return is_url_blocked_main_frame && is_url_blocked_sub_frame;
+  }
+
+  void AllowAllSitesForSupervisedUser() {
+    classification_ = safe_search_api::ClientClassification::kAllowed;
+  }
+
+  void RestrictAllSitesForSupervisedUser() {
+    classification_ = safe_search_api::ClientClassification::kRestricted;
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+  web::WebTaskEnvironment task_environment_;
+  network::TestURLLoaderFactory test_url_loader_factory_;
+  std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
+  web::FakeWebState web_state_;
+  std::unique_ptr<kids_management::KidsChromeManagementClientForTesting>
+      kids_chrome_management_client_;
+  safe_search_api::ClientClassification classification_;
+};
+
+TEST_F(SupervisedUserURLFilterTabHelperTest,
+       BlockCertainSitesForSupervisedUser) {
+  SignIn(kTestEmail,
+         /*is_subject_to_parental_controls=*/true);
+  RestrictAllSitesForSupervisedUser();
+  EXPECT_TRUE(IsURLBlocked(@"http://blockedurl.com"));
+  AllowAllSitesForSupervisedUser();
+  EXPECT_FALSE(IsURLBlocked(@"http://allowedurl.com"));
+}
+
+TEST_F(SupervisedUserURLFilterTabHelperTest,
+       AllowsAllSitesForNonSupervisedUser) {
+  SignIn(kTestEmail,
+         /*is_subject_to_parental_controls=*/false);
+  RestrictAllSitesForSupervisedUser();
+  EXPECT_FALSE(IsURLBlocked(@"http://blockedurl.com"));
+  AllowAllSitesForSupervisedUser();
+  EXPECT_FALSE(IsURLBlocked(@"http://allowedurl.com"));
+}
+
+TEST_F(SupervisedUserURLFilterTabHelperTest, AllowsAllSitesWhenLoggedOut) {
+  RestrictAllSitesForSupervisedUser();
+  EXPECT_FALSE(IsURLBlocked(@"http://blockedurl.com"));
+  AllowAllSitesForSupervisedUser();
+  EXPECT_FALSE(IsURLBlocked(@"http://allowedurl.com"));
+}
diff --git a/ios/chrome/browser/ui/authentication/cells/signin_promo_view_consumer.h b/ios/chrome/browser/ui/authentication/cells/signin_promo_view_consumer.h
index cf475441..7475c1f 100644
--- a/ios/chrome/browser/ui/authentication/cells/signin_promo_view_consumer.h
+++ b/ios/chrome/browser/ui/authentication/cells/signin_promo_view_consumer.h
@@ -26,6 +26,9 @@
 
 @optional
 
+// Called when the sign-in in progress status changes.
+- (void)promoProgressStateDidChange;
+
 // Called when the sign-in is finished.
 - (void)signinDidFinish;
 
diff --git a/ios/chrome/browser/ui/authentication/signed_in_accounts/signed_in_accounts_table_view_controller.mm b/ios/chrome/browser/ui/authentication/signed_in_accounts/signed_in_accounts_table_view_controller.mm
index 4e90271e..80e554d0 100644
--- a/ios/chrome/browser/ui/authentication/signed_in_accounts/signed_in_accounts_table_view_controller.mm
+++ b/ios/chrome/browser/ui/authentication/signed_in_accounts/signed_in_accounts_table_view_controller.mm
@@ -51,6 +51,8 @@
                       (ChromeAccountManagerService*)accountManagerService {
   self = [super initWithStyle:UITableViewStylePlain];
   if (self) {
+    CHECK(identityManager);
+    CHECK(accountManagerService);
     _identityManager = identityManager;
     _accountManagerService = accountManagerService;
     _accountManagerServiceObserver.reset(
diff --git a/ios/chrome/browser/ui/authentication/signed_in_accounts/signed_in_accounts_view_controller.mm b/ios/chrome/browser/ui/authentication/signed_in_accounts/signed_in_accounts_view_controller.mm
index ca22b1a4..a25f2d0 100644
--- a/ios/chrome/browser/ui/authentication/signed_in_accounts/signed_in_accounts_view_controller.mm
+++ b/ios/chrome/browser/ui/authentication/signed_in_accounts/signed_in_accounts_view_controller.mm
@@ -84,6 +84,8 @@
                               (id<ApplicationSettingsCommands>)dispatcher {
   self = [super initWithNibName:nil bundle:nil];
   if (self) {
+    CHECK(browserState);
+    CHECK(dispatcher);
     _browserState = browserState;
     _dispatcher = dispatcher;
     _identityManager =
@@ -137,6 +139,7 @@
   _identityManager = nullptr;
   _identityManagerObserver.reset();
   _dispatcher = nil;
+  _browserState = nullptr;
 }
 
 #pragma mark UIViewController
diff --git a/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.h b/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.h
index 3cc42a8..8c9e76b 100644
--- a/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.h
+++ b/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.h
@@ -7,6 +7,7 @@
 
 #import <Foundation/Foundation.h>
 
+#import "components/sync/base/model_type.h"
 #import "ios/chrome/browser/ui/authentication/cells/signin_promo_view.h"
 #import "ios/chrome/browser/ui/authentication/cells/signin_promo_view_delegate.h"
 
@@ -23,6 +24,10 @@
 enum class AccessPoint;
 }
 
+namespace syncer {
+class SyncService;
+}
+
 namespace ios {
 // Enums for the sign-in promo view state. Those states are sequential, with no
 // way to go backwards. All states can be skipped except `NeverVisible` and
@@ -100,6 +105,7 @@
               (ChromeAccountManagerService*)accountManagerService
                     authService:(AuthenticationService*)authService
                     prefService:(PrefService*)prefService
+                    syncService:(syncer::SyncService*)syncService
                     accessPoint:(signin_metrics::AccessPoint)accessPoint
                       presenter:(id<SigninPresenter>)presenter
              baseViewController:(UIViewController*)baseViewController
@@ -116,6 +122,9 @@
 // never been shown, or it is already hidden, this method does nothing.
 - (void)signinPromoViewIsHidden;
 
+// Set the data type that should be synced before the sign-in completes.
+- (void)setDataTypeToWaitForInitialSync:(syncer::ModelType)dataType;
+
 // Disconnects the mediator, this method needs to be called when the sign-in
 // promo view is removed from the view hierarchy (it or one of its superviews is
 // removed). The mediator should not be used after this called.
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 36835966..c4b206e 100644
--- a/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.mm
+++ b/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.mm
@@ -24,6 +24,7 @@
 #import "ios/chrome/browser/signin/chrome_account_manager_service.h"
 #import "ios/chrome/browser/signin/chrome_account_manager_service_observer_bridge.h"
 #import "ios/chrome/browser/signin/system_identity.h"
+#import "ios/chrome/browser/sync/sync_observer_bridge.h"
 #import "ios/chrome/browser/ui/authentication/authentication_flow.h"
 #import "ios/chrome/browser/ui/authentication/cells/signin_promo_view_configurator.h"
 #import "ios/chrome/browser/ui/authentication/cells/signin_promo_view_consumer.h"
@@ -496,7 +497,8 @@
 }  // namespace
 
 @interface SigninPromoViewMediator () <ChromeAccountManagerServiceObserver,
-                                       IdentityChooserCoordinatorDelegate>
+                                       IdentityChooserCoordinatorDelegate,
+                                       SyncObserverModelBridge>
 
 // Redefined to be readwrite.
 @property(nonatomic, strong, readwrite) id<SystemIdentity> identity;
@@ -539,6 +541,10 @@
   UIViewController* _baseViewController;
   // Sign-in flow, used only when `self.signInOnly` is `YES`.
   AuthenticationFlow* _authenticationFlow;
+  // Sync service.
+  syncer::SyncService* _syncService;
+  // Observer for changes to the sync state.
+  std::unique_ptr<SyncObserverBridge> _syncObserverBridge;
   // Coordinator for the user to select an account.
   IdentityChooserCoordinator* _identityChooserCoordinator;
   // Coordinator to add an account.
@@ -546,6 +552,8 @@
   // TODO(crbug.com/1448830): This class should not need to block the UI.
   // The UI blocker is only used in sign-in only cases.
   std::unique_ptr<ScopedUIBlocker> _uiBlocker;
+  // The type of data that should be synced before the sign-in completes.
+  syncer::ModelType _dataTypeToWaitForInitialSync;
 }
 
 + (void)registerBrowserStatePrefs:(user_prefs::PrefRegistrySyncable*)registry {
@@ -634,6 +642,7 @@
               (ChromeAccountManagerService*)accountManagerService
                     authService:(AuthenticationService*)authService
                     prefService:(PrefService*)prefService
+                    syncService:(syncer::SyncService*)syncService
                     accessPoint:(signin_metrics::AccessPoint)accessPoint
                       presenter:(id<SigninPresenter>)presenter
              baseViewController:(UIViewController*)baseViewController {
@@ -645,12 +654,20 @@
     _accountManagerService = accountManagerService;
     _authService = authService;
     _prefService = prefService;
+    _syncService = syncService;
     _accessPoint = accessPoint;
+    _dataTypeToWaitForInitialSync = syncer::ModelType::UNSPECIFIED;
     _presenter = presenter;
     _baseViewController = baseViewController;
     _accountManagerServiceObserver =
         std::make_unique<ChromeAccountManagerServiceObserverBridge>(
             self, _accountManagerService);
+    // Starting the sync state observation enables the sign-in progress to be
+    // set to YES even if the user hasn't interacted with the promo. It is
+    // intentional to keep UX consistency, given the initial sync cancellation
+    // which should end the sign-in progress is tricky to detect.
+    _syncObserverBridge =
+        std::make_unique<SyncObserverBridge>(self, _syncService);
 
     id<SystemIdentity> defaultIdentity = [self defaultIdentity];
     if (defaultIdentity) {
@@ -758,12 +775,19 @@
   self.signinPromoViewVisible = NO;
 }
 
+- (void)setDataTypeToWaitForInitialSync:(syncer::ModelType)dataType {
+  _dataTypeToWaitForInitialSync = dataType;
+  [self updateSignInProgressWithSyncState];
+}
+
 - (void)disconnect {
   [self signinPromoViewIsRemoved];
   self.consumer = nil;
   self.accountManagerService = nullptr;
   self.authService = nullptr;
+  _syncService = nullptr;
   _accountManagerServiceObserver.reset();
+  _syncObserverBridge.reset();
 }
 
 #pragma mark - Public properties
@@ -825,6 +849,10 @@
   }
   _signinInProgress = signinInProgress;
   SigninPromoViewConfigurator* configurator = [self createConfigurator];
+  if ([self.consumer
+          respondsToSelector:@selector(promoProgressStateDidChange)]) {
+    [self.consumer promoProgressStateDidChange];
+  }
   [self.consumer configureSigninPromoWithConfigurator:configurator
                                       identityChanged:NO];
 }
@@ -945,6 +973,10 @@
   __weak __typeof(self) weakSelf = self;
   [_authenticationFlow startSignInWithCompletion:^(BOOL success) {
     [weakSelf signInFlowCompletedForSignInOnly];
+    if ([weakSelf shouldWaitForInitialSync]) {
+      return;
+    }
+    weakSelf.signinInProgress = NO;
     if ([weakConsumer respondsToSelector:@selector(signinDidFinish)]) {
       [weakConsumer signinDidFinish];
     }
@@ -956,7 +988,6 @@
 - (void)signInFlowCompletedForSignInOnly {
   DCHECK(self.signInOnly) << base::SysNSStringToUTF8([self description]);
   _uiBlocker.reset();
-  self.signinInProgress = NO;
 }
 
 - (void)startAddAccountForSignInOnly {
@@ -1029,6 +1060,29 @@
                                                      displayedCount);
 }
 
+// Whether the sign-in needs to wait for the end of the initial sync to
+// complete.
+- (BOOL)shouldWaitForInitialSync {
+  return _dataTypeToWaitForInitialSync != syncer::ModelType::UNSPECIFIED;
+}
+
+// If initial sync is needed before the sign-in completes, set the
+// `signinInProgress` according to the initial sync state.
+- (void)updateSignInProgressWithSyncState {
+  if (![self shouldWaitForInitialSync]) {
+    return;
+  }
+  self.signinInProgress = [self isPerformingInitialSync];
+}
+
+// Whether the initial sync of the ModelType given by
+// `_dataTypeToWaitForInitialSync` is in progress.
+- (BOOL)isPerformingInitialSync {
+  CHECK(_dataTypeToWaitForInitialSync != syncer::ModelType::UNSPECIFIED);
+  return _syncService->GetTypesWithPendingDownloadForInitialSync().Has(
+      _dataTypeToWaitForInitialSync);
+}
+
 #pragma mark - ChromeAccountManagerServiceObserver
 
 - (void)identityListChanged {
@@ -1175,6 +1229,29 @@
   [self startSignInOnlyFlow];
 }
 
+#pragma mark - SyncObserverModelBridge
+
+// If additional data sync is needed during sign-in, update `signinInProgress`
+// to match the sync progress state when the sync state changes. This is needed
+// especially when the sign-in is undone during initial sync and
+// `onSyncConfigurationCompleted` is not called.
+- (void)onSyncStateChanged {
+  [self updateSignInProgressWithSyncState];
+}
+
+// If additional data sync is needed during sign-in, set `signinInProgress`
+// to NO when the initial sync finishes for the data type.
+- (void)onSyncConfigurationCompleted {
+  if (![self shouldWaitForInitialSync] || [self isPerformingInitialSync]) {
+    return;
+  }
+  // Handle sign-in completion.
+  self.signinInProgress = NO;
+  if ([self.consumer respondsToSelector:@selector(signinDidFinish)]) {
+    [self.consumer signinDidFinish];
+  }
+}
+
 #pragma mark - NSObject
 
 - (NSString*)description {
diff --git a/ios/chrome/browser/ui/authentication/signin_promo_view_mediator_unittest.mm b/ios/chrome/browser/ui/authentication/signin_promo_view_mediator_unittest.mm
index bfda9a76..8d50295 100644
--- a/ios/chrome/browser/ui/authentication/signin_promo_view_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/authentication/signin_promo_view_mediator_unittest.mm
@@ -113,6 +113,7 @@
                                       chrome_browser_state_.get())
                   authService:GetAuthenticationService()
                   prefService:chrome_browser_state_.get()->GetPrefs()
+                  syncService:GetSyncService()
                   accessPoint:access_point
                     presenter:nil
            baseViewController:nil];
@@ -143,6 +144,10 @@
         chrome_browser_state_.get());
   }
 
+  syncer::SyncService* GetSyncService() {
+    return SyncServiceFactory::GetForBrowserState(chrome_browser_state_.get());
+  }
+
   // Creates the default identity and adds it into the ChromeIdentityService.
   void AddDefaultIdentity() {
     fake_system_identity_manager()->AddIdentity(identity_);
@@ -455,6 +460,7 @@
                            signin_metrics::PromoAction::
                                PROMO_ACTION_NEW_ACCOUNT_NO_EXISTING_ACCOUNT
                         completion:completion_arg]);
+  OCMExpect([consumer_ promoProgressStateDidChange]);
   ExpectConfiguratorNotification(NO /* identity changed */);
   [mediator_ signinPromoViewDidTapSigninWithNewAccount:signin_promo_view_];
   EXPECT_TRUE(mediator_.signinInProgress);
@@ -462,6 +468,7 @@
             mediator_.signinPromoViewState);
   EXPECT_NE(nil, (id)completion);
   // Stop sign-in.
+  OCMExpect([consumer_ promoProgressStateDidChange]);
   OCMExpect([consumer_ signinDidFinish]);
   ExpectConfiguratorNotification(NO /* identity changed */);
   completion(YES);
@@ -489,6 +496,7 @@
                            signin_metrics::PromoAction::
                                PROMO_ACTION_NEW_ACCOUNT_NO_EXISTING_ACCOUNT
                         completion:completion_arg]);
+  OCMExpect([consumer_ promoProgressStateDidChange]);
   ExpectConfiguratorNotification(NO /* identity changed */);
   // Starts sign-in without identity.
   [mediator_ signinPromoViewDidTapSigninWithNewAccount:signin_promo_view_];
@@ -497,6 +505,7 @@
   // No consumer notification should be expected.
   fake_system_identity_manager()->WaitForServiceCallbacksToComplete();
   // Finishs the sign-in.
+  OCMExpect([consumer_ promoProgressStateDidChange]);
   OCMExpect([consumer_ signinDidFinish]);
   ExpectConfiguratorNotification(NO /* identity changed */);
   completion(YES);
@@ -520,6 +529,7 @@
                                    promoAction:signin_metrics::PromoAction::
                                                    PROMO_ACTION_WITH_DEFAULT
                                     completion:completion_arg]);
+  OCMExpect([consumer_ promoProgressStateDidChange]);
   ExpectConfiguratorNotification(NO /* identity changed */);
   // Starts sign-in with an identity.
   [mediator_ signinPromoViewDidTapSigninWithDefaultAccount:signin_promo_view_];
@@ -532,6 +542,7 @@
   // Spins the run loop to wait for the profile image update.
   fake_system_identity_manager()->WaitForServiceCallbacksToComplete();
   // Finishs the sign-in.
+  OCMExpect([consumer_ promoProgressStateDidChange]);
   OCMExpect([consumer_ signinDidFinish]);
   ExpectConfiguratorNotification(NO /* identity changed */);
   completion(YES);
@@ -594,6 +605,7 @@
                                    promoAction:signin_metrics::PromoAction::
                                                    PROMO_ACTION_WITH_DEFAULT
                                     completion:completion_arg]);
+  OCMExpect([consumer_ promoProgressStateDidChange]);
   ExpectConfiguratorNotification(NO /* identity changed */);
   // Start sign-in with an identity.
   [mediator_ signinPromoViewDidTapSigninWithDefaultAccount:signin_promo_view_];
@@ -626,6 +638,7 @@
                                    promoAction:signin_metrics::PromoAction::
                                                    PROMO_ACTION_WITH_DEFAULT
                                     completion:completion_arg]);
+  OCMExpect([consumer_ promoProgressStateDidChange]);
   ExpectConfiguratorNotification(NO /* identity changed */);
   // Start sign-in with an identity.
   [mediator_ signinPromoViewDidTapSigninWithDefaultAccount:signin_promo_view_];
diff --git a/ios/chrome/browser/ui/authentication/signout_action_sheet_coordinator.mm b/ios/chrome/browser/ui/authentication/signout_action_sheet_coordinator.mm
index 879ae8c..75a0647a 100644
--- a/ios/chrome/browser/ui/authentication/signout_action_sheet_coordinator.mm
+++ b/ios/chrome/browser/ui/authentication/signout_action_sheet_coordinator.mm
@@ -93,6 +93,10 @@
   self.actionSheetCoordinator = nil;
 }
 
+- (void)dealloc {
+  DCHECK(!self.actionSheetCoordinator);
+}
+
 #pragma mark - ActionSheetCoordinator properties
 
 - (NSString*)title {
diff --git a/ios/chrome/browser/ui/authentication/signout_action_sheet_coordinator_unittest.mm b/ios/chrome/browser/ui/authentication/signout_action_sheet_coordinator_unittest.mm
index b193843c..f490b04a 100644
--- a/ios/chrome/browser/ui/authentication/signout_action_sheet_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/authentication/signout_action_sheet_coordinator_unittest.mm
@@ -71,6 +71,12 @@
         SyncSetupServiceFactory::GetForBrowserState(browser_state_.get()));
   }
 
+  void TearDown() override {
+    [signout_coordinator_ stop];
+    signout_coordinator_ = nil;
+    PlatformTest::TearDown();
+  }
+
   // Identity services.
   AuthenticationService* authentication_service() {
     return AuthenticationServiceFactory::GetForBrowserState(
diff --git a/ios/chrome/browser/ui/bookmarks/home/bookmark_promo_controller.h b/ios/chrome/browser/ui/bookmarks/home/bookmark_promo_controller.h
index 4ffe2ea..1163b2d9 100644
--- a/ios/chrome/browser/ui/bookmarks/home/bookmark_promo_controller.h
+++ b/ios/chrome/browser/ui/bookmarks/home/bookmark_promo_controller.h
@@ -12,6 +12,10 @@
 @class SigninPromoViewConfigurator;
 @class SigninPromoViewMediator;
 
+namespace syncer {
+class SyncService;
+}
+
 @protocol BookmarkPromoControllerDelegate
 
 // Controls the state of the promo.
@@ -46,6 +50,7 @@
 // Designated initializer.
 // `baseViewController` is the view to present UI for sign-in.
 - (instancetype)initWithBrowser:(Browser*)browser
+                    syncService:(syncer::SyncService*)syncService
                        delegate:(id<BookmarkPromoControllerDelegate>)delegate
                       presenter:(id<SigninPresenter>)presenter
              baseViewController:(UIViewController*)baseViewController
diff --git a/ios/chrome/browser/ui/bookmarks/home/bookmark_promo_controller.mm b/ios/chrome/browser/ui/bookmarks/home/bookmark_promo_controller.mm
index d40ba12..aacdaa6 100644
--- a/ios/chrome/browser/ui/bookmarks/home/bookmark_promo_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/home/bookmark_promo_controller.mm
@@ -42,6 +42,7 @@
 }
 
 - (instancetype)initWithBrowser:(Browser*)browser
+                    syncService:(syncer::SyncService*)syncService
                        delegate:(id<BookmarkPromoControllerDelegate>)delegate
                       presenter:(id<SigninPresenter>)presenter
              baseViewController:(UIViewController*)baseViewController {
@@ -62,11 +63,17 @@
                   authService:AuthenticationServiceFactory::GetForBrowserState(
                                   browserState)
                   prefService:browserState->GetPrefs()
+                  syncService:syncService
                   accessPoint:signin_metrics::AccessPoint::
                                   ACCESS_POINT_BOOKMARK_MANAGER
                     presenter:presenter
            baseViewController:baseViewController];
     _signinPromoViewMediator.consumer = self;
+    if (base::FeatureList::IsEnabled(
+            bookmarks::kEnableBookmarksAccountStorage)) {
+      [_signinPromoViewMediator
+          setDataTypeToWaitForInitialSync:syncer::ModelType::BOOKMARKS];
+    }
     [self updateShouldShowSigninPromo];
   }
   return self;
@@ -147,7 +154,8 @@
     _signinPromoViewMediator.signInOnly = NO;
     return;
   }
-  if ([self.delegate isPerformingInitialSync]) {
+
+  if (self.signinPromoViewMediator.signinInProgress) {
     // The user is opted into syncing bookmarks, but the first sync is not
     // finished yet - keep the promo visible to show the spinner.
     self.shouldShowSigninPromo = YES;
@@ -184,6 +192,10 @@
                                       identityChanged:identityChanged];
 }
 
+- (void)promoProgressStateDidChange {
+  [self updateShouldShowSigninPromo];
+}
+
 - (void)signinDidFinish {
   [self updateShouldShowSigninPromo];
 }
diff --git a/ios/chrome/browser/ui/bookmarks/home/bookmarks_home_mediator.mm b/ios/chrome/browser/ui/bookmarks/home/bookmarks_home_mediator.mm
index d6e9ca7..7630b08 100644
--- a/ios/chrome/browser/ui/bookmarks/home/bookmarks_home_mediator.mm
+++ b/ios/chrome/browser/ui/bookmarks/home/bookmarks_home_mediator.mm
@@ -146,8 +146,10 @@
   _syncedBookmarksObserver =
       std::make_unique<sync_bookmarks::SyncedBookmarksObserverBridge>(
           self, browserState);
+  _syncService = SyncServiceFactory::GetForBrowserState(browserState);
   _bookmarkPromoController =
       [[BookmarkPromoController alloc] initWithBrowser:_browser.get()
+                                           syncService:_syncService
                                               delegate:self
                                              presenter:self
                                     baseViewController:_baseViewController];
@@ -162,8 +164,6 @@
   _prefObserverBridge->ObserveChangesForPreference(
       bookmarks::prefs::kManagedBookmarks, _prefChangeRegistrar.get());
 
-  _syncService = SyncServiceFactory::GetForBrowserState(browserState);
-
   [self computePromoTableViewData];
   [self computeBookmarkTableViewData];
 }
diff --git a/ios/chrome/browser/ui/ntp/feed_top_section/BUILD.gn b/ios/chrome/browser/ui/ntp/feed_top_section/BUILD.gn
index 5adb9041..e64b9434 100644
--- a/ios/chrome/browser/ui/ntp/feed_top_section/BUILD.gn
+++ b/ios/chrome/browser/ui/ntp/feed_top_section/BUILD.gn
@@ -25,6 +25,7 @@
     "//ios/chrome/browser/shared/model/browser_state",
     "//ios/chrome/browser/shared/public/commands",
     "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/sync",
     "//ios/chrome/browser/ui/authentication",
     "//ios/chrome/browser/ui/authentication:signin_presenter",
     "//ios/chrome/browser/ui/authentication/cells",
diff --git a/ios/chrome/browser/ui/ntp/feed_top_section/feed_top_section_coordinator.mm b/ios/chrome/browser/ui/ntp/feed_top_section/feed_top_section_coordinator.mm
index d92987a..5d5ffd41 100644
--- a/ios/chrome/browser/ui/ntp/feed_top_section/feed_top_section_coordinator.mm
+++ b/ios/chrome/browser/ui/ntp/feed_top_section/feed_top_section_coordinator.mm
@@ -14,6 +14,7 @@
 #import "ios/chrome/browser/signin/chrome_account_manager_service.h"
 #import "ios/chrome/browser/signin/chrome_account_manager_service_factory.h"
 #import "ios/chrome/browser/signin/identity_manager_factory.h"
+#import "ios/chrome/browser/sync/sync_service_factory.h"
 #import "ios/chrome/browser/ui/authentication/signin_presenter.h"
 #import "ios/chrome/browser/ui/authentication/signin_promo_view_mediator.h"
 #import "ios/chrome/browser/ui/ntp/feed_top_section/feed_top_section_mediator.h"
@@ -51,6 +52,8 @@
       IdentityManagerFactory::GetForBrowserState(browserState);
   AuthenticationService* authenticationService =
       AuthenticationServiceFactory::GetForBrowserState(browserState);
+  syncer::SyncService* syncService =
+      SyncServiceFactory::GetForBrowserState(browserState);
   self.feedTopSectionMediator = [[FeedTopSectionMediator alloc]
       initWithConsumer:self.feedTopSectionViewController
        identityManager:identityManager
@@ -65,6 +68,7 @@
                 authService:AuthenticationServiceFactory::GetForBrowserState(
                                 browserState)
                 prefService:browserState->GetPrefs()
+                syncService:syncService
                 accessPoint:signin_metrics::AccessPoint::
                                 ACCESS_POINT_NTP_FEED_TOP_PROMO
                   presenter:self
diff --git a/ios/chrome/browser/ui/promos_manager/promos_manager_coordinator.mm b/ios/chrome/browser/ui/promos_manager/promos_manager_coordinator.mm
index 39cd66d60..8364f77 100644
--- a/ios/chrome/browser/ui/promos_manager/promos_manager_coordinator.mm
+++ b/ios/chrome/browser/ui/promos_manager/promos_manager_coordinator.mm
@@ -81,8 +81,8 @@
       std::map<promos_manager::Promo, id<StandardPromoAlertProvider>>>
       _alertProviderPromos;
 
-  // The currently displayed promo, if any.
-  absl::optional<promos_manager::Promo> current_promo;
+  // The currently displayed promo data, if any.
+  absl::optional<PromoDisplayData> _currentPromoData;
 }
 
 // A mediator that observes when it's a good time to display a promo.
@@ -170,7 +170,7 @@
 }
 
 - (void)displayPromoCallback:(BOOL)isFirstShownPromo {
-  absl::optional<promos_manager::Promo> nextPromoForDisplay =
+  absl::optional<PromoDisplayData> nextPromoForDisplay =
       [self.mediator nextPromoForDisplay:isFirstShownPromo];
 
   if (nextPromoForDisplay.has_value()) {
@@ -197,9 +197,10 @@
 }
 
 - (void)promoWasDismissed {
-  if (ShouldPromosManagerUseFET() && current_promo.has_value()) {
+  if (ShouldPromosManagerUseFET() && _currentPromoData.has_value() &&
+      !_currentPromoData.value().was_forced) {
     PromoConfigsSet configs = [self promoImpressionLimits];
-    auto it = configs.find(current_promo.value());
+    auto it = configs.find(_currentPromoData.value().promo);
     if (it == configs.end() || !it->feature_engagement_feature) {
       return;
     }
@@ -209,25 +210,27 @@
             self.browser->GetBrowserState());
     tracker->Dismissed(*it->feature_engagement_feature);
   }
-  current_promo = absl::nullopt;
+  _currentPromoData = absl::nullopt;
 }
 
-- (void)displayPromo:(promos_manager::Promo)promo {
+- (void)displayPromo:(PromoDisplayData)promoData {
   if (tests_hook::DisablePromoManagerFullScreenPromos()) {
     return;
   }
 
+  promos_manager::Promo promo = promoData.promo;
+
   // Trying to display a promo while the previous dismissal was not communicated
   // back to the promos manager.
   // TODO(crbug.com/1452233): Remove once all promos dismiss themselves.
-  if (current_promo.has_value()) {
+  if (_currentPromoData.has_value()) {
     static crash_reporter::CrashKeyString<40> key("current-promo");
     crash_reporter::ScopedCrashKeyString crashKey(
-        &key, ShortNameForPromo(current_promo.value()));
+        &key, ShortNameForPromo(_currentPromoData.value().promo));
     base::debug::DumpWithoutCrashing();
   }
 
-  current_promo = promo;
+  _currentPromoData = promoData;
 
   auto handler_it = _displayHandlerPromos.find(promo);
   auto provider_it = _viewProviderPromos.find(promo);
diff --git a/ios/chrome/browser/ui/promos_manager/promos_manager_mediator.h b/ios/chrome/browser/ui/promos_manager/promos_manager_mediator.h
index 0b85b71c..ef77acdd 100644
--- a/ios/chrome/browser/ui/promos_manager/promos_manager_mediator.h
+++ b/ios/chrome/browser/ui/promos_manager/promos_manager_mediator.h
@@ -12,6 +12,12 @@
 #import "ios/chrome/browser/promos_manager/promos_manager.h"
 #import "third_party/abseil-cpp/absl/types/optional.h"
 
+// Data used and cached to know what promo to show.
+struct PromoDisplayData {
+  promos_manager::Promo promo;
+  bool was_forced;
+};
+
 // A mediator that (1) communicates with the PromosManager to find the next
 // promo (promos_manager::Promo), if any, to display, and (2) records the
 // display impression of said promo.
@@ -33,8 +39,7 @@
 // Queries the PromosManager for the next promo (promos_manager::Promo) to
 // display, if any. Allows for special behavior if this is the first promo
 // shown.
-- (absl::optional<promos_manager::Promo>)nextPromoForDisplay:
-    (BOOL)isFirstShownPromo;
+- (absl::optional<PromoDisplayData>)nextPromoForDisplay:(BOOL)isFirstShownPromo;
 
 // The Promos Manager used for deciding which promo should be displayed, if any.
 @property(nonatomic, assign) PromosManager* promosManager;
diff --git a/ios/chrome/browser/ui/promos_manager/promos_manager_mediator.mm b/ios/chrome/browser/ui/promos_manager/promos_manager_mediator.mm
index 4e816c41..3d86f353 100644
--- a/ios/chrome/browser/ui/promos_manager/promos_manager_mediator.mm
+++ b/ios/chrome/browser/ui/promos_manager/promos_manager_mediator.mm
@@ -39,7 +39,7 @@
   _promosManager->RecordImpression(promo);
 }
 
-- (absl::optional<promos_manager::Promo>)nextPromoForDisplay:
+- (absl::optional<PromoDisplayData>)nextPromoForDisplay:
     (BOOL)isFirstShownPromo {
   DCHECK_NE(_promosManager, nullptr);
   // Only check for a forced promo the first time around, to prevent infinite
@@ -50,10 +50,16 @@
     absl::optional<promos_manager::Promo> forcedPromo =
         [self forcedPromoToDisplay];
     if (forcedPromo) {
-      return forcedPromo;
+      return PromoDisplayData{.promo = forcedPromo.value(), .was_forced = true};
     }
   }
-  return self.promosManager->NextPromoForDisplay();
+
+  absl::optional<promos_manager::Promo> promo =
+      self.promosManager->NextPromoForDisplay();
+  if (promo) {
+    return PromoDisplayData{.promo = promo.value(), .was_forced = false};
+  }
+  return absl::nullopt;
 }
 
 // Returns the promo selected in the Force Promo experimental setting.
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_coordinator.mm b/ios/chrome/browser/ui/reading_list/reading_list_coordinator.mm
index 5f3dbd2..cb576c3 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_coordinator.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_coordinator.mm
@@ -205,12 +205,15 @@
       accountManagerService:accountManagerService
                 authService:_authService
                 prefService:_prefService
+                syncService:_syncService
                 accessPoint:signin_metrics::AccessPoint::
                                 ACCESS_POINT_READING_LIST
                   presenter:self
          baseViewController:self.tableViewController];
   _signinPromoViewMediator.signInOnly = YES;
   _signinPromoViewMediator.consumer = self;
+  [_signinPromoViewMediator
+      setDataTypeToWaitForInitialSync:syncer::ModelType::READING_LIST];
   [self updateSignInPromoVisibility];
 
   [super start];
@@ -575,6 +578,10 @@
                            identityChanged:identityChanged];
 }
 
+- (void)promoProgressStateDidChange {
+  [self updateSignInPromoVisibility];
+}
+
 - (void)signinDidFinish {
   [self updateSignInPromoVisibility];
 }
@@ -629,8 +636,12 @@
     self.shouldShowSignInPromo = NO;
     return;
   }
+
   if (_identityManager->HasPrimaryAccount(signin::ConsentLevel::kSignin)) {
-    self.shouldShowSignInPromo = NO;
+    // If the user is signed-in with the promo (thus opted-in for Reading List
+    // account storage), the promo should stay visible during the initial sync
+    // and a spinner should be shown on it.
+    self.shouldShowSignInPromo = _signinPromoViewMediator.signinInProgress;
   } else {
     const std::string lastSignedInGaiaId =
         _prefService->GetString(prefs::kGoogleServicesLastGaiaId);
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm b/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm
index a08c30d..9f329cb 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm
@@ -705,8 +705,7 @@
             (SigninPromoViewConfigurator*)promoConfigurator
                              identityChanged:(BOOL)identityChanged {
   if (![self.tableViewModel
-          hasSectionForSectionIdentifier:kSectionIdentifierSignInPromo] ||
-      !identityChanged) {
+          hasSectionForSectionIdentifier:kSectionIdentifierSignInPromo]) {
     return;
   }
 
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 522680b9..463fe5a 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
@@ -721,6 +721,7 @@
                   authService:AuthenticationServiceFactory::GetForBrowserState(
                                   self.browserState)
                   prefService:self.browserState->GetPrefs()
+                  syncService:self.syncService
                   accessPoint:signin_metrics::AccessPoint::
                                   ACCESS_POINT_RECENT_TABS
                     presenter:self
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_profile_table_view_controller.mm b/ios/chrome/browser/ui/settings/autofill/autofill_profile_table_view_controller.mm
index dbce625..93a3003b 100644
--- a/ios/chrome/browser/ui/settings/autofill/autofill_profile_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/autofill/autofill_profile_table_view_controller.mm
@@ -10,7 +10,10 @@
 #import "base/metrics/user_metrics.h"
 #import "base/metrics/user_metrics_action.h"
 #import "base/strings/sys_string_conversions.h"
+#import "base/strings/utf_string_conversions.h"
+#import "components/autofill/core/browser/geo/country_data.h"
 #import "components/autofill/core/browser/personal_data_manager.h"
+#import "components/autofill/core/browser/profile_requirement_utils.h"
 #import "components/autofill/core/common/autofill_features.h"
 #import "components/autofill/core/common/autofill_prefs.h"
 #import "components/autofill/ios/browser/personal_data_manager_observer_bridge.h"
@@ -263,13 +266,7 @@
         AutofillAddressProfileSource::AutofillSyncableProfile;
   } else {
     item.autofillProfileSource = AutofillLocalProfile;
-    if (base::FeatureList::IsEnabled(
-            autofill::features::kAutofillAccountProfileStorage) &&
-        base::FeatureList::IsEnabled(syncer::kSyncEnableContactInfoDataType) &&
-        base::FeatureList::IsEnabled(
-            syncer::kSyncEnableContactInfoDataTypeInTransportMode) &&
-        // Denotes that the user is signed-in.
-        self.userEmail != nil) {
+    if ([self shouldShowCloudOffIconForProfile:autofillProfile]) {
       item.image = CustomSymbolTemplateWithPointSize(
           kCloudSlashSymbol, kCloudSlashSymbolPointSize);
     }
@@ -761,4 +758,23 @@
   [self.autofillProfileEditCoordinator start];
 }
 
+// Returns YES if the cloud off icon should be shown next to the profile. Only
+// those profiles, that are eligible for the migration to Account show cloud off
+// icon.
+- (BOOL)shouldShowCloudOffIconForProfile:
+    (const autofill::AutofillProfile&)profile {
+  std::string country_code = base::UTF16ToUTF8(
+      profile.GetRawInfo(autofill::ServerFieldType::ADDRESS_HOME_COUNTRY));
+  const std::vector<std::string>& country_codes =
+      autofill::CountryDataMap::GetInstance()->country_codes();
+  return base::Contains(country_codes, country_code) &&
+         IsEligibleForMigrationToAccount(*_personalDataManager, profile) &&
+         base::FeatureList::IsEnabled(
+             syncer::kSyncEnableContactInfoDataTypeInTransportMode) &&
+         // Denotes that the user is signed-in.
+         self.userEmail != nil &&
+         IsMinimumAddress(profile, country_code,
+                          _personalDataManager->app_locale());
+}
+
 @end
diff --git a/ios/chrome/browser/ui/settings/google_services/google_services_settings_coordinator.mm b/ios/chrome/browser/ui/settings/google_services/google_services_settings_coordinator.mm
index 31c3ff1e..1123738 100644
--- a/ios/chrome/browser/ui/settings/google_services/google_services_settings_coordinator.mm
+++ b/ios/chrome/browser/ui/settings/google_services/google_services_settings_coordinator.mm
@@ -108,6 +108,11 @@
                                            animated:YES];
 }
 
+- (void)stop {
+  [self.signOutCoordinator stop];
+  _signOutCoordinator = nil;
+}
+
 #pragma mark - Private
 
 - (void)authenticationFlowDidComplete {
diff --git a/ios/chrome/browser/ui/settings/google_services/manage_sync_settings_coordinator.mm b/ios/chrome/browser/ui/settings/google_services/manage_sync_settings_coordinator.mm
index a81fbd4..499ae0a1 100644
--- a/ios/chrome/browser/ui/settings/google_services/manage_sync_settings_coordinator.mm
+++ b/ios/chrome/browser/ui/settings/google_services/manage_sync_settings_coordinator.mm
@@ -174,6 +174,8 @@
   syncSetupService->CommitSyncChanges();
 
   _syncObserver.reset();
+  [self.signoutActionSheetCoordinator stop];
+  _signoutActionSheetCoordinator = nil;
 }
 
 #pragma mark - Properties
diff --git a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
index 807fb7b4..bf08ae9 100644
--- a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
@@ -611,6 +611,8 @@
                     authService:AuthenticationServiceFactory::
                                     GetForBrowserState(_browserState)
                     prefService:_browserState->GetPrefs()
+                    syncService:SyncServiceFactory::GetForBrowserState(
+                                    _browserState)
                     accessPoint:signin_metrics::AccessPoint::
                                     ACCESS_POINT_SETTINGS
                       presenter:self
diff --git a/ios/chrome/browser/web/BUILD.gn b/ios/chrome/browser/web/BUILD.gn
index ef8bffd1..cbf6bd5 100644
--- a/ios/chrome/browser/web/BUILD.gn
+++ b/ios/chrome/browser/web/BUILD.gn
@@ -277,7 +277,6 @@
     "//ios/chrome/browser/open_from_clipboard",
     "//ios/chrome/browser/optimization_guide",
     "//ios/chrome/browser/passwords",
-    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/policy",
     "//ios/chrome/browser/prerender",
     "//ios/chrome/browser/promos_manager",
@@ -286,6 +285,7 @@
     "//ios/chrome/browser/search_engines",
     "//ios/chrome/browser/shared/model/application_context",
     "//ios/chrome/browser/shared/model/browser_state",
+    "//ios/chrome/browser/shared/model/paths",
     "//ios/chrome/browser/shared/model/prefs:pref_names",
     "//ios/chrome/browser/shared/model/url",
     "//ios/chrome/browser/shared/model/url:constants",
diff --git a/ios/chrome/test/earl_grey2/BUILD.gn b/ios/chrome/test/earl_grey2/BUILD.gn
index b4958a4d..a9c10f63 100644
--- a/ios/chrome/test/earl_grey2/BUILD.gn
+++ b/ios/chrome/test/earl_grey2/BUILD.gn
@@ -91,7 +91,6 @@
     "//ios/chrome/browser/policy_url_blocking:eg2_tests",
     "//ios/chrome/browser/prerender:eg2_tests",
     "//ios/chrome/browser/safe_browsing:eg2_tests",
-    "//ios/chrome/browser/supervised_user:eg2_tests",
     "//ios/chrome/browser/ui/autofill:eg2_tests",
     "//ios/chrome/browser/ui/autofill/branding:eg2_tests",
     "//ios/chrome/browser/ui/autofill/manual_fill:eg2_tests",
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
index 6f0e2ec6..9c213e3 100644
--- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-d6365ec598375f905de8c35a4a6b6a50e3843e1f
\ No newline at end of file
+d1b940509cf2479a8ea2097695fe7f172377f75e
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
index 3d151308..dab9686 100644
--- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-59525ff49d8eac61747f2638ff309de6df3b8b7e
\ No newline at end of file
+468289da5674685612458cbf2436e362567e9c75
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
index 8de1eed..181c80c 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-a0391ddd3b2b8e60deec1a91054ee97d5f173d4f
\ No newline at end of file
+b7223d41e49fb84afdb79238b7b41f07880bc6be
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
index 32b066f..55e40c09 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-05368807b9fd6f4ecfe720ecceb8121e9610533c
\ No newline at end of file
+9794e1b7f945743501337a6f27aebf4d4fa802bb
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
index c4fd716..cd5a4e2 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-083f1c8cf8b6bc2f9f23e7cb19f467b88e4a5d61
\ No newline at end of file
+a09ed1a882cf43d192c98ba3734285478ad69f5e
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
index e0db0b8..090e02f 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-e659499d525e5ebb7360bbc71cdcc9dcb001447f
\ No newline at end of file
+aea15d247dcdde4142dea1d5f9245166daa3e7f9
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
index c023d4a..ed23e87 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-5ae99231fcf60cb3c04cfd023b6890f7357150c9
\ No newline at end of file
+3e7a60d90053762d27e3aa2fda7a1012e382df57
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
index 33e121c..c8548d6 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-fd3d7fc5cb0c77e6eef6c369daea1483bacf9e51
\ No newline at end of file
+52dab00d433c6abacc059fd2715082b59c03987a
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
index 06f3f4c..0f72d005 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-9e397433f6aecc4c8c611fc2562d8281d51fc107
\ No newline at end of file
+ccca59fcb24a249d260e6edef472d90760b3d0a3
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
index da334a5..9f24d2b 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-10683931cd225e06bc9c92022c1d10d262491bbb
\ No newline at end of file
+bbe31d9999fbe4ff8864530fd600d7a7cc66a552
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
index 49256bf5..c6f3c9d 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-70c67676f4ea7ca005ebe889b1d883d319f2b4cd
\ No newline at end of file
+1dbc38e55d2ded1faeaf1bdcc37637df058eb7b4
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
index d1bdde02..71933b2 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-39f40a3cdd5860d92d6ee3b8000d3c1a20de4743
\ No newline at end of file
+9ef0a68d2dc57744c98e45711e9206bde3bcfade
\ No newline at end of file
diff --git a/ios/web/public/web_view_only/BUILD.gn b/ios/web/public/web_view_only/BUILD.gn
index b27f62a..29de8ba 100644
--- a/ios/web/public/web_view_only/BUILD.gn
+++ b/ios/web/public/web_view_only/BUILD.gn
@@ -12,8 +12,8 @@
   deps = [ "//ios/web/web_view_only" ]
 
   visibility = [
-    "//ios/web_view:*",
     "//ios/web/web_view_only:unittests",
+    "//ios/web_view:*",
   ]
 }
 
diff --git a/ipc/ipc_channel_mojo.cc b/ipc/ipc_channel_mojo.cc
index 50bb176..881322a 100644
--- a/ipc/ipc_channel_mojo.cc
+++ b/ipc/ipc_channel_mojo.cc
@@ -100,7 +100,7 @@
 
   const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
   const Forwarder forwarder_;
-  const raw_ref<mojo::AssociatedGroupController, DanglingUntriaged>
+  const raw_ref<mojo::AssociatedGroupController, DanglingAcrossTasks>
       group_controller_;
 };
 
diff --git a/media/audio/audio_device_stats_reporter.cc b/media/audio/audio_device_stats_reporter.cc
index 10426bd..9ae781e 100644
--- a/media/audio/audio_device_stats_reporter.cc
+++ b/media/audio/audio_device_stats_reporter.cc
@@ -45,13 +45,6 @@
                                   // delays up to 1s.
           /*bucket_count = */ 50,
           type)),
-      delay_difference_log_callback_(CreateAggregateCallback(
-          "DelayDifference",
-          params.latency_tag(),
-          /*max_value = */ 1000,  // Measured in ms. Allows us to differentiate
-                                  // delay differences up to 1s.
-          /*bucket_count = */ 50,
-          type)),
       glitch_count_log_callback_(CreateAggregateCallback(
           "GlitchCount",
           params.latency_tag(),
@@ -88,8 +81,6 @@
   ++stats_.callback_count;
   stats_.glitch_count += glitch_info.count;
   stats_.glitch_duration += glitch_info.duration;
-  stats_.largest_delay = std::max(delay, stats_.largest_delay);
-  stats_.smallest_delay = std::min(delay, stats_.smallest_delay);
 
   if (stats_.callback_count >= 1000) {
     UploadStats(stats_, SamplingPeriod::kIntervals);
@@ -111,21 +102,13 @@
   int glitch_duration_permille =
       std::round(1000 * stats.glitch_duration / stats_duration);
 
-  DCHECK_NE(stats.largest_delay, base::TimeDelta::Min());
-  DCHECK_NE(stats.smallest_delay, base::TimeDelta::Max());
-  int delay_difference_ms =
-      (stats.largest_delay - stats.smallest_delay).InMilliseconds();
-
   glitch_count_log_callback_.Run(stats.glitch_count, sampling_period);
-  delay_difference_log_callback_.Run(delay_difference_ms, sampling_period);
   glitch_duration_log_callback_.Run(glitch_duration_permille, sampling_period);
 }
 
 // Used to generate callbacks for:
-// Media.AudioOutputDevice.AudioServiceDelayDifference.*.*
 // Media.AudioOutputDevice.AudioServiceGlitchCount.*.*
 // Media.AudioOutputDevice.AudioServiceDroppedAudio.*.*
-// Media.AudioInputDevice.AudioServiceDelayDifference.*
 // Media.AudioInputDevice.AudioServiceGlitchCount.*
 // Media.AudioInputDevice.AudioServiceDroppedAudio.*
 // |latency| is ignored for input.
diff --git a/media/audio/audio_device_stats_reporter.h b/media/audio/audio_device_stats_reporter.h
index 6bf1fe38a..8e82f394 100644
--- a/media/audio/audio_device_stats_reporter.h
+++ b/media/audio/audio_device_stats_reporter.h
@@ -48,8 +48,6 @@
     int callback_count = 0;
     int glitch_count = 0;
     base::TimeDelta glitch_duration;
-    base::TimeDelta smallest_delay = base::TimeDelta::Max();
-    base::TimeDelta largest_delay = base::TimeDelta::Min();
   };
 
   // Logs data aggregated over intervals.
@@ -82,7 +80,6 @@
 
   // Callback functions for writing to the histograms.
   const RealtimeLogCallback delay_log_callback_;
-  const AggregateLogCallback delay_difference_log_callback_;
   const AggregateLogCallback glitch_count_log_callback_;
   const AggregateLogCallback glitch_duration_log_callback_;
 
diff --git a/media/audio/audio_device_stats_reporter_unittest.cc b/media/audio/audio_device_stats_reporter_unittest.cc
index 4d722ad..f68d3af 100644
--- a/media/audio/audio_device_stats_reporter_unittest.cc
+++ b/media/audio/audio_device_stats_reporter_unittest.cc
@@ -20,10 +20,6 @@
 namespace {
 
 const std::string kRenderDelay = "Media.AudioOutputDevice.AudioServiceDelay";
-const std::string kRenderDelayDifferenceShort =
-    "Media.AudioOutputDevice.AudioServiceDelayDifference.Short";
-const std::string kRenderDelayDifferenceIntervals =
-    "Media.AudioOutputDevice.AudioServiceDelayDifference.Intervals";
 const std::string kRenderGlitchCountShort =
     "Media.AudioOutputDevice.AudioServiceGlitchCount.Short";
 const std::string kRenderGlitchCountIntervals =
@@ -34,10 +30,6 @@
     "Media.AudioOutputDevice.AudioServiceGlitchDuration.Intervals";
 
 const std::string kCaptureDelay = "Media.AudioInputDevice.AudioServiceDelay";
-const std::string kCaptureDelayDifferenceShort =
-    "Media.AudioInputDevice.AudioServiceDelayDifference.Short";
-const std::string kCaptureDelayDifferenceIntervals =
-    "Media.AudioInputDevice.AudioServiceDelayDifference.Intervals";
 const std::string kCaptureGlitchCountShort =
     "Media.AudioInputDevice.AudioServiceGlitchCount.Short";
 const std::string kCaptureGlitchCountIntervals =
@@ -98,9 +90,6 @@
   histogram_tester_.ExpectBucketCount(kRenderDelay + latency_tag_, 60, 50);
   histogram_tester_.ExpectBucketCount(kRenderDelay, 140, 50);
   histogram_tester_.ExpectBucketCount(kRenderDelay + latency_tag_, 140, 50);
-  histogram_tester_.ExpectBucketCount(kRenderDelayDifferenceShort, 80, 1);
-  histogram_tester_.ExpectBucketCount(
-      kRenderDelayDifferenceShort + latency_tag_, 80, 1);
   histogram_tester_.ExpectBucketCount(kRenderGlitchCountShort, 50, 1);
   histogram_tester_.ExpectBucketCount(kRenderGlitchCountShort + latency_tag_,
                                       50, 1);
@@ -108,7 +97,6 @@
   histogram_tester_.ExpectBucketCount(kRenderGlitchDurationShort + latency_tag_,
                                       500, 1);
 
-  histogram_tester_.ExpectTotalCount(kRenderDelayDifferenceIntervals, 0);
   histogram_tester_.ExpectTotalCount(kRenderGlitchCountIntervals, 0);
   histogram_tester_.ExpectTotalCount(kRenderGlitchDurationIntervals, 0);
 }
@@ -152,9 +140,6 @@
   histogram_tester_.ExpectBucketCount(kRenderDelay, 140, 500);
   histogram_tester_.ExpectBucketCount(kRenderDelay + latency_tag_, 140, 500);
 
-  histogram_tester_.ExpectBucketCount(kRenderDelayDifferenceIntervals, 80, 1);
-  histogram_tester_.ExpectBucketCount(
-      kRenderDelayDifferenceIntervals + latency_tag_, 80, 1);
   histogram_tester_.ExpectBucketCount(kRenderGlitchCountIntervals, 500, 1);
   histogram_tester_.ExpectBucketCount(
       kRenderGlitchCountIntervals + latency_tag_, 500, 1);
@@ -167,9 +152,6 @@
   histogram_tester_.ExpectBucketCount(kRenderDelay + latency_tag_, 10, 500);
   histogram_tester_.ExpectBucketCount(kRenderDelay, 190, 500);
   histogram_tester_.ExpectBucketCount(kRenderDelay + latency_tag_, 190, 500);
-  histogram_tester_.ExpectBucketCount(kRenderDelayDifferenceIntervals, 180, 1);
-  histogram_tester_.ExpectBucketCount(
-      kRenderDelayDifferenceIntervals + latency_tag_, 180, 1);
   histogram_tester_.ExpectBucketCount(kRenderGlitchCountIntervals, 250, 1);
   histogram_tester_.ExpectBucketCount(
       kRenderGlitchCountIntervals + latency_tag_, 250, 1);
@@ -182,7 +164,6 @@
   histogram_tester_.ExpectBucketCount(kRenderDelay + latency_tag_, 100, 500);
 
   reporter_.reset();
-  histogram_tester_.ExpectTotalCount(kRenderDelayDifferenceShort, 0);
   histogram_tester_.ExpectTotalCount(kRenderGlitchCountShort, 0);
   histogram_tester_.ExpectTotalCount(kRenderGlitchDurationShort, 0);
 }
@@ -238,11 +219,9 @@
 
   histogram_tester_.ExpectBucketCount(kCaptureDelay, 60, 50);
   histogram_tester_.ExpectBucketCount(kCaptureDelay, 140, 50);
-  histogram_tester_.ExpectBucketCount(kCaptureDelayDifferenceShort, 80, 1);
   histogram_tester_.ExpectBucketCount(kCaptureGlitchCountShort, 50, 1);
   histogram_tester_.ExpectBucketCount(kCaptureGlitchDurationShort, 500, 1);
 
-  histogram_tester_.ExpectTotalCount(kCaptureDelayDifferenceIntervals, 0);
   histogram_tester_.ExpectTotalCount(kCaptureGlitchCountIntervals, 0);
   histogram_tester_.ExpectTotalCount(kCaptureGlitchDurationIntervals, 0);
 }
@@ -281,14 +260,12 @@
   histogram_tester_.ExpectBucketCount(kCaptureDelay, 60, 500);
   histogram_tester_.ExpectBucketCount(kCaptureDelay, 140, 500);
 
-  histogram_tester_.ExpectBucketCount(kCaptureDelayDifferenceIntervals, 80, 1);
   histogram_tester_.ExpectBucketCount(kCaptureGlitchCountIntervals, 500, 1);
   histogram_tester_.ExpectBucketCount(kCaptureGlitchDurationIntervals, 500, 1);
 
   // Data from the second interval.
   histogram_tester_.ExpectBucketCount(kCaptureDelay, 10, 500);
   histogram_tester_.ExpectBucketCount(kCaptureDelay, 190, 500);
-  histogram_tester_.ExpectBucketCount(kCaptureDelayDifferenceIntervals, 180, 1);
   histogram_tester_.ExpectBucketCount(kCaptureGlitchCountIntervals, 250, 1);
   histogram_tester_.ExpectBucketCount(kCaptureGlitchDurationIntervals, 250, 1);
 
@@ -296,7 +273,6 @@
   histogram_tester_.ExpectBucketCount(kCaptureDelay, 100, 500);
 
   reporter_.reset();
-  histogram_tester_.ExpectTotalCount(kCaptureDelayDifferenceShort, 0);
   histogram_tester_.ExpectTotalCount(kCaptureGlitchCountShort, 0);
   histogram_tester_.ExpectTotalCount(kCaptureGlitchDurationShort, 0);
 }
diff --git a/media/capture/BUILD.gn b/media/capture/BUILD.gn
index e39e96f..4c3112f6 100644
--- a/media/capture/BUILD.gn
+++ b/media/capture/BUILD.gn
@@ -272,6 +272,8 @@
 
   if (is_linux) {
     sources += [
+      "video/linux/v4l2_capture_delegate_gpu_helper.cc",
+      "video/linux/v4l2_capture_delegate_gpu_helper.h",
       "video/linux/v4l2_gpu_memory_buffer_tracker.cc",
       "video/linux/v4l2_gpu_memory_buffer_tracker.h",
       "video/linux/video_capture_gpu_memory_buffer_manager.cc",
@@ -469,7 +471,11 @@
   }
 
   if (is_linux) {
-    sources += [ "video/linux/v4l2_gpu_memory_buffer_tracker_unittest.cc" ]
+    sources += [
+      "video/linux/v4l2_capture_delegate_gpu_helper_unittest.cc",
+      "video/linux/v4l2_gpu_memory_buffer_tracker_unittest.cc",
+    ]
+    data += [ "//media/test/data/one_frame_1280x720.mjpeg" ]
   }
 
   if (is_android) {
diff --git a/media/capture/video/apple/video_capture_device_avfoundation.mm b/media/capture/video/apple/video_capture_device_avfoundation.mm
index c6e47da..4e2c635 100644
--- a/media/capture/video/apple/video_capture_device_avfoundation.mm
+++ b/media/capture/video/apple/video_capture_device_avfoundation.mm
@@ -407,11 +407,14 @@
   // yes/no and preserve aspect ratio yes/no when scaling. Currently we set
   // cropping and preservation.
   NSDictionary* videoSettingsDictionary = @{
+#if BUILDFLAG(IS_MAC)
     (id)kCVPixelBufferWidthKey : @(width),
     (id)kCVPixelBufferHeightKey : @(height),
-    (id)kCVPixelBufferPixelFormatTypeKey : @(best_fourcc),
-    AVVideoScalingModeKey : AVVideoScalingModeResizeAspectFill
+    AVVideoScalingModeKey : AVVideoScalingModeResizeAspectFill,
+#endif
+    (id)kCVPixelBufferPixelFormatTypeKey : @(best_fourcc)
   };
+
   _captureVideoDataOutput.videoSettings = videoSettingsDictionary;
 
 #if (!defined(__IPHONE_7_0) || __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0)
diff --git a/media/capture/video/linux/v4l2_capture_delegate_gpu_helper.cc b/media/capture/video/linux/v4l2_capture_delegate_gpu_helper.cc
new file mode 100644
index 0000000..5c6fcff
--- /dev/null
+++ b/media/capture/video/linux/v4l2_capture_delegate_gpu_helper.cc
@@ -0,0 +1,266 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/capture/video/linux/v4l2_capture_delegate_gpu_helper.h"
+
+#include "third_party/libyuv/include/libyuv.h"
+#include "ui/gfx/gpu_memory_buffer.h"
+
+namespace media {
+
+namespace {
+constexpr media::VideoPixelFormat kTargetPixelFormat =
+    media::VideoPixelFormat::PIXEL_FORMAT_NV12;
+constexpr gfx::BufferFormat kTargetBufferFormat =
+    gfx::BufferFormat::YUV_420_BIPLANAR;
+
+libyuv::FourCC VideoCaptureFormatToLibyuvFourcc(
+    const VideoCaptureFormat& capture_format) {
+  const int chopped_width = capture_format.frame_size.width() & 1;
+  const int chopped_height = capture_format.frame_size.height() & 1;
+  libyuv::FourCC fourcc_format = libyuv::FOURCC_ANY;
+
+  switch (capture_format.pixel_format) {
+    case PIXEL_FORMAT_UNKNOWN:  // Color format not set.
+      break;
+    case PIXEL_FORMAT_I420:
+      DCHECK(!chopped_width && !chopped_height);
+      fourcc_format = libyuv::FOURCC_I420;
+      break;
+    case PIXEL_FORMAT_YV12:
+      DCHECK(!chopped_width && !chopped_height);
+      fourcc_format = libyuv::FOURCC_YV12;
+      break;
+    case PIXEL_FORMAT_NV12:
+      DCHECK(!chopped_width && !chopped_height);
+      fourcc_format = libyuv::FOURCC_NV12;
+      break;
+    case PIXEL_FORMAT_NV21:
+      DCHECK(!chopped_width && !chopped_height);
+      fourcc_format = libyuv::FOURCC_NV21;
+      break;
+    case PIXEL_FORMAT_YUY2:
+      DCHECK(!chopped_width);
+      fourcc_format = libyuv::FOURCC_YUY2;
+      break;
+    case PIXEL_FORMAT_UYVY:
+      DCHECK(!chopped_width);
+      fourcc_format = libyuv::FOURCC_UYVY;
+      break;
+    case PIXEL_FORMAT_RGB24:
+      fourcc_format = libyuv::FOURCC_RAW;
+      break;
+    case PIXEL_FORMAT_ARGB:
+      // Windows platforms e.g. send the data vertically flipped sometimes.
+      fourcc_format = libyuv::FOURCC_ARGB;
+      break;
+    case PIXEL_FORMAT_MJPEG:
+      fourcc_format = libyuv::FOURCC_MJPG;
+      break;
+    default:
+      NOTREACHED();
+  }
+  return fourcc_format;
+}
+
+libyuv::RotationMode TranslateRotation(int rotation_degrees) {
+  DCHECK_EQ(0, rotation_degrees % 90) << " Rotation must be a multiple of 90, "
+                                         "now: "
+                                      << rotation_degrees;
+  libyuv::RotationMode rotation_mode = libyuv::kRotate0;
+  if (rotation_degrees == 90) {
+    rotation_mode = libyuv::kRotate90;
+  } else if (rotation_degrees == 180) {
+    rotation_mode = libyuv::kRotate180;
+  } else if (rotation_degrees == 270) {
+    rotation_mode = libyuv::kRotate270;
+  }
+  return rotation_mode;
+}
+
+}  // namespace
+
+V4L2CaptureDelegateGpuHelper::V4L2CaptureDelegateGpuHelper(
+    std::unique_ptr<gpu::GpuMemoryBufferSupport> gmb_support)
+    : gmb_support_(gmb_support
+                       ? std::move(gmb_support)
+                       : std::make_unique<gpu::GpuMemoryBufferSupport>()) {}
+
+V4L2CaptureDelegateGpuHelper::~V4L2CaptureDelegateGpuHelper() = default;
+
+int V4L2CaptureDelegateGpuHelper::OnIncomingCapturedData(
+    VideoCaptureDevice::Client* client,
+    const uint8_t* sample,
+    size_t sample_size,
+    const VideoCaptureFormat& capture_format,
+    const gfx::ColorSpace& data_color_space,
+    int rotation,
+    base::TimeTicks reference_time,
+    base::TimeDelta timestamp,
+    int frame_feedback_id) {
+  if (!client) {
+    return -1;
+  }
+
+  // Align destination resolution to be even.
+  int dst_width = capture_format.frame_size.width() & ~1;
+  int dst_height = capture_format.frame_size.height() & ~1;
+  if (rotation == 90 || rotation == 270) {
+    std::swap(dst_width, dst_height);
+  }
+  const gfx::Size dimensions(dst_width, dst_height);
+  VideoCaptureDevice::Client::Buffer capture_buffer;
+  auto reservation_result_code = client->ReserveOutputBuffer(
+      dimensions, kTargetPixelFormat, frame_feedback_id, &capture_buffer);
+  if (reservation_result_code !=
+      VideoCaptureDevice::Client::ReserveResult::kSucceeded) {
+    DLOG(ERROR) << "Failed to reserve output capture buffer: "
+                << (int)reservation_result_code;
+    client->OnFrameDropped(
+        ConvertReservationFailureToFrameDropReason(reservation_result_code));
+    return -1;
+  }
+
+  std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buff =
+      gmb_support_->CreateGpuMemoryBufferImplFromHandle(
+          capture_buffer.handle_provider->GetGpuMemoryBufferHandle(),
+          dimensions, kTargetBufferFormat,
+          gfx::BufferUsage::GPU_READ_CPU_READ_WRITE, base::NullCallback());
+  if (!gpu_memory_buff || !gpu_memory_buff->Map()) {
+    DLOG(ERROR) << "Failed to allocate gpu memory buffer buffer.";
+    client->OnFrameDropped(ConvertReservationFailureToFrameDropReason(
+        VideoCaptureDevice::Client::ReserveResult::kAllocationFailed));
+    return -1;
+  }
+
+  uint8_t* dst_y = (uint8_t*)gpu_memory_buff->memory(VideoFrame::kYPlane);
+  uint8_t* dst_uv = (uint8_t*)gpu_memory_buff->memory(VideoFrame::kUVPlane);
+  const int dst_stride_y = gpu_memory_buff->stride(VideoFrame::kYPlane);
+  const int dst_stride_uv = gpu_memory_buff->stride(VideoFrame::kUVPlane);
+  int status = ConvertCaptureDataToNV12(
+      sample, sample_size, capture_format, dimensions, data_color_space,
+      rotation, dst_y, dst_uv, dst_stride_y, dst_stride_uv);
+
+  gpu_memory_buff->Unmap();
+
+  if (status != 0) {
+    DLOG(ERROR) << "Failed to convert capture data.";
+    client->OnFrameDropped(ConvertReservationFailureToFrameDropReason(
+        VideoCaptureDevice::Client::ReserveResult::kSucceeded));
+    return status;
+  }
+
+  client->OnIncomingCapturedBufferExt(
+      std::move(capture_buffer),
+      VideoCaptureFormat(dimensions, capture_format.frame_rate,
+                         kTargetPixelFormat),
+      gfx::ColorSpace(), reference_time, timestamp, gfx::Rect(dimensions),
+      VideoFrameMetadata());
+  return status;
+}
+
+int V4L2CaptureDelegateGpuHelper::ConvertCaptureDataToNV12(
+    const uint8_t* sample,
+    size_t sample_size,
+    const VideoCaptureFormat& capture_format,
+    const gfx::Size& dimensions,
+    const gfx::ColorSpace& data_color_space,
+    int rotation,
+    uint8_t* dst_y,
+    uint8_t* dst_uv,
+    int dst_stride_y,
+    int dst_stride_uv) {
+  const libyuv::FourCC fourcc =
+      VideoCaptureFormatToLibyuvFourcc(capture_format);
+  const libyuv::RotationMode rotation_mode = TranslateRotation(rotation);
+  if (rotation_mode == libyuv::RotationMode::kRotate0 &&
+      IsNV12ConvertSupported(fourcc)) {
+    return FastConvertToNV12(sample, sample_size, capture_format, dst_y, dst_uv,
+                             dst_stride_y, dst_stride_uv);
+  }
+
+  const size_t i420_size = VideoFrame::AllocationSize(
+      VideoPixelFormat::PIXEL_FORMAT_I420, dimensions);
+  i420_buffer_.reserve(i420_size);
+  if (!i420_buffer_.data()) {
+    return -1;
+  }
+
+  uint8_t* i420_y = i420_buffer_.data();
+  uint8_t* i420_u =
+      i420_y + VideoFrame::PlaneSize(VideoPixelFormat::PIXEL_FORMAT_I420,
+                                     VideoFrame::kYPlane, dimensions)
+                   .GetArea();
+  uint8_t* i420_v =
+      i420_u + VideoFrame::PlaneSize(VideoPixelFormat::PIXEL_FORMAT_I420,
+                                     VideoFrame::kUPlane, dimensions)
+                   .GetArea();
+  std::vector<int32_t> i420_strides = VideoFrame::ComputeStrides(
+      VideoPixelFormat::PIXEL_FORMAT_I420, dimensions);
+  const int i420_stride_y = i420_strides[VideoFrame::kYPlane];
+  const int i420_stride_u = i420_strides[VideoFrame::kUPlane];
+  const int i420_stride_v = i420_strides[VideoFrame::kVPlane];
+
+  const int width = capture_format.frame_size.width();
+  const int height = capture_format.frame_size.height();
+  const int crop_width = width & ~1;
+  const int crop_height = height & ~1;
+  int status = libyuv::ConvertToI420(
+      sample, sample_size, i420_y, i420_stride_y, i420_u, i420_stride_u, i420_v,
+      i420_stride_v, 0, 0, width, height, crop_width, crop_height,
+      rotation_mode, fourcc);
+  if (status != 0) {
+    return status;
+  }
+
+  status = libyuv::I420ToNV12(i420_y, i420_stride_y, i420_u, i420_stride_u,
+                              i420_v, i420_stride_v, dst_y, dst_stride_y,
+                              dst_uv, dst_stride_uv, width, height);
+
+  return status;
+}
+
+int V4L2CaptureDelegateGpuHelper::FastConvertToNV12(
+    const uint8_t* sample,
+    size_t sample_size,
+    const VideoCaptureFormat& capture_format,
+    uint8_t* dst_y,
+    uint8_t* dst_uv,
+    int dst_stride_y,
+    int dst_stride_uv) {
+  const int src_width = capture_format.frame_size.width();
+  const int src_height = capture_format.frame_size.height();
+  const uint8_t* src_uv = sample + (src_width * src_height);
+
+  const libyuv::FourCC fourcc =
+      VideoCaptureFormatToLibyuvFourcc(capture_format);
+  switch (libyuv::CanonicalFourCC(fourcc)) {
+    case libyuv::FOURCC_YUY2:
+      return libyuv::YUY2ToNV12(sample, src_width * 2, dst_y, dst_stride_y,
+                                dst_uv, dst_stride_uv, src_width, src_height);
+    case libyuv::FOURCC_MJPG:
+      return libyuv::MJPGToNV12(sample, sample_size, dst_y, dst_stride_y,
+                                dst_uv, dst_stride_uv, src_width, src_height,
+                                src_width, src_height);
+    case libyuv::FOURCC_NV12:
+      return libyuv::NV12Copy(sample, src_width, src_uv, src_width, dst_y,
+                              dst_stride_y, dst_uv, dst_stride_uv, src_width,
+                              src_height);
+    default:
+      return -1;
+  }
+}
+
+bool V4L2CaptureDelegateGpuHelper::IsNV12ConvertSupported(uint32_t fourcc) {
+  switch (libyuv::CanonicalFourCC(fourcc)) {
+    case libyuv::FOURCC_NV12:
+    case libyuv::FOURCC_YUY2:
+    case libyuv::FOURCC_MJPG:
+      return true;
+    default:
+      return false;
+  }
+}
+
+}  // namespace media
diff --git a/media/capture/video/linux/v4l2_capture_delegate_gpu_helper.h b/media/capture/video/linux/v4l2_capture_delegate_gpu_helper.h
new file mode 100644
index 0000000..f7e8baba
--- /dev/null
+++ b/media/capture/video/linux/v4l2_capture_delegate_gpu_helper.h
@@ -0,0 +1,79 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_CAPTURE_VIDEO_LINUX_V4L2_CAPTURE_DELEGATE_GPU_HELPER_H_
+#define MEDIA_CAPTURE_VIDEO_LINUX_V4L2_CAPTURE_DELEGATE_GPU_HELPER_H_
+
+#include <vector>
+
+#include "gpu/ipc/common/gpu_memory_buffer_support.h"
+#include "media/capture/video/video_capture_device.h"
+
+namespace media {
+
+// V4L2CaptureDelegate GPU memory buffer helper.
+// This class is a helper to covert video capture data into `NV12` format and
+// copy into GPU memory buffer.
+class CAPTURE_EXPORT V4L2CaptureDelegateGpuHelper {
+ public:
+  explicit V4L2CaptureDelegateGpuHelper(
+      std::unique_ptr<gpu::GpuMemoryBufferSupport> gmb_support = nullptr);
+
+  V4L2CaptureDelegateGpuHelper(const V4L2CaptureDelegateGpuHelper&) = delete;
+  V4L2CaptureDelegateGpuHelper& operator=(const V4L2CaptureDelegateGpuHelper&) =
+      delete;
+
+  ~V4L2CaptureDelegateGpuHelper();
+
+ public:
+  // The `V4L2CaptureDelegate` calls and passes the member
+  // `V4L2CaptureDelegate::client_`. This method requests the GPU memory buffer
+  // by `V4L2CaptureDelegate::client_`. Then, it converts and copies the capture
+  // data into the GPU memory buffer with `NV12` format. At last, it notifies
+  // the client that data coming by calling
+  // `VideoCaptureDeviceClient::OnIncomingCapturedBufferExt()`.
+  // The |rotation| value should be 0, 90, 180, or 270.
+  int OnIncomingCapturedData(VideoCaptureDevice::Client* client,
+                             const uint8_t* sample,
+                             size_t sample_size,
+                             const VideoCaptureFormat& format,
+                             const gfx::ColorSpace& data_color_space,
+                             int rotation,
+                             base::TimeTicks reference_time,
+                             base::TimeDelta timestamp,
+                             int frame_feedback_id = 0);
+
+ private:
+  int ConvertCaptureDataToNV12(const uint8_t* sample,
+                               size_t sample_size,
+                               const VideoCaptureFormat& format,
+                               const gfx::Size& dimensions,
+                               const gfx::ColorSpace& data_color_space,
+                               int rotation,
+                               uint8_t* dst_y,
+                               uint8_t* dst_uv,
+                               int dst_stride_y,
+                               int dst_stride_uv);
+
+  // This method directly converts the sample data into `NV12` format when the
+  // input `VideoCaptureFormat` supported.
+  int FastConvertToNV12(const uint8_t* sample,
+                        size_t sample_size,
+                        const VideoCaptureFormat& format,
+                        uint8_t* dst_y,
+                        uint8_t* dst_uv,
+                        int dst_stride_y,
+                        int dst_stride_uv);
+
+  bool IsNV12ConvertSupported(uint32_t fourcc);
+
+  std::unique_ptr<gpu::GpuMemoryBufferSupport> gmb_support_;
+  // I420 buffer used when can't directly convert video sample data into `NV12`
+  // format.
+  std::vector<uint8_t> i420_buffer_;
+};
+
+}  // namespace media
+
+#endif  // !MEDIA_CAPTURE_VIDEO_LINUX_V4L2_CAPTURE_DELEGATE_GPU_HELPER_H_
diff --git a/media/capture/video/linux/v4l2_capture_delegate_gpu_helper_unittest.cc b/media/capture/video/linux/v4l2_capture_delegate_gpu_helper_unittest.cc
new file mode 100644
index 0000000..1b55e094
--- /dev/null
+++ b/media/capture/video/linux/v4l2_capture_delegate_gpu_helper_unittest.cc
@@ -0,0 +1,379 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include "media/capture/video/linux/v4l2_capture_delegate_gpu_helper.h"
+
+#include "base/command_line.h"
+#include "base/test/bind.h"
+#include "base/test/task_environment.h"
+#include "media/base/test_data_util.h"
+#include "media/capture/video/mock_gpu_memory_buffer_manager.h"
+#include "media/video/fake_gpu_memory_buffer.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::A;
+using testing::AtLeast;
+using testing::AtMost;
+using testing::Invoke;
+using testing::InvokeWithoutArgs;
+
+namespace media {
+
+namespace {
+
+constexpr char kMjpegFrameFile[] = "one_frame_1280x720.mjpeg";
+class MockV4l2GpuClient : public VideoCaptureDevice::Client {
+ public:
+  void OnIncomingCapturedData(const uint8_t* data,
+                              int length,
+                              const VideoCaptureFormat& frame_format,
+                              const gfx::ColorSpace& color_space,
+                              int clockwise_rotation,
+                              bool flip_y,
+                              base::TimeTicks reference_time,
+                              base::TimeDelta timestamp,
+                              int frame_feedback_id = 0) override {}
+
+  void OnIncomingCapturedGfxBuffer(gfx::GpuMemoryBuffer* buffer,
+                                   const VideoCaptureFormat& frame_format,
+                                   int clockwise_rotation,
+                                   base::TimeTicks reference_time,
+                                   base::TimeDelta timestamp,
+                                   int frame_feedback_id = 0) override {}
+
+  void OnIncomingCapturedExternalBuffer(
+      CapturedExternalVideoBuffer buffer,
+      std::vector<CapturedExternalVideoBuffer> scaled_buffers,
+      base::TimeTicks reference_time,
+      base::TimeDelta timestamp,
+      const gfx::Rect& visible_rect) override {}
+
+  void OnCaptureConfigurationChanged() override {}
+
+  MOCK_METHOD4(ReserveOutputBuffer,
+               ReserveResult(const gfx::Size&, VideoPixelFormat, int, Buffer*));
+
+  void OnIncomingCapturedBuffer(Buffer buffer,
+                                const VideoCaptureFormat& format,
+                                base::TimeTicks reference_,
+                                base::TimeDelta timestamp) override {}
+
+  MOCK_METHOD7(OnIncomingCapturedBufferExt,
+               void(Buffer,
+                    const VideoCaptureFormat&,
+                    const gfx::ColorSpace&,
+                    base::TimeTicks,
+                    base::TimeDelta,
+                    gfx::Rect,
+                    const VideoFrameMetadata&));
+
+  MOCK_METHOD3(OnError,
+               void(VideoCaptureError,
+                    const base::Location&,
+                    const std::string&));
+
+  MOCK_METHOD1(OnFrameDropped, void(VideoCaptureFrameDropReason));
+
+  double GetBufferPoolUtilization() const override { return 0.0; }
+
+  void OnStarted() override {}
+};
+
+class MockCaptureHandleProvider
+    : public VideoCaptureDevice::Client::Buffer::HandleProvider {
+ public:
+  MockCaptureHandleProvider(const gfx::Size& size, gfx::BufferFormat format) {
+    gmb_ = std::make_unique<FakeGpuMemoryBuffer>(size, format);
+  }
+  // Duplicate as an writable (unsafe) shared memory region.
+  base::UnsafeSharedMemoryRegion DuplicateAsUnsafeRegion() override {
+    return base::UnsafeSharedMemoryRegion();
+  }
+
+  // Access a |VideoCaptureBufferHandle| for local, writable memory.
+  std::unique_ptr<VideoCaptureBufferHandle> GetHandleForInProcessAccess()
+      override {
+    return nullptr;
+  }
+
+  // Clone a |GpuMemoryBufferHandle| for IPC.
+  gfx::GpuMemoryBufferHandle GetGpuMemoryBufferHandle() override {
+    gfx::GpuMemoryBufferHandle handle;
+    return gmb_->CloneHandle();
+  }
+  std::unique_ptr<FakeGpuMemoryBuffer> gmb_;
+};
+
+class InvalidGpuMemoryBufferSupport : public gpu::GpuMemoryBufferSupport {
+ public:
+  std::unique_ptr<gpu::GpuMemoryBufferImpl> CreateGpuMemoryBufferImplFromHandle(
+      gfx::GpuMemoryBufferHandle handle,
+      const gfx::Size& size,
+      gfx::BufferFormat format,
+      gfx::BufferUsage usage,
+      gpu::GpuMemoryBufferImpl::DestructionCallback callback,
+      gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager = nullptr,
+      scoped_refptr<base::UnsafeSharedMemoryPool> pool = nullptr,
+      base::span<uint8_t> premapped_memory = base::span<uint8_t>()) override {
+    return nullptr;
+  }
+};
+}  // namespace
+
+class V4l2CaptureDelegateGpuHelperTest
+    : public ::testing::TestWithParam<VideoCaptureFormat> {
+ public:
+  V4l2CaptureDelegateGpuHelperTest() {}
+  ~V4l2CaptureDelegateGpuHelperTest() override = default;
+
+ public:
+  void SetUp() override {}
+
+  void TearDown() override { task_environment_.RunUntilIdle(); }
+
+  void SetUpWithFakeGpuMemoryBufferSupport() {
+    std::unique_ptr<FakeGpuMemoryBufferSupport> gbm_support =
+        std::make_unique<FakeGpuMemoryBufferSupport>();
+    v4l2_gpu_helper_ =
+        std::make_unique<V4L2CaptureDelegateGpuHelper>(std::move(gbm_support));
+  }
+  void SetUpWithInvalidGpuMemoryBufferSupport() {
+    std::unique_ptr<InvalidGpuMemoryBufferSupport> gbm_support =
+        std::make_unique<InvalidGpuMemoryBufferSupport>();
+    v4l2_gpu_helper_ =
+        std::make_unique<V4L2CaptureDelegateGpuHelper>(std::move(gbm_support));
+  }
+
+  std::unique_ptr<std::vector<uint8_t>> ReadSampleData(
+      VideoCaptureFormat format) {
+    std::unique_ptr<std::vector<uint8_t>> sample =
+        std::make_unique<std::vector<uint8_t>>();
+    if (format.pixel_format == VideoPixelFormat::PIXEL_FORMAT_MJPEG) {
+      auto file_path = media::GetTestDataFilePath(kMjpegFrameFile);
+      if (!file_path.empty()) {
+        FILE* fp = fopen(file_path.value().c_str(), "rb");
+        if (fp) {
+          fseek(fp, 0, SEEK_END);
+          size_t size = ftell(fp);
+          sample->resize(size);
+          fseek(fp, 0, SEEK_SET);
+          size_t read_size = fread(sample->data(), 1, size, fp);
+          EXPECT_EQ(size, read_size);
+          fclose(fp);
+        }
+      }
+    } else {
+      auto size =
+          VideoFrame::AllocationSize(format.pixel_format, format.frame_size);
+      sample->resize(size);
+    }
+    return sample;
+  }
+
+ protected:
+  base::test::TaskEnvironment task_environment_;
+  std::unique_ptr<V4L2CaptureDelegateGpuHelper> v4l2_gpu_helper_;
+};
+
+TEST_F(V4l2CaptureDelegateGpuHelperTest, FailureAsInvalidClient) {
+  SetUpWithFakeGpuMemoryBufferSupport();
+  constexpr int kRotation = 0;
+  const base::TimeTicks reference_time = base::TimeTicks::Now();
+  const base::TimeDelta timestamp = reference_time - reference_time;
+  const VideoCaptureFormat capture_format = VideoCaptureFormat(
+      gfx::Size(1280, 720), 30.0f, VideoPixelFormat::PIXEL_FORMAT_YUY2);
+  std::unique_ptr<std::vector<uint8_t>> sample = ReadSampleData(capture_format);
+
+  int status = v4l2_gpu_helper_->OnIncomingCapturedData(
+      nullptr, sample->data(), sample->size(), capture_format,
+      gfx::ColorSpace(), kRotation, reference_time, timestamp);
+  EXPECT_NE(status, 0);
+}
+
+TEST_F(V4l2CaptureDelegateGpuHelperTest,
+       FailureAsInvalidMJPEGCaptureSampleData) {
+  SetUpWithFakeGpuMemoryBufferSupport();
+  constexpr int kRotation = 0;
+  const base::TimeTicks reference_time = base::TimeTicks::Now();
+  const base::TimeDelta timestamp = reference_time - reference_time;
+  const VideoCaptureFormat capture_format = VideoCaptureFormat(
+      gfx::Size(1280, 720), 30.0f, VideoPixelFormat::PIXEL_FORMAT_MJPEG);
+  std::unique_ptr<std::vector<uint8_t>> sample = ReadSampleData(capture_format);
+  MockV4l2GpuClient client;
+
+  if (sample) {
+    // corrupt the sample data
+    uint8_t* data = sample->data();
+    for (size_t i = 0; i < 0xff && i < sample->size(); i++) {
+      data[i] = 0xff;
+    }
+  }
+
+  EXPECT_CALL(client, ReserveOutputBuffer(_, _, _, _))
+      .WillRepeatedly(
+          Invoke([](const gfx::Size& size, VideoPixelFormat pixel_format,
+                    int feedback_id,
+                    VideoCaptureDevice::Client::Buffer* capture_buffer) {
+            EXPECT_EQ(pixel_format, PIXEL_FORMAT_NV12);
+            capture_buffer->handle_provider =
+                std::make_unique<MockCaptureHandleProvider>(
+                    size, gfx::BufferFormat::YUV_420_BIPLANAR);
+            return VideoCaptureDevice::Client::ReserveResult::kSucceeded;
+          }));
+  EXPECT_CALL(client, OnFrameDropped(_))
+      .WillRepeatedly(Invoke([](VideoCaptureFrameDropReason reason) {
+        EXPECT_EQ(reason, VideoCaptureFrameDropReason::kNone);
+      }));
+
+  int status = v4l2_gpu_helper_->OnIncomingCapturedData(
+      &client, sample->data(), sample->size(), capture_format,
+      gfx::ColorSpace(), kRotation, reference_time, timestamp);
+  EXPECT_NE(status, 0);
+}
+
+TEST_F(V4l2CaptureDelegateGpuHelperTest, FailureAsReserveOutputBufferErr) {
+  SetUpWithFakeGpuMemoryBufferSupport();
+  constexpr int kRotation = 0;
+  const base::TimeTicks reference_time = base::TimeTicks::Now();
+  const base::TimeDelta timestamp = reference_time - reference_time;
+  const VideoCaptureFormat capture_format = VideoCaptureFormat(
+      gfx::Size(1280, 720), 30.0f, VideoPixelFormat::PIXEL_FORMAT_YUY2);
+  std::unique_ptr<std::vector<uint8_t>> sample = ReadSampleData(capture_format);
+  MockV4l2GpuClient client;
+
+  EXPECT_CALL(client, ReserveOutputBuffer(_, _, _, _))
+      .WillRepeatedly(
+          Invoke([](const gfx::Size& size, VideoPixelFormat pixel_format,
+                    int feedback_id,
+                    VideoCaptureDevice::Client::Buffer* capture_buffer) {
+            return VideoCaptureDevice::Client::ReserveResult::kAllocationFailed;
+          }));
+  EXPECT_CALL(client, OnFrameDropped(_))
+      .WillRepeatedly(Invoke([](VideoCaptureFrameDropReason reason) {
+        EXPECT_EQ(
+            reason,
+            VideoCaptureFrameDropReason::kBufferPoolBufferAllocationFailed);
+      }));
+
+  int status = v4l2_gpu_helper_->OnIncomingCapturedData(
+      &client, sample->data(), sample->size(), capture_format,
+      gfx::ColorSpace(), kRotation, reference_time, timestamp);
+  EXPECT_NE(status, 0);
+}
+
+TEST_F(V4l2CaptureDelegateGpuHelperTest,
+       FailureAsInvalidCreateGpuMemoryBuffer) {
+  SetUpWithInvalidGpuMemoryBufferSupport();
+  constexpr int kRotation = 0;
+  const base::TimeTicks reference_time = base::TimeTicks::Now();
+  const base::TimeDelta timestamp = reference_time - reference_time;
+  const VideoCaptureFormat capture_format = VideoCaptureFormat(
+      gfx::Size(1280, 720), 30.0f, VideoPixelFormat::PIXEL_FORMAT_YUY2);
+  std::unique_ptr<std::vector<uint8_t>> sample = ReadSampleData(capture_format);
+  MockV4l2GpuClient client;
+
+  EXPECT_CALL(client, ReserveOutputBuffer(_, _, _, _))
+      .WillRepeatedly(
+          Invoke([](const gfx::Size& size, VideoPixelFormat pixel_format,
+                    int feedback_id,
+                    VideoCaptureDevice::Client::Buffer* capture_buffer) {
+            EXPECT_EQ(pixel_format, PIXEL_FORMAT_NV12);
+            capture_buffer->handle_provider =
+                std::make_unique<MockCaptureHandleProvider>(
+                    size, gfx::BufferFormat::YUV_420_BIPLANAR);
+            return VideoCaptureDevice::Client::ReserveResult::kSucceeded;
+          }));
+  EXPECT_CALL(client, OnFrameDropped(_))
+      .WillRepeatedly(Invoke([](VideoCaptureFrameDropReason reason) {
+        EXPECT_EQ(
+            reason,
+            VideoCaptureFrameDropReason::kBufferPoolBufferAllocationFailed);
+      }));
+
+  int status = v4l2_gpu_helper_->OnIncomingCapturedData(
+      &client, sample->data(), sample->size(), capture_format,
+      gfx::ColorSpace(), kRotation, reference_time, timestamp);
+  EXPECT_NE(status, 0);
+}
+
+TEST_F(V4l2CaptureDelegateGpuHelperTest, SuccessRotationIsNotZero) {
+  SetUpWithFakeGpuMemoryBufferSupport();
+  constexpr int kRotation = 180;
+  const base::TimeTicks reference_time = base::TimeTicks::Now();
+  const base::TimeDelta timestamp = reference_time - reference_time;
+  const VideoCaptureFormat capture_format = VideoCaptureFormat(
+      gfx::Size(1280, 720), 30.0f, VideoPixelFormat::PIXEL_FORMAT_YUY2);
+  std::unique_ptr<std::vector<uint8_t>> sample = ReadSampleData(capture_format);
+  MockV4l2GpuClient client;
+
+  EXPECT_CALL(client, ReserveOutputBuffer(_, _, _, _))
+      .WillRepeatedly(
+          Invoke([](const gfx::Size& size, VideoPixelFormat pixel_format,
+                    int feedback_id,
+                    VideoCaptureDevice::Client::Buffer* capture_buffer) {
+            EXPECT_EQ(pixel_format, PIXEL_FORMAT_NV12);
+            capture_buffer->handle_provider =
+                std::make_unique<MockCaptureHandleProvider>(
+                    size, gfx::BufferFormat::YUV_420_BIPLANAR);
+            return VideoCaptureDevice::Client::ReserveResult::kSucceeded;
+          }));
+  EXPECT_CALL(client, OnIncomingCapturedBufferExt(_, _, _, _, _, _, _))
+      .WillRepeatedly(InvokeWithoutArgs([]() {}));
+
+  int status = v4l2_gpu_helper_->OnIncomingCapturedData(
+      &client, sample->data(), sample->size(), capture_format,
+      gfx::ColorSpace(), kRotation, reference_time, timestamp);
+
+  EXPECT_EQ(status, 0);
+}
+
+TEST_P(V4l2CaptureDelegateGpuHelperTest, SuccessConvertWithCaptureParam) {
+  SetUpWithFakeGpuMemoryBufferSupport();
+  constexpr int kRotation = 0;
+  const base::TimeTicks reference_time = base::TimeTicks::Now();
+  const base::TimeDelta timestamp = reference_time - reference_time;
+  const VideoCaptureFormat& capture_format = GetParam();
+  const std::unique_ptr<std::vector<uint8_t>> sample =
+      ReadSampleData(capture_format);
+  MockV4l2GpuClient client;
+
+  EXPECT_CALL(client, ReserveOutputBuffer(_, _, _, _))
+      .WillRepeatedly(
+          Invoke([](const gfx::Size& size, VideoPixelFormat pixel_format,
+                    int feedback_id,
+                    VideoCaptureDevice::Client::Buffer* capture_buffer) {
+            EXPECT_EQ(pixel_format, PIXEL_FORMAT_NV12);
+            capture_buffer->handle_provider =
+                std::make_unique<MockCaptureHandleProvider>(
+                    size, gfx::BufferFormat::YUV_420_BIPLANAR);
+            return VideoCaptureDevice::Client::ReserveResult::kSucceeded;
+          }));
+  EXPECT_CALL(client, OnIncomingCapturedBufferExt(_, _, _, _, _, _, _))
+      .WillRepeatedly(InvokeWithoutArgs([]() {}));
+
+  int status = v4l2_gpu_helper_->OnIncomingCapturedData(
+      &client, sample->data(), sample->size(), capture_format,
+      gfx::ColorSpace(), kRotation, reference_time, timestamp);
+  EXPECT_EQ(status, 0);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    V4l2CaptureDelegateGpuHelperTest,
+    ::testing::Values(
+        VideoCaptureFormat(gfx::Size(1280, 720),
+                           30.0f,
+                           VideoPixelFormat::PIXEL_FORMAT_NV12),
+        VideoCaptureFormat(gfx::Size(1280, 720),
+                           30.0f,
+                           VideoPixelFormat::PIXEL_FORMAT_YUY2),
+        VideoCaptureFormat(gfx::Size(1280, 720),
+                           30.0f,
+                           VideoPixelFormat::PIXEL_FORMAT_MJPEG),
+        VideoCaptureFormat(gfx::Size(1280, 720),
+                           30.0f,
+                           VideoPixelFormat::PIXEL_FORMAT_RGB24)));
+
+}  // namespace media
diff --git a/media/gpu/DEPS b/media/gpu/DEPS
index 2a7e6a79c..427823a 100644
--- a/media/gpu/DEPS
+++ b/media/gpu/DEPS
@@ -18,7 +18,6 @@
   "-media/base/media_export.h",
 
   # SharedImageVideo uses it.
-  "+components/viz/common/resources/resource_format_utils.h",
   "+components/viz/common/resources/resource_sizes.h",
 
   # Chrome OS specific JEA/MJDA.
diff --git a/media/gpu/ipc/service/picture_buffer_manager.cc b/media/gpu/ipc/service/picture_buffer_manager.cc
index 1908729f..2dd84ca 100644
--- a/media/gpu/ipc/service/picture_buffer_manager.cc
+++ b/media/gpu/ipc/service/picture_buffer_manager.cc
@@ -14,7 +14,6 @@
 #include "base/synchronization/lock.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/thread_annotations.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "gpu/command_buffer/common/mailbox_holder.h"
 #include "ui/gfx/gpu_memory_buffer.h"
 
diff --git a/media/gpu/test/raw_video.cc b/media/gpu/test/raw_video.cc
index a85a72b..7730d8a0 100644
--- a/media/gpu/test/raw_video.cc
+++ b/media/gpu/test/raw_video.cc
@@ -15,6 +15,7 @@
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread.h"
 #include "media/base/media.h"
+#include "media/base/media_serializers.h"
 #include "media/base/video_decoder_config.h"
 #include "media/base/video_frame.h"
 #include "media/base/video_types.h"
@@ -56,154 +57,6 @@
   return success ? std::move(mmapped_file) : nullptr;
 }
 
-void DecodeVP9Task(base::span<const uint8_t> data,
-                   const gfx::Size& resolution,
-                   const size_t num_frames,
-                   const size_t video_frame_size,
-                   uint8_t* dst_buffer,
-                   bool* success,
-                   base::WaitableEvent* done) {
-  *success = false;
-  InitializeMediaLibrary();
-
-  // Initialize ffmpeg with the compressed video data.
-  InMemoryUrlProtocol protocol(&data[0], data.size(), false);
-  FFmpegGlue glue(&protocol);
-  ASSERT_TRUE(glue.OpenContext());
-
-  // Find the first VP9 stream in the file.
-  int stream_index = -1;
-  VideoDecoderConfig config;
-  for (size_t i = 0; i < glue.format_context()->nb_streams; ++i) {
-    AVStream* stream = glue.format_context()->streams[i];
-    const AVCodecParameters* codec_parameters = stream->codecpar;
-    const AVMediaType codec_type = codec_parameters->codec_type;
-    const AVCodecID codec_id = codec_parameters->codec_id;
-    if (codec_type == AVMEDIA_TYPE_VIDEO && codec_id == AV_CODEC_ID_VP9) {
-      *success = AVStreamToVideoDecoderConfig(stream, &config) &&
-                 config.IsValidConfig();
-      stream_index = i;
-      break;
-    }
-  }
-  if (!*success) {
-    done->Signal();
-    return;
-  }
-
-  auto on_frame_decoded = [](const gfx::Size& resolution,
-                             const size_t video_frame_size,
-                             uint8_t* const dst_buffer,
-                             size_t* decode_frame_count,
-                             scoped_refptr<VideoFrame> frame) {
-    ASSERT_EQ(frame->format(), VideoPixelFormat::PIXEL_FORMAT_I420);
-    size_t num_planes = VideoFrame::NumPlanes(frame->format());
-    uint8_t* dst_plane = dst_buffer + video_frame_size * (*decode_frame_count);
-    // Copy the resolution area.
-    for (size_t plane = 0; plane < num_planes; ++plane) {
-      const int stride = frame->stride(plane);
-      const int rows =
-          VideoFrame::Rows(plane, frame->format(), resolution.height());
-      const int row_bytes =
-          VideoFrame::RowBytes(plane, frame->format(), resolution.width());
-      // VideoFrame::PlaneSize() cannot be used because it computes the
-      // plane size with resolutions aligned by two while our test code
-      // works with a succinct buffer size.
-      const uint8_t* src = frame->data(plane);
-      libyuv::CopyPlane(src, stride, dst_plane, row_bytes, row_bytes, rows);
-      dst_plane += (rows * row_bytes);
-    }
-    *decode_frame_count += 1;
-  };
-
-  size_t decode_frame_count = 0;
-  // Setup the VP9 decoder.
-  DecoderStatus init_result;
-  VpxVideoDecoder decoder(
-      media::OffloadableVideoDecoder::OffloadState::kOffloaded);
-  media::VideoDecoder::InitCB init_cb =
-      base::BindOnce([](DecoderStatus* save_to,
-                        DecoderStatus save_from) { *save_to = save_from; },
-                     &init_result);
-  decoder.Initialize(
-      config, false, nullptr, std::move(init_cb),
-      base::BindRepeating(on_frame_decoded, resolution, video_frame_size,
-                          dst_buffer, &decode_frame_count),
-      base::NullCallback());
-  if (!init_result.is_ok()) {
-    done->Signal();
-    return;
-  }
-
-  // Start decoding and wait until all frames are ready.
-  AVPacket packet = {};
-  size_t num_decoded_frames = 0;
-  while (av_read_frame(glue.format_context(), &packet) >= 0 &&
-         num_decoded_frames < num_frames) {
-    if (packet.stream_index == stream_index) {
-      media::VideoDecoder::DecodeCB decode_cb = base::BindOnce(
-          [](bool* success, DecoderStatus status) {
-            *success = (status.is_ok());
-          },
-          success);
-      decoder.Decode(DecoderBuffer::CopyFrom(packet.data, packet.size),
-                     std::move(decode_cb));
-      if (!*success) {
-        break;
-      }
-      num_decoded_frames++;
-    }
-    av_packet_unref(&packet);
-  }
-
-  done->Signal();
-}
-
-// Decode the vp9 data and returns the raw I420 data. Returns empty vector on
-// fatal.
-std::unique_ptr<base::MemoryMappedFile> DecodeAndLoadVP9Data(
-    const base::FilePath& data_file_path,
-    const gfx::Size& resolution,
-    size_t video_frame_size,
-    size_t num_read_frames) {
-  base::MemoryMappedFile compressed_data_mmap_file;
-  if (!compressed_data_mmap_file.Initialize(
-          data_file_path, base::MemoryMappedFile::READ_ONLY)) {
-    LOG(ERROR) << "Failed to read file: " << data_file_path;
-    return nullptr;
-  }
-  base::span<const uint8_t> compressed_data(compressed_data_mmap_file.data(),
-                                            compressed_data_mmap_file.length());
-
-  auto decompressed_data_mmap_file =
-      CreateMemoryMappedFile(video_frame_size * num_read_frames);
-  if (!decompressed_data_mmap_file) {
-    LOG(ERROR) << "Failed to create memory mapped file for decompressed data";
-    return nullptr;
-  }
-  // The VpxVideoDecoder requires running on a SequencedTaskRunner, so we
-  // can't decode the video on the main test thread.
-  base::Thread decode_thread("DecodeThread");
-  if (!decode_thread.Start()) {
-    LOG(ERROR) << "Failed to start decode thread";
-    return nullptr;
-  }
-
-  bool success = false;
-  base::WaitableEvent done;
-  decode_thread.task_runner()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&DecodeVP9Task, compressed_data, resolution,
-                     num_read_frames, video_frame_size,
-                     decompressed_data_mmap_file->data(), &success, &done));
-  done.Wait();
-  decode_thread.Stop();
-  if (!success) {
-    return nullptr;
-  }
-  return decompressed_data_mmap_file;
-}
-
 std::unique_ptr<base::MemoryMappedFile> LoadRawData(
     const base::FilePath& data_file_path,
     size_t video_frame_size,
@@ -222,6 +75,208 @@
 }
 }  // namespace
 
+class VP9Decoder {
+ public:
+  static std::unique_ptr<VP9Decoder> Create(
+      const base::FilePath& vp9_webm_data_file_path,
+      const VideoFrameLayout& layout,
+      size_t num_read_frames);
+
+  std::vector<uint8_t> DecodeNextFrame() {
+    // If this is the first decode, then starts the thread.
+    if (!decoder_thread_.IsRunning()) {
+      LOG_IF(FATAL, !decoder_thread_.Start())
+          << "Failed to start decoder thread";
+      DecoderStatus result;
+      base::WaitableEvent event;
+      // base::Unretained(this) is safe because this is blocking call.
+      decoder_thread_.task_runner()->PostTask(
+          FROM_HERE, base::BindOnce(&VP9Decoder::InitializeTask,
+                                    base::Unretained(this), &result, &event));
+      event.Wait();
+      LOG_ASSERT(result.is_ok())
+          << "Failed to initialize VpxVideoDecoder: " << MediaSerialize(result)
+          << "with config=" << config_.AsHumanReadableString();
+    }
+
+    std::vector<uint8_t> decoded_frame_buffer;
+    base::WaitableEvent done;
+    decoder_thread_.task_runner()->PostTask(
+        FROM_HERE,
+        base::BindOnce(&VP9Decoder::DecodeNextFrameTask, base::Unretained(this),
+                       &decoded_frame_buffer, &done));
+    done.Wait();
+    CHECK(!decoded_frame_buffer.empty());
+    return decoded_frame_buffer;
+  }
+
+  ~VP9Decoder() {
+    if (decoder_thread_.IsRunning()) {
+      decoder_thread_.task_runner()->DeleteSoon(FROM_HERE,
+                                                std::move(vpx_decoder_));
+    }
+  }
+
+ private:
+  VP9Decoder(std::unique_ptr<base::MemoryMappedFile> vp9_data_mmap_file,
+             const std::vector<base::span<const uint8_t>>& vp9_data_chunks,
+             const VideoDecoderConfig& config,
+             const VideoFrameLayout& layout)
+      : vp9_data_mmap_file_(std::move(vp9_data_mmap_file)),
+        config_(config),
+        layout_(layout),
+        decoder_thread_("VP9DecoderThread"),
+        vp9_data_chunks_(vp9_data_chunks) {
+    DETACH_FROM_SEQUENCE(decoder_sequence_);
+  }
+
+  void OnFrameDecoded(scoped_refptr<VideoFrame> frame) {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_);
+    last_decoded_frame_ = std::move(frame);
+  }
+
+  void InitializeTask(DecoderStatus* result, base::WaitableEvent* event) {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_);
+    vpx_decoder_ = std::make_unique<VpxVideoDecoder>(
+        OffloadableVideoDecoder::OffloadState::kOffloaded);
+    vpx_decoder_->Initialize(
+        config_,
+        /*low_delay*/ false,
+        /*CdmContext*/ nullptr,
+        base::BindOnce([](DecoderStatus* save_to,
+                          DecoderStatus save_from) { *save_to = save_from; },
+                       result),
+        // base::Unretained(this) is safe because |vpx_decoder_| is owned by
+        // this.
+        base::BindRepeating(&VP9Decoder::OnFrameDecoded,
+                            base::Unretained(this)),
+        /*waiting_cb=*/base::NullCallback());
+    event->Signal();
+  }
+
+  void DecodeNextFrameTask(std::vector<uint8_t>* decoded_frame_buffer,
+                           base::WaitableEvent* done) {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_);
+    CHECK_LT(next_frame_index_, vp9_data_chunks_.size());
+    base::span<const uint8_t> chunk = vp9_data_chunks_[next_frame_index_];
+    DecoderStatus decode_status{DecoderStatus::Codes::kOk};
+    vpx_decoder_->Decode(
+        DecoderBuffer::CopyFrom(chunk.data(), chunk.size()),
+        base::BindOnce([](DecoderStatus* out_status,
+                          DecoderStatus status) { *out_status = status; },
+                       &decode_status));
+    LOG_ASSERT(decode_status.is_ok())
+        << "Failed to decode the " << next_frame_index_
+        << "-th vp9 chunk: " << MediaSerialize(decode_status);
+    LOG_ASSERT(!!last_decoded_frame_) << "|last_decoded_frame_| is not filled";
+    *decoded_frame_buffer = CreateBufferFromFrame(*last_decoded_frame_);
+    last_decoded_frame_.reset();
+    next_frame_index_++;
+    done->Signal();
+  }
+
+  std::vector<uint8_t> CreateBufferFromFrame(
+      const VideoFrame& i420_frame) const {
+    LOG_ASSERT(i420_frame.format() == VideoPixelFormat::PIXEL_FORMAT_I420);
+    std::vector<uint8_t> buffer;
+    buffer.resize(layout_.planes()[2].offset + layout_.planes()[2].size);
+    // Copy the resolution area.
+    uint8_t* dst_plane = buffer.data();
+    for (size_t plane = 0; plane < 3; ++plane) {
+      const int stride = i420_frame.stride(plane);
+      const int rows = VideoFrame::Rows(plane, i420_frame.format(),
+                                        layout_.coded_size().height());
+      const int row_bytes = VideoFrame::RowBytes(plane, i420_frame.format(),
+                                                 layout_.coded_size().width());
+      // VideoFrame::PlaneSize() cannot be used because it computes the
+      // plane size with resolutions aligned by two while our test code
+      // works with a succinct buffer size.
+      const uint8_t* src = i420_frame.data(plane);
+      libyuv::CopyPlane(src, stride, dst_plane, row_bytes, row_bytes, rows);
+      dst_plane += (rows * row_bytes);
+    }
+    return buffer;
+  }
+
+  const std::unique_ptr<base::MemoryMappedFile> vp9_data_mmap_file_;
+  const VideoDecoderConfig config_;
+  const VideoFrameLayout layout_;
+
+  base::Thread decoder_thread_;
+  const std::vector<base::span<const uint8_t>> vp9_data_chunks_
+      GUARDED_BY_CONTEXT(decoder_sequence_);
+  std::unique_ptr<VpxVideoDecoder> vpx_decoder_
+      GUARDED_BY_CONTEXT(decoder_sequence_);
+  size_t next_frame_index_ GUARDED_BY_CONTEXT(decoder_sequence_){0};
+  scoped_refptr<VideoFrame> last_decoded_frame_
+      GUARDED_BY_CONTEXT(decoder_sequence_);
+  SEQUENCE_CHECKER(decoder_sequence_);
+};
+
+// static
+std::unique_ptr<VP9Decoder> VP9Decoder::Create(
+    const base::FilePath& vp9_webm_data_file_path,
+    const VideoFrameLayout& layout,
+    size_t num_read_frames) {
+  base::MemoryMappedFile vp9_webm_data_mmap_file;
+  if (!vp9_webm_data_mmap_file.Initialize(vp9_webm_data_file_path,
+                                          base::MemoryMappedFile::READ_ONLY)) {
+    LOG(ERROR) << "Failed to read file: " << vp9_webm_data_file_path;
+    return nullptr;
+  }
+  base::span<const uint8_t> vp9_webm_data(vp9_webm_data_mmap_file.data(),
+                                          vp9_webm_data_mmap_file.length());
+
+  InitializeMediaLibrary();
+
+  // Initialize ffmpeg with the compressed video data.
+  InMemoryUrlProtocol protocol(vp9_webm_data.data(), vp9_webm_data.size(),
+                               /*streaming=*/false);
+  FFmpegGlue glue(&protocol);
+  LOG_ASSERT(glue.OpenContext()) << "Failed to open AVFormatContext";
+  // Find the first VP9 stream in the file.
+  absl::optional<size_t> vp9_stream_index;
+  VideoDecoderConfig config;
+  for (size_t i = 0; i < glue.format_context()->nb_streams; ++i) {
+    AVStream* stream = glue.format_context()->streams[i];
+    const AVCodecParameters* codec_parameters = stream->codecpar;
+    const AVMediaType codec_type = codec_parameters->codec_type;
+    const AVCodecID codec_id = codec_parameters->codec_id;
+    if (codec_type == AVMEDIA_TYPE_VIDEO && codec_id == AV_CODEC_ID_VP9 &&
+        AVStreamToVideoDecoderConfig(stream, &config) &&
+        config.IsValidConfig()) {
+      vp9_stream_index = i;
+      break;
+    }
+  }
+  if (!vp9_stream_index) {
+    return nullptr;
+  }
+
+  auto vp9_data_mmap_file = CreateMemoryMappedFile(vp9_webm_data.size());
+  uint8_t* const vp9_data = vp9_data_mmap_file->data();
+  size_t vp9_data_size = 0;
+  AVPacket packet = {};
+  size_t num_packets = 0;
+  std::vector<base::span<const uint8_t>> vp9_data_chunks(num_read_frames);
+  while (av_read_frame(glue.format_context(), &packet) >= 0 &&
+         num_packets < num_read_frames) {
+    if (base::checked_cast<size_t>(packet.stream_index) ==
+        (*vp9_stream_index)) {
+      LOG_ASSERT(vp9_data_size + packet.size <= vp9_data_mmap_file->length())
+          << "The vp9 data size must be less than webm file size";
+      std::memcpy(vp9_data + vp9_data_size, packet.data, packet.size);
+      vp9_data_chunks[num_packets] = base::span<const uint8_t>(
+          vp9_data + vp9_data_size, base::checked_cast<size_t>(packet.size));
+      vp9_data_size += packet.size;
+      num_packets++;
+    }
+    av_packet_unref(&packet);
+  }
+  return base::WrapUnique<VP9Decoder>(new VP9Decoder(
+      std::move(vp9_data_mmap_file), vp9_data_chunks, config, layout));
+}
+
 RawVideo::RawVideo(std::unique_ptr<base::MemoryMappedFile> memory_mapped_file,
                    const Metadata& metadata,
                    size_t video_frame_size)
@@ -371,10 +426,18 @@
   }
 
   std::unique_ptr<base::MemoryMappedFile> memory_mapped_file;
+
   if (is_vp9_data) {
     // If the given data is compressed video (i.e. vp9 webm), then we decode.
-    memory_mapped_file = DecodeAndLoadVP9Data(
-        data_file_path, resolution, video_frame_size, metadata.num_frames);
+    auto vp9_decoder = VP9Decoder::Create(
+        data_file_path, *metadata.frame_layout, metadata.num_frames);
+    memory_mapped_file =
+        CreateMemoryMappedFile(video_frame_size * metadata.num_frames);
+    for (size_t i = 0; i < metadata.num_frames; ++i) {
+      auto buffer = vp9_decoder->DecodeNextFrame();
+      memcpy(memory_mapped_file->data() + i * video_frame_size, buffer.data(),
+             buffer.size());
+    }
   } else {
     memory_mapped_file =
         LoadRawData(data_file_path, video_frame_size, metadata.num_frames);
@@ -390,6 +453,8 @@
 std::unique_ptr<RawVideo> RawVideo::CreateNV12Video() const {
   LOG_ASSERT(FrameLayout().format() == PIXEL_FORMAT_I420)
       << "The pixel format of source video is not I420";
+  LOG_ASSERT(memory_mapped_file_) << "CreateNV12Video() is supported only if "
+                                  << "|memory_mapped_file_| is valid";
   auto nv12_layout = CreateVideoFrameLayout(PIXEL_FORMAT_NV12, Resolution(),
                                             1u /* alignment*/);
   LOG_ASSERT(nv12_layout) << "Failed creating VideoFrameLayout";
diff --git a/media/gpu/windows/d3d11_texture_wrapper.cc b/media/gpu/windows/d3d11_texture_wrapper.cc
index 7816d63c..d4c99887 100644
--- a/media/gpu/windows/d3d11_texture_wrapper.cc
+++ b/media/gpu/windows/d3d11_texture_wrapper.cc
@@ -11,7 +11,6 @@
 
 #include "base/task/bind_post_task.h"
 #include "base/task/single_thread_task_runner.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "gpu/command_buffer/common/constants.h"
 #include "gpu/command_buffer/common/shared_image_usage.h"
 #include "gpu/command_buffer/service/dxgi_shared_handle_manager.h"
diff --git a/media/renderers/video_frame_rgba_to_yuva_converter.cc b/media/renderers/video_frame_rgba_to_yuva_converter.cc
index 882514d..d1a73054 100644
--- a/media/renderers/video_frame_rgba_to_yuva_converter.cc
+++ b/media/renderers/video_frame_rgba_to_yuva_converter.cc
@@ -8,7 +8,6 @@
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
 #include "components/viz/common/gpu/raster_context_provider.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
 #include "gpu/command_buffer/client/raster_interface.h"
 #include "gpu/command_buffer/client/shared_image_interface.h"
diff --git a/media/renderers/video_frame_yuv_converter.cc b/media/renderers/video_frame_yuv_converter.cc
index b5a2a74..0a2dae2a 100644
--- a/media/renderers/video_frame_yuv_converter.cc
+++ b/media/renderers/video_frame_yuv_converter.cc
@@ -8,7 +8,6 @@
 
 #include "base/logging.h"
 #include "components/viz/common/gpu/raster_context_provider.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "gpu/command_buffer/client/raster_interface.h"
 #include "gpu/command_buffer/client/shared_image_interface.h"
 #include "gpu/command_buffer/common/shared_image_usage.h"
diff --git a/media/renderers/video_frame_yuv_mailboxes_holder.cc b/media/renderers/video_frame_yuv_mailboxes_holder.cc
index dc815ee..64247e76 100644
--- a/media/renderers/video_frame_yuv_mailboxes_holder.cc
+++ b/media/renderers/video_frame_yuv_mailboxes_holder.cc
@@ -8,7 +8,6 @@
 
 #include "base/logging.h"
 #include "components/viz/common/gpu/raster_context_provider.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/shared_image_format.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "gpu/command_buffer/client/raster_interface.h"
diff --git a/media/renderers/video_resource_updater.cc b/media/renderers/video_resource_updater.cc
index c126ddc..93baf36 100644
--- a/media/renderers/video_resource_updater.cc
+++ b/media/renderers/video_resource_updater.cc
@@ -34,7 +34,6 @@
 #include "components/viz/common/quads/video_hole_draw_quad.h"
 #include "components/viz/common/quads/yuv_video_draw_quad.h"
 #include "components/viz/common/resources/bitmap_allocation.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/resource_sizes.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
 #include "gpu/GLES2/gl2extchromium.h"
diff --git a/media/test/data/README.md b/media/test/data/README.md
index 6dc8c528..6aa3184a 100644
--- a/media/test/data/README.md
+++ b/media/test/data/README.md
@@ -1544,3 +1544,5 @@
 ffmpeg -i bear6.wav -c:a dtsxS -b:a 160000 -movflags frag_keyframe -y bear_dtsx.mp4
 # truncate to size of moov box (truncate -s)
 ```
+### one_frame_1280x720.mjpeg
+It's a single frame mjpeg data. Resolution: 1280x720, color primary: sRGB, transfer function: BT.709, color matrix: BT.601, color range: full-range.
diff --git a/media/test/data/one_frame_1280x720.mjpeg b/media/test/data/one_frame_1280x720.mjpeg
new file mode 100644
index 0000000..5078353
--- /dev/null
+++ b/media/test/data/one_frame_1280x720.mjpeg
Binary files differ
diff --git a/media/test/media_bundle_data.filelist b/media/test/media_bundle_data.filelist
index b5e8f07..0fffe6f 100644
--- a/media/test/media_bundle_data.filelist
+++ b/media/test/media_bundle_data.filelist
@@ -375,6 +375,7 @@
 data/noise-xhe-aac.mp4
 data/nonzero-start-time.webm
 data/npot-video.h264
+data/one_frame_1280x720.mjpeg
 data/opus-trimming-test.mp4
 data/opus-trimming-test.ogg
 data/opus-trimming-test.webm
diff --git a/media/unit_tests_bundle_data.filelist b/media/unit_tests_bundle_data.filelist
index 51436ae..147a4d8 100644
--- a/media/unit_tests_bundle_data.filelist
+++ b/media/unit_tests_bundle_data.filelist
@@ -387,6 +387,7 @@
 //media/test/data/noise-xhe-aac.mp4
 //media/test/data/nonzero-start-time.webm
 //media/test/data/npot-video.h264
+//media/test/data/one_frame_1280x720.mjpeg
 //media/test/data/opus-trimming-test.mp4
 //media/test/data/opus-trimming-test.ogg
 //media/test/data/opus-trimming-test.webm
diff --git a/mojo/core/channel.h b/mojo/core/channel.h
index 83f39d46..d7a9cb2 100644
--- a/mojo/core/channel.h
+++ b/mojo/core/channel.h
@@ -491,7 +491,7 @@
   class ReadBuffer;
 
   const bool is_for_ipcz_;
-  raw_ptr<Delegate, DanglingUntriaged> delegate_;
+  raw_ptr<Delegate, DanglingAcrossTasks> delegate_;
   HandlePolicy handle_policy_;
   const std::unique_ptr<ReadBuffer> read_buffer_;
 
diff --git a/mojo/public/cpp/bindings/lib/sequence_local_sync_event_watcher.cc b/mojo/public/cpp/bindings/lib/sequence_local_sync_event_watcher.cc
index f367934..b3bac4a 100644
--- a/mojo/public/cpp/bindings/lib/sequence_local_sync_event_watcher.cc
+++ b/mojo/public/cpp/bindings/lib/sequence_local_sync_event_watcher.cc
@@ -258,7 +258,7 @@
 
  private:
   const base::WeakPtr<SequenceLocalState> weak_shared_state_;
-  const raw_ptr<SequenceLocalState, DanglingUntriaged> shared_state_;
+  const raw_ptr<SequenceLocalState, DanglingAcrossTasks> shared_state_;
   WatcherStateMap::iterator watcher_state_iterator_;
   const scoped_refptr<WatcherState> watcher_state_;
 };
diff --git a/net/http/http_cache_transaction.h b/net/http/http_cache_transaction.h
index ef6a8631..e8c363c 100644
--- a/net/http/http_cache_transaction.h
+++ b/net/http/http_cache_transaction.h
@@ -658,7 +658,7 @@
   // |external_validation_| contains the value of those headers.
   ValidationHeaders external_validation_;
   base::WeakPtr<HttpCache> cache_;
-  raw_ptr<HttpCache::ActiveEntry, DanglingUntriaged> entry_ = nullptr;
+  raw_ptr<HttpCache::ActiveEntry, DanglingAcrossTasks> entry_ = nullptr;
   // This field is not a raw_ptr<> because it was filtered by the rewriter for:
   // #addr-of
   RAW_PTR_EXCLUSION HttpCache::ActiveEntry* new_entry_ = nullptr;
diff --git a/services/network/shared_dictionary/shared_dictionary_network_transaction.cc b/services/network/shared_dictionary/shared_dictionary_network_transaction.cc
index 1e28a9a0..2f7b8e9 100644
--- a/services/network/shared_dictionary/shared_dictionary_network_transaction.cc
+++ b/services/network/shared_dictionary/shared_dictionary_network_transaction.cc
@@ -214,7 +214,7 @@
     return net::ERR_IO_PENDING;
   }
 
-  if (header_status_ == HeaderStatus::kUknown) {
+  if (header_status_ == HeaderStatus::kUnknown) {
     header_status_ = ContentEncodingIsSbrOnly(
                          *network_transaction_->GetResponseInfo()->headers)
                          ? HeaderStatus::kSharedBrotliUsed
diff --git a/services/network/shared_dictionary/shared_dictionary_network_transaction.h b/services/network/shared_dictionary/shared_dictionary_network_transaction.h
index 0858244..c983089 100644
--- a/services/network/shared_dictionary/shared_dictionary_network_transaction.h
+++ b/services/network/shared_dictionary/shared_dictionary_network_transaction.h
@@ -100,7 +100,7 @@
     kFailed,
   };
   enum class HeaderStatus {
-    kUknown,
+    kUnknown,
     kSharedBrotliUsed,
     kSharedBrotliNotUsed,
   };
@@ -134,7 +134,7 @@
       origin_check_callback_;
 
   DictionaryStatus dictionary_status_ = DictionaryStatus::kNoDictionary;
-  HeaderStatus header_status_ = HeaderStatus::kUknown;
+  HeaderStatus header_status_ = HeaderStatus::kUnknown;
 
   std::unique_ptr<PendingReadTask> pending_read_task_;
 
diff --git a/services/viz/public/cpp/gpu/context_provider_command_buffer.cc b/services/viz/public/cpp/gpu/context_provider_command_buffer.cc
index b9993aa..ad7816e 100644
--- a/services/viz/public/cpp/gpu/context_provider_command_buffer.cc
+++ b/services/viz/public/cpp/gpu/context_provider_command_buffer.cc
@@ -25,7 +25,6 @@
 #include "base/trace_event/memory_dump_provider.h"
 #include "build/build_config.h"
 #include "components/viz/common/gpu/context_cache_controller.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
 #include "gpu/command_buffer/client/gles2_cmd_helper.h"
 #include "gpu/command_buffer/client/gles2_trace_implementation.h"
diff --git a/storage/browser/blob/blob_transport_strategy.h b/storage/browser/blob/blob_transport_strategy.h
index e25aa6d..264e122 100644
--- a/storage/browser/blob/blob_transport_strategy.h
+++ b/storage/browser/blob/blob_transport_strategy.h
@@ -51,7 +51,7 @@
   BlobTransportStrategy(BlobDataBuilder* builder,
                         ResultCallback result_callback);
 
-  raw_ptr<BlobDataBuilder, DanglingUntriaged> builder_;
+  raw_ptr<BlobDataBuilder, DanglingAcrossTasks> builder_;
   ResultCallback result_callback_;
 };
 
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 6e275b00..01c841f 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -5049,24 +5049,6 @@
             ]
         }
     ],
-    "DownweightAutocompleteSearchResultsStudy": [
-        {
-            "platforms": [
-                "chromeos"
-            ],
-            "experiments": [
-                {
-                    "name": "EnabledWithCutoff_20221221",
-                    "params": {
-                        "enable_cutoff": "true"
-                    },
-                    "enable_features": [
-                        "LauncherFuzzyMatchForOmnibox"
-                    ]
-                }
-            ]
-        }
-    ],
     "EcheNetworkConnectionState": [
         {
             "platforms": [
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
index 9ea4cfa..03804964 100644
--- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl
+++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -9634,6 +9634,12 @@
     parameters
       string bucketId
 
+  # https://wicg.github.io/attribution-reporting-api/
+  experimental command setAttributionReportingLocalTestingMode
+    parameters
+      # If enabled, noise is suppressed and reports are sent immediately.
+      boolean enabled
+
 # The SystemInfo domain defines methods and events for querying low-level system information.
 experimental domain SystemInfo
 
diff --git a/third_party/blink/renderer/core/css/resolver/font_builder.cc b/third_party/blink/renderer/core/css/resolver/font_builder.cc
index bddbb98..0f3b7c7 100644
--- a/third_party/blink/renderer/core/css/resolver/font_builder.cc
+++ b/third_party/blink/renderer/core/css/resolver/font_builder.cc
@@ -220,10 +220,9 @@
   font_description_.SetFontVariantAlternates(variant_alternates);
 }
 
-void FontBuilder::SetFontSmoothing(FontSmoothingMode foont_smoothing_mode) {
+void FontBuilder::SetFontSmoothing(FontSmoothingMode font_smoothing_mode) {
   Set(PropertySetFlag::kFontSmoothing);
-
-  font_description_.SetFontSmoothing(foont_smoothing_mode);
+  font_description_.SetFontSmoothing(font_smoothing_mode);
 }
 
 void FontBuilder::SetFeatureSettings(
@@ -392,88 +391,175 @@
   font_description.SetComputedSize(computed_size);
 }
 
-void FontBuilder::UpdateFontDescription(FontDescription& description,
+bool FontBuilder::UpdateFontDescription(FontDescription& description,
                                         FontOrientation font_orientation) {
+  bool modified = false;
   if (IsSet(PropertySetFlag::kFamily)) {
-    description.SetGenericFamily(font_description_.GenericFamily());
-    description.SetFamily(font_description_.Family());
+    if (description.GenericFamily() != font_description_.GenericFamily() ||
+        description.Family() != font_description_.Family()) {
+      modified = true;
+      description.SetGenericFamily(font_description_.GenericFamily());
+      description.SetFamily(font_description_.Family());
+    }
   }
   if (IsSet(PropertySetFlag::kSize)) {
-    description.SetKeywordSize(font_description_.KeywordSize());
-    description.SetSpecifiedSize(font_description_.SpecifiedSize());
-    description.SetIsAbsoluteSize(font_description_.IsAbsoluteSize());
+    if (description.KeywordSize() != font_description_.KeywordSize() ||
+        description.SpecifiedSize() != font_description_.SpecifiedSize() ||
+        description.IsAbsoluteSize() != font_description_.IsAbsoluteSize()) {
+      modified = true;
+      description.SetKeywordSize(font_description_.KeywordSize());
+      description.SetSpecifiedSize(font_description_.SpecifiedSize());
+      description.SetIsAbsoluteSize(font_description_.IsAbsoluteSize());
+    }
   }
 
   if (IsSet(PropertySetFlag::kSizeAdjust)) {
-    description.SetSizeAdjust(font_description_.SizeAdjust());
+    if (description.SizeAdjust() != font_description_.SizeAdjust()) {
+      modified = true;
+      description.SetSizeAdjust(font_description_.SizeAdjust());
+    }
   }
   if (IsSet(PropertySetFlag::kWeight)) {
-    description.SetWeight(font_description_.Weight());
+    if (description.Weight() != font_description_.Weight()) {
+      modified = true;
+      description.SetWeight(font_description_.Weight());
+    }
   }
   if (IsSet(PropertySetFlag::kStretch)) {
-    description.SetStretch(font_description_.Stretch());
+    if (description.Stretch() != font_description_.Stretch()) {
+      modified = true;
+      description.SetStretch(font_description_.Stretch());
+    }
   }
   if (IsSet(PropertySetFlag::kFeatureSettings)) {
-    description.SetFeatureSettings(font_description_.FeatureSettings());
+    if (description.FeatureSettings() != font_description_.FeatureSettings()) {
+      modified = true;
+      description.SetFeatureSettings(font_description_.FeatureSettings());
+    }
   }
   if (IsSet(PropertySetFlag::kLocale)) {
-    description.SetLocale(font_description_.Locale());
+    if (description.Locale() != font_description_.Locale()) {
+      modified = true;
+      description.SetLocale(font_description_.Locale());
+    }
   }
   if (IsSet(PropertySetFlag::kStyle)) {
-    description.SetStyle(font_description_.Style());
+    if (description.Style() != font_description_.Style()) {
+      modified = true;
+      description.SetStyle(font_description_.Style());
+    }
   }
   if (IsSet(PropertySetFlag::kVariantCaps)) {
-    description.SetVariantCaps(font_description_.VariantCaps());
+    if (description.VariantCaps() != font_description_.VariantCaps()) {
+      modified = true;
+      description.SetVariantCaps(font_description_.VariantCaps());
+    }
   }
   if (IsSet(PropertySetFlag::kVariantEastAsian)) {
-    description.SetVariantEastAsian(font_description_.VariantEastAsian());
+    if (description.VariantEastAsian() !=
+        font_description_.VariantEastAsian()) {
+      modified = true;
+      description.SetVariantEastAsian(font_description_.VariantEastAsian());
+    }
   }
   if (IsSet(PropertySetFlag::kVariantLigatures)) {
-    description.SetVariantLigatures(font_description_.GetVariantLigatures());
+    if (description.GetVariantLigatures() !=
+        font_description_.GetVariantLigatures()) {
+      modified = true;
+      description.SetVariantLigatures(font_description_.GetVariantLigatures());
+    }
   }
   if (IsSet(PropertySetFlag::kVariantNumeric)) {
-    description.SetVariantNumeric(font_description_.VariantNumeric());
+    if (description.VariantNumeric() != font_description_.VariantNumeric()) {
+      modified = true;
+      description.SetVariantNumeric(font_description_.VariantNumeric());
+    }
   }
   if (IsSet(PropertySetFlag::kVariationSettings)) {
-    description.SetVariationSettings(font_description_.VariationSettings());
+    if (description.VariationSettings() !=
+        font_description_.VariationSettings()) {
+      modified = true;
+      description.SetVariationSettings(font_description_.VariationSettings());
+    }
   }
   if (IsSet(PropertySetFlag::kFontSynthesisWeight)) {
-    description.SetFontSynthesisWeight(
-        font_description_.GetFontSynthesisWeight());
+    if (description.GetFontSynthesisWeight() !=
+        font_description_.GetFontSynthesisWeight()) {
+      modified = true;
+      description.SetFontSynthesisWeight(
+          font_description_.GetFontSynthesisWeight());
+    }
   }
   if (IsSet(PropertySetFlag::kFontSynthesisStyle)) {
-    description.SetFontSynthesisStyle(
-        font_description_.GetFontSynthesisStyle());
+    if (description.GetFontSynthesisStyle() !=
+        font_description_.GetFontSynthesisStyle()) {
+      modified = true;
+      description.SetFontSynthesisStyle(
+          font_description_.GetFontSynthesisStyle());
+    }
   }
   if (IsSet(PropertySetFlag::kFontSynthesisSmallCaps)) {
-    description.SetFontSynthesisSmallCaps(
-        font_description_.GetFontSynthesisSmallCaps());
+    if (description.GetFontSynthesisSmallCaps() !=
+        font_description_.GetFontSynthesisSmallCaps()) {
+      modified = true;
+      description.SetFontSynthesisSmallCaps(
+          font_description_.GetFontSynthesisSmallCaps());
+    }
   }
   if (IsSet(PropertySetFlag::kTextRendering)) {
-    description.SetTextRendering(font_description_.TextRendering());
+    if (description.TextRendering() != font_description_.TextRendering()) {
+      modified = true;
+      description.SetTextRendering(font_description_.TextRendering());
+    }
   }
   if (IsSet(PropertySetFlag::kKerning)) {
-    description.SetKerning(font_description_.GetKerning());
+    if (description.GetKerning() != font_description_.GetKerning()) {
+      modified = true;
+      description.SetKerning(font_description_.GetKerning());
+    }
   }
   if (IsSet(PropertySetFlag::kFontOpticalSizing)) {
-    description.SetFontOpticalSizing(font_description_.FontOpticalSizing());
+    if (description.FontOpticalSizing() !=
+        font_description_.FontOpticalSizing()) {
+      modified = true;
+      description.SetFontOpticalSizing(font_description_.FontOpticalSizing());
+    }
   }
   if (IsSet(PropertySetFlag::kFontPalette)) {
-    description.SetFontPalette(font_description_.GetFontPalette());
+    if (description.GetFontPalette() != font_description_.GetFontPalette()) {
+      modified = true;
+      description.SetFontPalette(font_description_.GetFontPalette());
+    }
   }
   if (IsSet(PropertySetFlag::kFontVariantAlternates)) {
-    description.SetFontVariantAlternates(
-        font_description_.GetFontVariantAlternates());
+    if (description.GetFontVariantAlternates() !=
+        font_description_.GetFontVariantAlternates()) {
+      modified = true;
+      description.SetFontVariantAlternates(
+          font_description_.GetFontVariantAlternates());
+    }
   }
   if (IsSet(PropertySetFlag::kFontSmoothing)) {
-    description.SetFontSmoothing(font_description_.FontSmoothing());
+    if (description.FontSmoothing() != font_description_.FontSmoothing()) {
+      modified = true;
+      description.SetFontSmoothing(font_description_.FontSmoothing());
+    }
   }
   if (IsSet(PropertySetFlag::kTextOrientation) ||
       IsSet(PropertySetFlag::kWritingMode)) {
-    description.SetOrientation(font_orientation);
+    if (description.Orientation() != font_orientation) {
+      modified = true;
+      description.SetOrientation(font_orientation);
+    }
   }
   if (IsSet(PropertySetFlag::kVariantPosition)) {
-    description.SetVariantPosition(font_description_.VariantPosition());
+    if (description.VariantPosition() != font_description_.VariantPosition()) {
+      modified = true;
+      description.SetVariantPosition(font_description_.VariantPosition());
+    }
+  }
+  if (!modified && !IsSet(PropertySetFlag::kEffectiveZoom)) {
+    return false;
   }
 
   float size = description.SpecifiedSize();
@@ -487,6 +573,7 @@
   if (size && description.HasSizeAdjust()) {
     description.SetAdjustedSize(size);
   }
+  return true;
 }
 
 FontSelector* FontBuilder::FontSelectorFromTreeScope(
@@ -524,7 +611,12 @@
                    : builder.GetFontDescription();
 
   FontDescription description = builder.GetFontDescription();
-  UpdateFontDescription(description, builder.ComputeFontOrientation());
+  if (!UpdateFontDescription(description, builder.ComputeFontOrientation())) {
+    // Early exit; nothing was actually changed (i.e., everything that was set
+    // already matched the initial/parent style).
+    flags_ = 0;
+    return;
+  }
   UpdateSpecifiedSize(description, parent_description);
   UpdateComputedSize(description, builder);
 
diff --git a/third_party/blink/renderer/core/css/resolver/font_builder.h b/third_party/blink/renderer/core/css/resolver/font_builder.h
index 5555ddab..8bce0915 100644
--- a/third_party/blink/renderer/core/css/resolver/font_builder.h
+++ b/third_party/blink/renderer/core/css/resolver/font_builder.h
@@ -88,7 +88,9 @@
   void SetVariantPosition(FontDescription::FontVariantPosition);
 
   // FIXME: These need to just vend a Font object eventually.
-  void UpdateFontDescription(FontDescription&,
+  // UpdateFontDescription() returns true if any properties were actually
+  // changed.
+  bool UpdateFontDescription(FontDescription&,
                              FontOrientation = FontOrientation::kHorizontal);
   void CreateFont(ComputedStyleBuilder&, const ComputedStyle* parent_style);
   void CreateInitialFont(ComputedStyleBuilder&);
diff --git a/third_party/blink/renderer/core/html/track/text_track_container.cc b/third_party/blink/renderer/core/html/track/text_track_container.cc
index 5540132..6ea0e8e 100644
--- a/third_party/blink/renderer/core/html/track/text_track_container.cc
+++ b/third_party/blink/renderer/core/html/track/text_track_container.cc
@@ -123,9 +123,8 @@
   // for lack of per-spec vh/vw support) but the whole media element is used
   // for cue rendering. This is inconsistent. See also the somewhat related
   // spec bug: https://www.w3.org/Bugs/Public/show_bug.cgi?id=28105
-  LayoutSize video_size = To<LayoutBox>(media_layout_object)->ContentSize();
-  LayoutUnit smallest_dimension =
-      std::min(video_size.Height(), video_size.Width());
+  PhysicalSize video_size = To<LayoutBox>(media_layout_object)->ContentSize();
+  LayoutUnit smallest_dimension = std::min(video_size.height, video_size.width);
   float font_size = smallest_dimension * 0.05f;
   if (media_layout_object->GetFrame())
     font_size /= media_layout_object->GetFrame()->PageZoomFactor();
diff --git a/third_party/blink/renderer/core/layout/layout_box.h b/third_party/blink/renderer/core/layout/layout_box.h
index 0afc674..50c12b2 100644
--- a/third_party/blink/renderer/core/layout/layout_box.h
+++ b/third_party/blink/renderer/core/layout/layout_box.h
@@ -639,9 +639,9 @@
     return (ClientHeight() - PaddingTop() - PaddingBottom())
         .ClampNegativeToZero();
   }
-  LayoutSize ContentSize() const {
+  PhysicalSize ContentSize() const {
     NOT_DESTROYED();
-    return LayoutSize(ContentWidth(), ContentHeight());
+    return PhysicalSize(ContentWidth(), ContentHeight());
   }
   LayoutUnit ContentLogicalWidth() const {
     NOT_DESTROYED();
diff --git a/third_party/blink/renderer/core/paint/box_paint_invalidator.cc b/third_party/blink/renderer/core/paint/box_paint_invalidator.cc
index c553328..db733488 100644
--- a/third_party/blink/renderer/core/paint/box_paint_invalidator.cc
+++ b/third_party/blink/renderer/core/paint/box_paint_invalidator.cc
@@ -403,7 +403,7 @@
   // crbug.com/490533
   if ((style.BackgroundLayers().AnyLayerUsesContentBox() ||
        style.MaskLayers().AnyLayerUsesContentBox()) &&
-      PhysicalSizeToBeNoop(box_.ContentSize()) != box_.Size()) {
+      box_.ContentSize() != box_.Size()) {
     return true;
   }
 
diff --git a/third_party/blink/renderer/core/resize_observer/resize_observer_entry.cc b/third_party/blink/renderer/core/resize_observer/resize_observer_entry.cc
index 9fcdfb3..17fb1c4d 100644
--- a/third_party/blink/renderer/core/resize_observer/resize_observer_entry.cc
+++ b/third_party/blink/renderer/core/resize_observer/resize_observer_entry.cc
@@ -40,8 +40,8 @@
 
 void ResizeObserverEntry::PopulateFromLayoutBox(const LayoutBox& layout_box) {
   const ComputedStyle& style = layout_box.StyleRef();
-  LayoutRect content_rect(
-      LayoutPoint(layout_box.PaddingLeft(), layout_box.PaddingTop()),
+  PhysicalRect content_rect(
+      PhysicalOffset(layout_box.PaddingLeft(), layout_box.PaddingTop()),
       layout_box.ContentSize());
   content_rect_ =
       ResizeObserverUtilities::ZoomAdjustedLayoutRect(content_rect, style);
diff --git a/third_party/blink/renderer/core/resize_observer/resize_observer_utilities.cc b/third_party/blink/renderer/core/resize_observer/resize_observer_utilities.cc
index c1696f6..7ec8d04 100644
--- a/third_party/blink/renderer/core/resize_observer/resize_observer_utilities.cc
+++ b/third_party/blink/renderer/core/resize_observer/resize_observer_utilities.cc
@@ -69,7 +69,7 @@
 }
 
 DOMRectReadOnly* ResizeObserverUtilities::ZoomAdjustedLayoutRect(
-    LayoutRect content_rect,
+    PhysicalRect content_rect,
     const ComputedStyle& style) {
   content_rect.SetX(
       AdjustForAbsoluteZoom::AdjustLayoutUnit(content_rect.X(), style));
diff --git a/third_party/blink/renderer/core/resize_observer/resize_observer_utilities.h b/third_party/blink/renderer/core/resize_observer/resize_observer_utilities.h
index 8e9af44..c21a5237 100644
--- a/third_party/blink/renderer/core/resize_observer/resize_observer_utilities.h
+++ b/third_party/blink/renderer/core/resize_observer/resize_observer_utilities.h
@@ -17,8 +17,8 @@
 class DOMRectReadOnly;
 class LayoutBox;
 class LayoutObject;
-class LayoutRect;
 class LayoutSize;
+struct PhysicalRect;
 
 // Helper functions for ResizeObserverEntry and ResizeObservation.
 class ResizeObserverUtilities {
@@ -38,7 +38,7 @@
       const LayoutObject& layout_object,
       const ComputedStyle& style);
 
-  static DOMRectReadOnly* ZoomAdjustedLayoutRect(LayoutRect content_rect,
+  static DOMRectReadOnly* ZoomAdjustedLayoutRect(PhysicalRect content_rect,
                                                  const ComputedStyle& style);
 };
 
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc
index 7a9c010..63300ff 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc
@@ -737,8 +737,7 @@
 MLOperand* MLGraphBuilder::concat(const HeapVector<Member<MLOperand>>& inputs,
                                   const uint32_t axis,
                                   ExceptionState& exception_state) {
-  auto* concat =
-      MakeGarbageCollected<MLOperator>(this, MLOperator::OperatorKind::kConcat);
+  auto* concat = MakeGarbageCollected<MLConcatOperator>(this, axis);
   if (inputs.empty()) {
     exception_state.ThrowDOMException(DOMExceptionCode::kDataError,
                                       "The inputs should not be empty.");
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_xnnpack.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_xnnpack.cc
index afd5073..c3d41b3 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_xnnpack.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_xnnpack.cc
@@ -1581,27 +1581,12 @@
   return xnn_status_success;
 }
 
-// Helper to find the concat axis by comparing the first input shape and output
-// shape which is already calculated by `MLGraphBuilder::concat()`.
-absl::optional<uint32_t> GetConcatAxis(const MLOperator* concat) {
-  // The output tensor should has the same shape size with all the input tensors
-  const auto& output_dims = concat->Outputs()[0]->Dimensions();
-  for (const auto& input : concat->Inputs()) {
-    CHECK_EQ(input->Dimensions().size(), output_dims.size());
-  }
-  const auto& input_dims = concat->Inputs()[0]->Dimensions();
-  for (wtf_size_t i = 0; i < input_dims.size(); ++i) {
-    if (input_dims[i] != output_dims[i]) {
-      return i;
-    }
-  }
-  return absl::nullopt;
-}
-
 xnn_status DefineXnnNodeForConcat(xnn_subgraph_t subgraph,
-                                  const MLOperator* concat,
+                                  const MLOperator* ml_operator,
                                   const OperandValueIdMap& operand_value_id_map,
                                   String& error_message) {
+  const MLConcatOperator* concat =
+      static_cast<const MLConcatOperator*>(ml_operator);
   const auto inputs_size = concat->Inputs().size();
   Vector<uint32_t> input_ids(inputs_size);
   for (uint32_t i = 0; i < inputs_size; ++i) {
@@ -1616,25 +1601,20 @@
         xnn_define_copy(subgraph, input_ids[0], output_id, flags));
     return xnn_status_success;
   }
-  absl::optional<uint32_t> axis = GetConcatAxis(concat);
-  if (!axis) {
-    error_message = "Can not find the concat axis.";
-    return xnn_status_unsupported_parameter;
-  }
+  const auto axis = concat->Axis();
   switch (inputs_size) {
     case 2u:
-      XNN_CHECK_STATUS_AND_SET_ERROR_MESSAGE(
-          xnn_define_concatenate2(subgraph, axis.value(), input_ids[0],
-                                  input_ids[1], output_id, flags));
+      XNN_CHECK_STATUS_AND_SET_ERROR_MESSAGE(xnn_define_concatenate2(
+          subgraph, axis, input_ids[0], input_ids[1], output_id, flags));
       break;
     case 3u:
-      XNN_CHECK_STATUS_AND_SET_ERROR_MESSAGE(xnn_define_concatenate3(
-          subgraph, axis.value(), input_ids[0], input_ids[1], input_ids[2],
-          output_id, flags));
+      XNN_CHECK_STATUS_AND_SET_ERROR_MESSAGE(
+          xnn_define_concatenate3(subgraph, axis, input_ids[0], input_ids[1],
+                                  input_ids[2], output_id, flags));
       break;
     case 4u:
       XNN_CHECK_STATUS_AND_SET_ERROR_MESSAGE(xnn_define_concatenate4(
-          subgraph, axis.value(), input_ids[0], input_ids[1], input_ids[2],
+          subgraph, axis, input_ids[0], input_ids[1], input_ids[2],
           input_ids[3], output_id, flags));
       break;
     default:
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_operator.cc b/third_party/blink/renderer/modules/ml/webnn/ml_operator.cc
index 3957e087..ca74b7d4 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_operator.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_operator.cc
@@ -121,6 +121,16 @@
   is_connected_ = true;
 }
 
+MLConcatOperator::MLConcatOperator(MLGraphBuilder* builder, const uint32_t axis)
+    : MLOperator(builder, MLOperator::OperatorKind::kConcat, nullptr),
+      axis_(axis) {}
+
+MLConcatOperator::~MLConcatOperator() = default;
+
+uint32_t MLConcatOperator::Axis() const {
+  return axis_;
+}
+
 MLPadOperator::MLPadOperator(MLGraphBuilder* builder,
                              const Vector<uint32_t>& beginning_padding,
                              const Vector<uint32_t>& ending_padding,
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_operator.h b/third_party/blink/renderer/modules/ml/webnn/ml_operator.h
index ab78498..d1174c5 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_operator.h
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_operator.h
@@ -108,6 +108,21 @@
   HeapVector<Member<const MLOperand>> outputs_;
 };
 
+class MODULES_EXPORT MLConcatOperator : public MLOperator {
+ public:
+  MLConcatOperator(MLGraphBuilder* builder, const uint32_t axis);
+
+  MLConcatOperator(const MLConcatOperator&) = delete;
+  MLConcatOperator& operator=(const MLConcatOperator&) = delete;
+
+  ~MLConcatOperator();
+
+  uint32_t Axis() const;
+
+ private:
+  uint32_t axis_;
+};
+
 class MODULES_EXPORT MLPadOperator : public MLOperator {
  public:
   MLPadOperator(MLGraphBuilder* builder,
diff --git a/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc b/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc
index 8555485..e10c9982 100644
--- a/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc
+++ b/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc
@@ -9,7 +9,6 @@
 
 #include "base/task/single_thread_task_runner.h"
 #include "components/viz/common/resources/release_callback.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
diff --git a/third_party/blink/renderer/platform/graphics/canvas_color_params.cc b/third_party/blink/renderer/platform/graphics/canvas_color_params.cc
index 318005b6..6892376 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_color_params.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_color_params.cc
@@ -5,7 +5,6 @@
 #include "third_party/blink/renderer/platform/graphics/canvas_color_params.h"
 
 #include "cc/paint/skia_paint_canvas.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "third_party/khronos/GLES2/gl2.h"
 #include "third_party/khronos/GLES2/gl2ext.h"
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource.cc b/third_party/blink/renderer/platform/graphics/canvas_resource.cc
index 9612482..3647799 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource.cc
@@ -12,7 +12,6 @@
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
 #include "components/viz/common/resources/bitmap_allocation.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/shared_image_format.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
 #include "components/viz/common/resources/transferable_resource.h"
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
index 1f004d7..f4c2de6 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
@@ -19,7 +19,6 @@
 #include "cc/paint/decode_stashing_image_provider.h"
 #include "cc/paint/display_item_list.h"
 #include "cc/tiles/software_image_decode_cache.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "gpu/command_buffer/client/raster_interface.h"
diff --git a/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc b/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc
index 3d05cf4..9dbda9a 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc
@@ -8,7 +8,6 @@
 #include "cc/layers/texture_layer.h"
 #include "cc/resources/cross_thread_shared_bitmap.h"
 #include "components/viz/common/resources/bitmap_allocation.h"
-#include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/resources/shared_bitmap.h"
 #include "components/viz/common/resources/shared_image_format_utils.h"
 #include "components/viz/common/resources/transferable_resource.h"
diff --git a/third_party/blink/web_tests/SlowTests b/third_party/blink/web_tests/SlowTests
index 786d48d..4cc4d6a 100644
--- a/third_party/blink/web_tests/SlowTests
+++ b/third_party/blink/web_tests/SlowTests
@@ -884,7 +884,6 @@
 crbug.com/1091716 [ Mac12 ] svg/as-object/sizing/svg-in-object-placeholder-percentage-percentage-no-intrinsic-ratio.html [ Slow ]
 crbug.com/1091716 [ Release Win ] svg/as-object/sizing/svg-in-object-placeholder-percentage-percentage-no-intrinsic-ratio.html [ Slow ]
 crbug.com/1233743 [ Linux ] svg/filters/feDisplacementMap.svg [ Slow ]
-crbug.com/1233743 [ Mac12 ] svg/filters/feDisplacementMap.svg [ Slow ]
 crbug.com/1233743 [ Release Win ] svg/filters/feDisplacementMap.svg [ Slow ]
 
 crbug.com/1043669 [ Mac Release ] inspector-protocol/emulation/set-vision-deficiency.js [ Slow ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 7553b24..f8978e2 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -212,8 +212,6 @@
 # --- Skia roll test suppressions
 # --- END Skia roll test suppresions
 
-# Sheriff on 2020-09-03
-crbug.com/1124352 media/picture-in-picture/controls/picture-in-picture-button.html [ Crash Pass ]
 
 # These fail due to subtle anti-aliasing differences cause by the fact that
 # <canvas> renders via IOSurface and OffscreenCanvas does not.
@@ -1310,7 +1308,6 @@
 crbug.com/1377794 [ Win ] external/wpt/css/css-fonts/font-variant-emoji-1.html [ Failure ]
 crbug.com/1377794 [ Mac ] external/wpt/css/css-fonts/font-variant-emoji-2.html [ Failure ]
 crbug.com/1375884 external/wpt/css/css-fonts/rlh-in-monospace.html [ Failure ]
-crbug.com/1456655 external/wpt/css/css-fonts/format-specifiers-variations.html [ Failure ]
 
 crbug.com/1317062 external/wpt/html/rendering/non-replaced-elements/phrasing-content-0/br-wbr-content/content-property.tentative.html [ Failure ]
 
@@ -1825,7 +1822,6 @@
 
 crbug.com/821455 editing/pasteboard/drag-files-to-editable-element.html [ Failure ]
 
-crbug.com/1170052 external/wpt/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-audio-is-silence.https.html [ Pass Timeout ]
 crbug.com/1174937 external/wpt/mediacapture-streams/MediaStream-clone.https.html [ Crash ]
 
 
@@ -3194,7 +3190,10 @@
 crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-joining-dl-element-and-another-list.tentative.html?Delete [ Failure Timeout ]
 crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-deleting-in-list-items.tentative.html?Backspace,ol [ Failure Timeout ]
 crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-deleting-in-list-items.tentative.html?Delete,ol [ Failure Timeout ]
-crbug.com/626703 [ Mac ] external/wpt/webxr/xr_viewport_scale.https.html [ Failure Timeout ]
+crbug.com/626703 [ Mac10.15 Release ] external/wpt/webxr/xr_viewport_scale.https.html [ Failure Timeout ]
+crbug.com/626703 [ Mac11 Release ] external/wpt/webxr/xr_viewport_scale.https.html [ Failure Timeout ]
+crbug.com/626703 [ Mac12 Release ] external/wpt/webxr/xr_viewport_scale.https.html [ Failure Timeout ]
+crbug.com/626703 [ Mac13 ] external/wpt/webxr/xr_viewport_scale.https.html [ Failure Timeout ]
 crbug.com/626703 external/wpt/infrastructure/testdriver/actions/iframe.html [ Failure Timeout ]
 crbug.com/626703 external/wpt/infrastructure/testdriver/actions/crossOrigin.sub.html [ Timeout ]
 crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-during-and-after-dispatch.tentative.html [ Failure Timeout ]
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-extensions/RTCRtpTransceiver-headerExtensionControl.html b/third_party/blink/web_tests/external/wpt/webrtc-extensions/RTCRtpTransceiver-headerExtensionControl.html
index 79eba02..796d35d 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc-extensions/RTCRtpTransceiver-headerExtensionControl.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc-extensions/RTCRtpTransceiver-headerExtensionControl.html
@@ -94,7 +94,7 @@
   t.add_cleanup(() => pc.close());
   const transceiver = pc.addTransceiver('audio');
   const capabilities = transceiver.getHeaderExtensionsToNegotiate();
-  let capability = capabilities.find((capability) => {
+  const capability = capabilities.find((capability) => {
       return capability.uri === 'urn:ietf:params:rtp-hdrext:sdes:mid';
   });
   ['sendonly', 'recvonly', 'inactive', 'stopped'].map(direction => {
@@ -109,14 +109,14 @@
   const pc = new RTCPeerConnection();
   t.add_cleanup(() => pc.close());
   const transceiver = pc.addTransceiver('audio');
-  let capabilities = transceiver.getHeaderExtensionsToNegotiate();
-  let selected_capability = capabilities.find((capability) => {
+  const capabilities = transceiver.getHeaderExtensionsToNegotiate();
+  const selected_capability = capabilities.find((capability) => {
       return capability.direction === 'sendrecv' &&
              capability.uri !== 'urn:ietf:params:rtp-hdrext:sdes:mid';
   });
   selected_capability.direction = 'stopped';
   const offered_capabilities = transceiver.getHeaderExtensionsToNegotiate();
-  let altered_capability = capabilities.find((capability) => {
+  const altered_capability = capabilities.find((capability) => {
       return capability.uri === selected_capability.uri &&
              capability.direction === 'stopped';
   });
@@ -292,4 +292,66 @@
   }
 }, 'Prior to negotiation, getNegotiatedHeaderExtensions() returns `stopped` for all extensions.');
 
+promise_test(async t => {
+  const pc1 = new RTCPeerConnection();
+  t.add_cleanup(() => pc1.close());
+  const pc2 = new RTCPeerConnection();
+  t.add_cleanup(() => pc2.close());
+
+  // Disable a non-mandatory extension before first negotiation.
+  const transceiver = pc1.addTransceiver('video');
+  const capabilities = transceiver.getHeaderExtensionsToNegotiate();
+  const selected_capability = capabilities.find((capability) => {
+      return capability.direction === 'sendrecv' &&
+             capability.uri !== 'urn:ietf:params:rtp-hdrext:sdes:mid';
+  });
+  selected_capability.direction = 'stopped';
+  transceiver.setHeaderExtensionsToNegotiate(capabilities);
+
+  await negotiate(pc1, pc2);
+  const negotiated_capabilites = transceiver.getNegotiatedHeaderExtensions();
+
+  const local_negotiated = transceiver.getNegotiatedHeaderExtensions().find(ext => {
+    return ext.uri === selected_capability.uri;
+  });
+  assert_equals(local_negotiated.direction, 'stopped');
+  const remote_negotiated = pc2.getTransceivers()[0].getNegotiatedHeaderExtensions().find(ext => {
+    return ext.uri === selected_capability.uri;
+  });
+  assert_equals(remote_negotiated.direction, 'stopped');
+}, 'Answer header extensions are a subset of the offered header extensions');
+
+promise_test(async t => {
+  const pc1 = new RTCPeerConnection();
+  t.add_cleanup(() => pc1.close());
+  const pc2 = new RTCPeerConnection();
+  t.add_cleanup(() => pc2.close());
+
+  // Disable a non-mandatory extension before first negotiation.
+  const transceiver = pc1.addTransceiver('video');
+  const capabilities = transceiver.getHeaderExtensionsToNegotiate();
+  const selected_capability = capabilities.find((capability) => {
+      return capability.direction === 'sendrecv' &&
+             capability.uri !== 'urn:ietf:params:rtp-hdrext:sdes:mid';
+  });
+  selected_capability.direction = 'stopped';
+  transceiver.setHeaderExtensionsToNegotiate(capabilities);
+
+  await negotiate(pc1, pc2);
+  // Negotiate, switching sides.
+  await negotiate(pc2, pc1);
+
+  // PC2 will re-offer the extension.
+  const remote_reoffered = pc2.getTransceivers()[0].getHeaderExtensionsToNegotiate().find(ext => {
+    return ext.uri === selected_capability.uri;
+  });
+  assert_equals(remote_reoffered.direction, 'sendrecv');
+
+  // But PC1 will still reject the extension.
+  const negotiated_capabilites = transceiver.getNegotiatedHeaderExtensions();
+  const local_negotiated = transceiver.getNegotiatedHeaderExtensions().find(ext => {
+    return ext.uri === selected_capability.uri;
+  });
+  assert_equals(local_negotiated.direction, 'stopped');
+}, 'A subsequent offer from the other side will reoffer extensions not negotiated by the initial offerer');
 </script>
diff --git a/third_party/blink/web_tests/http/tests/devtools/indexeddb/database-refresh-view.js b/third_party/blink/web_tests/http/tests/devtools/indexeddb/database-refresh-view.js
index 2795112..a51e4ef 100644
--- a/third_party/blink/web_tests/http/tests/devtools/indexeddb/database-refresh-view.js
+++ b/third_party/blink/web_tests/http/tests/devtools/indexeddb/database-refresh-view.js
@@ -9,7 +9,11 @@
 (async function() {
   TestRunner.addResult(`Tests refreshing the database information and data views.\n`);
   await TestRunner.loadLegacyModule('console');
-    // Note: every test that uses a storage API must manually clean-up state from previous tests.
+  await TestRunner.navigatePromise('http://127.0.0.1:8000/devtools/indexeddb/resources/without-indexed-db.html');
+  await ApplicationTestRunner.setupIndexedDBHelpers();
+
+  // Note: every test that uses a storage API must manually clean-up state from
+  // previous tests.
   await ApplicationTestRunner.resetState();
 
   await TestRunner.loadLegacyModule('console');
@@ -62,13 +66,8 @@
   ApplicationTestRunner.dumpIndexedDBTree();
 
   // Create database
-  try {
-    ApplicationTestRunner.createDatabaseAsync(databaseName);
-    await new Promise(waitDatabaseAdded);
-  } catch (e) {
-    TestRunner.addResult(await TestRunnet.evaluateInPageAsync('window.location.href'));
-    throw e;
-  }
+  ApplicationTestRunner.createDatabaseAsync(databaseName);
+  await new Promise(waitDatabaseAdded);
   var idbDatabaseTreeElement = UI.panels.resources.sidebar.indexedDBListTreeElement.idbDatabaseTreeElements[0];
   databaseId = idbDatabaseTreeElement.databaseId;
   TestRunner.addResult('Created database.');
diff --git a/third_party/blink/web_tests/http/tests/devtools/indexeddb/delete-entry.js b/third_party/blink/web_tests/http/tests/devtools/indexeddb/delete-entry.js
index 92781e9..7899d31 100644
--- a/third_party/blink/web_tests/http/tests/devtools/indexeddb/delete-entry.js
+++ b/third_party/blink/web_tests/http/tests/devtools/indexeddb/delete-entry.js
@@ -8,6 +8,8 @@
 (async function() {
   TestRunner.addResult(`Tests object store and index entry deletion.\n`);
   await TestRunner.loadLegacyModule('console');
+  await TestRunner.navigatePromise('http://127.0.0.1:8000/devtools/indexeddb/resources/without-indexed-db.html');
+  await ApplicationTestRunner.setupIndexedDBHelpers();
     // Note: every test that uses a storage API must manually clean-up state from previous tests.
   await ApplicationTestRunner.resetState();
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/indexeddb/live-update-indexeddb-content.js b/third_party/blink/web_tests/http/tests/devtools/indexeddb/live-update-indexeddb-content.js
index 72cbdb0..cef35ee 100644
--- a/third_party/blink/web_tests/http/tests/devtools/indexeddb/live-update-indexeddb-content.js
+++ b/third_party/blink/web_tests/http/tests/devtools/indexeddb/live-update-indexeddb-content.js
@@ -8,6 +8,8 @@
 (async function() {
   TestRunner.addResult(`Tests that the IndexedDB database content live updates.\n`);
   await TestRunner.loadLegacyModule('console');
+  await TestRunner.navigatePromise('http://127.0.0.1:8000/devtools/indexeddb/resources/without-indexed-db.html');
+  await ApplicationTestRunner.setupIndexedDBHelpers();
     // Note: every test that uses a storage API must manually clean-up state from previous tests.
   await ApplicationTestRunner.resetState();
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/indexeddb/live-update-indexeddb-list.js b/third_party/blink/web_tests/http/tests/devtools/indexeddb/live-update-indexeddb-list.js
index 8d10e33..1c4fae3 100644
--- a/third_party/blink/web_tests/http/tests/devtools/indexeddb/live-update-indexeddb-list.js
+++ b/third_party/blink/web_tests/http/tests/devtools/indexeddb/live-update-indexeddb-list.js
@@ -8,6 +8,8 @@
 (async function() {
   TestRunner.addResult(`Tests that the IndexedDB database list live updates.\n`);
   await TestRunner.loadLegacyModule('console');
+  await TestRunner.navigatePromise('http://127.0.0.1:8000/devtools/indexeddb/resources/without-indexed-db.html');
+  await ApplicationTestRunner.setupIndexedDBHelpers();
     // Note: every test that uses a storage API must manually clean-up state from previous tests.
   await ApplicationTestRunner.resetState();
 
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/set-local-testing-mode-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/set-local-testing-mode-expected.txt
new file mode 100644
index 0000000..c1309f1
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/set-local-testing-mode-expected.txt
@@ -0,0 +1,14 @@
+Test that the Storage.setAttributionReportingLocalTestingMode command is handled.
+{
+    id : <number>
+    result : {
+    }
+    sessionId : <string>
+}
+{
+    id : <number>
+    result : {
+    }
+    sessionId : <string>
+}
+
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/set-local-testing-mode.js b/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/set-local-testing-mode.js
new file mode 100644
index 0000000..f30d0746
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/set-local-testing-mode.js
@@ -0,0 +1,16 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(async function(testRunner) {
+  const {dp} = await testRunner.startBlank(
+      'Test that the Storage.setAttributionReportingLocalTestingMode command is handled.');
+
+  testRunner.log(await dp.Storage.setAttributionReportingLocalTestingMode(
+      {enabled: true}));
+
+  testRunner.log(await dp.Storage.setAttributionReportingLocalTestingMode(
+      {enabled: false}));
+
+  testRunner.completeTest();
+})
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml
index 53c1d5bc..6df2a37 100644
--- a/tools/metrics/histograms/metadata/media/histograms.xml
+++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -1416,21 +1416,6 @@
   </summary>
 </histogram>
 
-<histogram name="Media.AudioInputDevice.AudioServiceDelayDifference{Duration}"
-    units="ms" expires_after="2023-08-01">
-  <owner>fhernqvist@google.com</owner>
-  <owner>olka@chromium.org</owner>
-  <owner>webrtc-audio-uma@google.com</owner>
-  <summary>
-    The difference between the largest and the lowest audio capture delay
-    observed during the sample interval. This stat considers the audio capture
-    delay in the Audio Service, including the IPC and the OS. Logged at the end
-    of each 1000-callback interval for Intervals. Logged at the end of the
-    stream for Short.
-  </summary>
-  <token key="Duration" variants="AudioAggregationDuration"/>
-</histogram>
-
 <histogram name="Media.AudioInputDevice.AudioServiceGlitchCount{Duration}"
     units="glitches" expires_after="2024-02-01">
   <owner>fhernqvist@google.com</owner>
@@ -1539,25 +1524,6 @@
   </summary>
 </histogram>
 
-<histogram
-    name="Media.AudioOutputDevice.AudioServiceDelayDifference{Duration}{LatencyTag}"
-    units="ms" expires_after="2023-08-01">
-  <owner>fhernqvist@google.com</owner>
-  <owner>olka@chromium.org</owner>
-  <owner>dalecurtis@chromium.org</owner>
-  <owner>tguilbert@chromium.org</owner>
-  <owner>webrtc-audio-uma@google.com</owner>
-  <summary>
-    The difference between the largest and the lowest audio playout delay
-    observed during the sample interval. This stat considers the audio playout
-    delay in the Audio Service, including the IPC and the OS. Logged at the end
-    of each 1000-callback interval for Intervals. Logged at the end of the
-    stream for Short.
-  </summary>
-  <token key="Duration" variants="AudioAggregationDuration"/>
-  <token key="LatencyTag" variants="AudioLatencyTag"/>
-</histogram>
-
 <histogram name="Media.AudioOutputDevice.AudioServiceDelay{LatencyTag}"
     units="ms" expires_after="2024-02-01">
   <owner>fhernqvist@google.com</owner>
diff --git a/ui/accessibility/platform/ax_platform_node_base.cc b/ui/accessibility/platform/ax_platform_node_base.cc
index 525eaef..c22a88f 100644
--- a/ui/accessibility/platform/ax_platform_node_base.cc
+++ b/ui/accessibility/platform/ax_platform_node_base.cc
@@ -10,6 +10,7 @@
 #include <sstream>
 #include <string>
 #include <unordered_map>
+#include <utility>
 
 #include "base/no_destructor.h"
 #include "base/numerics/checked_math.h"
@@ -1640,6 +1641,18 @@
 AXLegacyHypertext::AXLegacyHypertext(const AXLegacyHypertext& other) = default;
 AXLegacyHypertext& AXLegacyHypertext::operator=(
     const AXLegacyHypertext& other) = default;
+AXLegacyHypertext::AXLegacyHypertext(AXLegacyHypertext&& other) noexcept
+    : needs_update(std::exchange(other.needs_update, true)),
+      hyperlink_offset_to_index(std::move(other.hyperlink_offset_to_index)),
+      hyperlinks(std::move(other.hyperlinks)),
+      hypertext(std::move(other.hypertext)) {}
+AXLegacyHypertext& AXLegacyHypertext::operator=(AXLegacyHypertext&& other) {
+  needs_update = std::exchange(other.needs_update, true);
+  hyperlink_offset_to_index = std::move(other.hyperlink_offset_to_index);
+  hyperlinks = std::move(other.hyperlinks);
+  hypertext = std::move(other.hypertext);
+  return *this;
+}
 
 // TODO(nektar): To be able to use AXNode in Views, move this logic to AXNode.
 void AXPlatformNodeBase::UpdateComputedHypertext() const {
diff --git a/ui/accessibility/platform/ax_platform_node_base.h b/ui/accessibility/platform/ax_platform_node_base.h
index ac22478..8696761 100644
--- a/ui/accessibility/platform/ax_platform_node_base.h
+++ b/ui/accessibility/platform/ax_platform_node_base.h
@@ -43,6 +43,8 @@
   ~AXLegacyHypertext();
   AXLegacyHypertext(const AXLegacyHypertext& other);
   AXLegacyHypertext& operator=(const AXLegacyHypertext& other);
+  AXLegacyHypertext(AXLegacyHypertext&& other) noexcept;
+  AXLegacyHypertext& operator=(AXLegacyHypertext&& other);
 
   // A flag that should be set if the hypertext information in this struct is
   // out-of-date and needs to be updated. This flag should always be set upon
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index 80987a3d..672276a 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -7920,13 +7920,6 @@
   return false;
 }
 
-void AXPlatformNodeWin::ComputeHypertextRemovedAndInserted(size_t* start,
-                                                           size_t* old_len,
-                                                           size_t* new_len) {
-  AXPlatformNodeBase::ComputeHypertextRemovedAndInserted(old_hypertext_, start,
-                                                         old_len, new_len);
-}
-
 double AXPlatformNodeWin::GetHorizontalScrollPercent() {
   if (!IsHorizontallyScrollable())
     return UIA_ScrollPatternNoScroll;
diff --git a/ui/accessibility/platform/ax_platform_node_win.h b/ui/accessibility/platform/ax_platform_node_win.h
index 1dd6214..38f6c87 100644
--- a/ui/accessibility/platform/ax_platform_node_win.h
+++ b/ui/accessibility/platform/ax_platform_node_win.h
@@ -1220,8 +1220,6 @@
   // Relationships between this node and other nodes.
   std::vector<Microsoft::WRL::ComPtr<AXPlatformRelationWin>> relations_;
 
-  AXLegacyHypertext old_hypertext_;
-
   // These protected methods are still used by BrowserAccessibilityComWin. At
   // some point post conversion, we can probably move these to be private
   // methods.
@@ -1233,9 +1231,6 @@
   // Also, in IA2, text that includes embedded objects is called hypertext.
   // Returns true if the current object is an IA2 hyperlink.
   bool IsHyperlink();
-  void ComputeHypertextRemovedAndInserted(size_t* start,
-                                          size_t* old_len,
-                                          size_t* new_len);
 
   // If offset is a member of IA2TextSpecialOffsets this function updates the
   // value of offset and returns, otherwise offset remains unchanged.
diff --git a/ui/aura/window.h b/ui/aura/window.h
index 3120672..6777b11 100644
--- a/ui/aura/window.h
+++ b/ui/aura/window.h
@@ -733,7 +733,7 @@
   // parent during its parents destruction.
   bool owned_by_parent_ = true;
 
-  raw_ptr<WindowDelegate, DanglingUntriaged> delegate_;
+  raw_ptr<WindowDelegate, DanglingAcrossTasks> delegate_;
 
   // The Window's parent.
   raw_ptr<Window> parent_ = nullptr;
diff --git a/ui/aura/window_tree_host.h b/ui/aura/window_tree_host.h
index c85e519e..cf045970 100644
--- a/ui/aura/window_tree_host.h
+++ b/ui/aura/window_tree_host.h
@@ -448,7 +448,7 @@
   // valid during its deletion. (Window's dtor notifies observers that may
   // attempt to reach back up to access this object which will be valid until
   // the end of the dtor).
-  raw_ptr<Window, DanglingUntriaged> window_;  // Owning.
+  raw_ptr<Window, DanglingAcrossTasks> window_;  // Owning.
 
   // Keeps track of the occlusion state of the host, and used to send
   // notifications to observers when it changes.
diff --git a/ui/base/models/simple_menu_model.h b/ui/base/models/simple_menu_model.h
index 5ffe789..6a74342e 100644
--- a/ui/base/models/simple_menu_model.h
+++ b/ui/base/models/simple_menu_model.h
@@ -275,7 +275,8 @@
   void OnMenuClosed();
 
   ItemVector items_;
-  const raw_ptr<Delegate, DanglingUntriaged> delegate_;
+
+  raw_ptr<Delegate, DanglingAcrossTasks> delegate_;
 
   base::WeakPtrFactory<SimpleMenuModel> method_factory_{this};
 };
diff --git a/ui/compositor/layer_tree_owner.h b/ui/compositor/layer_tree_owner.h
index a4e16b3..9cac37473 100644
--- a/ui/compositor/layer_tree_owner.h
+++ b/ui/compositor/layer_tree_owner.h
@@ -34,7 +34,7 @@
   const Layer* root() const { return root_; }
 
  private:
-  raw_ptr<Layer, DanglingUntriaged> root_;
+  raw_ptr<Layer, DanglingAcrossTasks> root_;
 };
 
 }  // namespace
diff --git a/ui/gl/gl_bindings.h b/ui/gl/gl_bindings.h
index 4b8e2ac..92056e43 100644
--- a/ui/gl/gl_bindings.h
+++ b/ui/gl/gl_bindings.h
@@ -534,7 +534,7 @@
 struct GL_EXPORT CurrentGL {
   raw_ptr<GLApi, DanglingUntriaged> Api = nullptr;
   raw_ptr<DriverGL, DanglingUntriaged> Driver = nullptr;
-  raw_ptr<const GLVersionInfo, DanglingUntriaged> Version = nullptr;
+  raw_ptr<const GLVersionInfo, DanglingAcrossTasks> Version = nullptr;
 };
 
 #if defined(USE_EGL)
diff --git a/ui/views/layout/proposed_layout.h b/ui/views/layout/proposed_layout.h
index 7fdd058..e0517e8 100644
--- a/ui/views/layout/proposed_layout.h
+++ b/ui/views/layout/proposed_layout.h
@@ -27,7 +27,7 @@
 
   std::string ToString() const;
 
-  raw_ptr<View, DanglingUntriaged> child_view = nullptr;
+  raw_ptr<View, DanglingAcrossTasks> child_view = nullptr;
   bool visible = false;
   gfx::Rect bounds;
   SizeBounds available_size;
diff --git a/ui/views/view.h b/ui/views/view.h
index eec8861..3c0ce69 100644
--- a/ui/views/view.h
+++ b/ui/views/view.h
@@ -2344,7 +2344,7 @@
   // Context menus -------------------------------------------------------------
 
   // The menu controller.
-  raw_ptr<ContextMenuController, DanglingUntriaged> context_menu_controller_ =
+  raw_ptr<ContextMenuController, DanglingAcrossTasks> context_menu_controller_ =
       nullptr;
 
   // Drag and drop -------------------------------------------------------------
diff --git a/ui/views/view_targeter.h b/ui/views/view_targeter.h
index 8205412..f2839a66 100644
--- a/ui/views/view_targeter.h
+++ b/ui/views/view_targeter.h
@@ -60,7 +60,7 @@
 
   // ViewTargeter does not own the |delegate_|, but |delegate_| must
   // outlive the targeter.
-  raw_ptr<ViewTargeterDelegate, DanglingUntriaged> delegate_;
+  raw_ptr<ViewTargeterDelegate, DanglingAcrossTasks> delegate_;
 };
 
 }  // namespace views
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
index fbee21c..b60c0f8e 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
@@ -301,7 +301,7 @@
 
   // This is the return value from GetNativeView().
   // WARNING: this may be NULL, in particular during shutdown it becomes NULL.
-  raw_ptr<aura::Window, DanglingUntriaged> content_window_;
+  raw_ptr<aura::Window, DanglingAcrossTasks> content_window_;
 
   base::WeakPtr<internal::NativeWidgetDelegate> native_widget_delegate_;
 
diff --git a/ui/views/window/client_view.h b/ui/views/window/client_view.h
index 0c9d5af..7c90ab43 100644
--- a/ui/views/window/client_view.h
+++ b/ui/views/window/client_view.h
@@ -73,7 +73,7 @@
 
  private:
   // The View that this ClientView contains.
-  raw_ptr<View, DanglingUntriaged> contents_view_;
+  raw_ptr<View, DanglingAcrossTasks> contents_view_;
 };
 
 BEGIN_VIEW_BUILDER(VIEWS_EXPORT, ClientView, View)
diff --git a/ui/webui/examples/browser/content_browser_client.h b/ui/webui/examples/browser/content_browser_client.h
index 9889828b..b7862c1 100644
--- a/ui/webui/examples/browser/content_browser_client.h
+++ b/ui/webui/examples/browser/content_browser_client.h
@@ -30,7 +30,7 @@
   std::unique_ptr<content::DevToolsManagerDelegate>
   CreateDevToolsManagerDelegate() override;
 
-  raw_ptr<BrowserMainParts> browser_main_parts_ = nullptr;
+  raw_ptr<BrowserMainParts, DanglingAcrossTasks> browser_main_parts_ = nullptr;
 };
 
 }  // namespace webui_examples