diff --git a/DEPS b/DEPS
index b167905..d2fefb7 100644
--- a/DEPS
+++ b/DEPS
@@ -199,11 +199,11 @@
   # 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': '0a69b4bb071c7868dda1cd734351146898a74aba',
+  'skia_revision': 'be2a8614c5d6155e98ac6d5431349947da41fa0c',
   # 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': '1e60bce4522aa7c92b1010988f8815f96c8243b7',
+  'v8_revision': '6cbcce5b4a6305bfc281c520ca0d24fa6d0c9a39',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -211,7 +211,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '2ed9671a0dddaab9c2582b62d3e479895ee0d333',
+  'angle_revision': '62b8364eafc717bfa9c35af5304b7ad5959e7134',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -266,7 +266,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '3889691dd695c91c212b36d857d73089cb1b8f53',
+  'catapult_revision': '178c01be65a4a5458769084606cbc6504dde10f7',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -274,7 +274,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': 'e2ffb37426336eb63db537529022fadf263ebba6',
+  'devtools_frontend_revision': 'bcd6b5c3ff8aa390dcd16f05afe69454229d21d5',
   # 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.
@@ -314,7 +314,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': '7faa362ea9c2bffbb8e9cc2e2d9f4f4af2fe4dde',
+  'dawn_revision': '111ba65a5e3dbd23a58dd63991e92e9300f44d13',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -1135,7 +1135,7 @@
   },
 
   'src/third_party/libjpeg_turbo':
-    Var('chromium_git') + '/chromium/deps/libjpeg_turbo.git' + '@' + '09efc26aff7983f4377a1743a197ca3d74796d7d',
+    Var('chromium_git') + '/chromium/deps/libjpeg_turbo.git' + '@' + '518d81558c797486e125e37cb529d65b560a6ea0',
 
   'src/third_party/liblouis/src': {
       'url': Var('chromium_git') + '/external/liblouis-github.git' + '@' + '03d7d72d983d47c17f7de95bbeae89fe33e41943',
@@ -1266,7 +1266,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '44ba8e1708abec70b1c85015aae59026fb214c83',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '8fccd82e4e02ac89d83739225d4118b59e8ba1cf',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1546,7 +1546,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/linux-amd64',
-          'version': '1TBlbVMfJAvbrsCVFRL54CvG6OJv660nvwlbVn3QedoC',
+          'version': 'UBQI89SqFeAIiGdjUUikXKgyMRFxDbvtqVUceCn1kcwC',
         },
       ],
       'dep_type': 'cipd',
@@ -1556,7 +1556,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/windows-amd64',
-          'version': 'AefJEwE3M-ke_pwYEVGy2Ct2Ra80EaxvK1KADBuG8-EC',
+          'version': 'kIBp6ZuMA5QTpwxtMM3NtSMezpaetuByhNmVTMg8TtMC',
         },
       ],
       'dep_type': 'cipd',
@@ -1580,7 +1580,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@76d89fa22033c340522095168b69c33ad97e4a57',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@c9846ef0a8288bd025b33e08438511b2439b47eb',
     'condition': 'checkout_src_internal',
   },
 
@@ -1599,7 +1599,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'CahPFs6jLT-RYm6-kxrLmP917a316i02uOphMFmENT0C',
+        'version': 'ze58P0cJwOmw_WVAzh3TDsg4AbgoRTTor2emAc_jh6EC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index ebf2c17a..4042a00 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -2998,10 +2998,13 @@
 
       <!-- For CameraMicTrayItemView -->
       <message name="IDS_ASH_CAMERA_MIC_VM_USING_CAMERA" desc="Tooltip message shown at the systray camera indicator when a VM is using the camera">
-        A virtual machine is using your camera
+        An application is using your camera
+      </message>
+      <message name="IDS_ASH_CAMERA_MIC_VM_USING_CAMERA_AND_MIC" desc="Tooltip message shown at the systray camera indicator when a VM is using both the camera and mic">
+        An application is using your camera and microphone
       </message>
       <message name="IDS_ASH_CAMERA_MIC_VM_USING_MIC" desc="Tooltip message shown at the systray microphone indicator when a VM is using the microphone">
-        A virtual machine is using your microphone
+        An application is using your microphone
       </message>
 
       <message name="IDS_ASH_MESSAGE_CENTER_UNLOCK_TO_PERFORM_ACTION" desc="The short message to encourage user to unlock the device so that Chrome OS can perform the notification action selected by user after unlocking.">
diff --git a/ash/ash_strings_grd/IDS_ASH_CAMERA_MIC_VM_USING_CAMERA.png.sha1 b/ash/ash_strings_grd/IDS_ASH_CAMERA_MIC_VM_USING_CAMERA.png.sha1
index 1e4cfd0..e51c069 100644
--- a/ash/ash_strings_grd/IDS_ASH_CAMERA_MIC_VM_USING_CAMERA.png.sha1
+++ b/ash/ash_strings_grd/IDS_ASH_CAMERA_MIC_VM_USING_CAMERA.png.sha1
@@ -1 +1 @@
-d591db48d6c57816890d85213d98f10f6c322a6b
\ No newline at end of file
+27e7bb4609c6891d64bc47c2e232c6d410634d7e
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_CAMERA_MIC_VM_USING_CAMERA_AND_MIC.png.sha1 b/ash/ash_strings_grd/IDS_ASH_CAMERA_MIC_VM_USING_CAMERA_AND_MIC.png.sha1
new file mode 100644
index 0000000..75601f0
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_CAMERA_MIC_VM_USING_CAMERA_AND_MIC.png.sha1
@@ -0,0 +1 @@
+b5feac7cdbfe35bc8a2bc68a9d41106327310574
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_CAMERA_MIC_VM_USING_MIC.png.sha1 b/ash/ash_strings_grd/IDS_ASH_CAMERA_MIC_VM_USING_MIC.png.sha1
index e2d2dacc..ec1e087 100644
--- a/ash/ash_strings_grd/IDS_ASH_CAMERA_MIC_VM_USING_MIC.png.sha1
+++ b/ash/ash_strings_grd/IDS_ASH_CAMERA_MIC_VM_USING_MIC.png.sha1
@@ -1 +1 @@
-22591a040bd7307c93d9a3c760ed8c976a0b6e22
\ No newline at end of file
+aba716d721efb63bb24f6bd83a3f8d9c609556a4
\ No newline at end of file
diff --git a/ash/drag_drop/drag_drop_controller.cc b/ash/drag_drop/drag_drop_controller.cc
index bcee359..3d9a69c 100644
--- a/ash/drag_drop/drag_drop_controller.cc
+++ b/ash/drag_drop/drag_drop_controller.cc
@@ -23,6 +23,8 @@
 #include "ui/aura/window_delegate.h"
 #include "ui/aura/window_event_dispatcher.h"
 #include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_policy_controller.h"
 #include "ui/base/dragdrop/drag_drop_types.h"
 #include "ui/base/dragdrop/os_exchange_data.h"
 #include "ui/base/dragdrop/os_exchange_data_provider.h"
@@ -81,6 +83,17 @@
   }
 }
 
+bool IsDragDropAllowed(const ui::OSExchangeData* drag_data,
+                       aura::client::DragUpdateInfo& drag_info,
+                       bool is_drop) {
+  DCHECK(drag_data);
+
+  return ui::DataTransferPolicyController::HasInstance()
+             ? ui::DataTransferPolicyController::Get()->IsDragDropAllowed(
+                   drag_data->GetSource(), &drag_info.data_endpoint, is_drop)
+             : true;
+}
+
 }  // namespace
 
 class DragDropTrackerDelegate : public aura::WindowDelegate {
@@ -464,14 +477,19 @@
       e.set_flags(event.flags());
       ui::Event::DispatcherApi(&e).set_target(target);
       drag_info = delegate->OnDragUpdated(e);
+      bool is_drop_allowed = IsDragDropAllowed(drag_data_.get(), drag_info,
+                                               /*is_drop=*/false);
       gfx::NativeCursor cursor = ui::mojom::CursorType::kNoDrop;
-      if (drag_info.drag_operation & ui::DragDropTypes::DRAG_COPY)
-        cursor = ui::mojom::CursorType::kCopy;
-      else if (drag_info.drag_operation & ui::DragDropTypes::DRAG_LINK)
-        cursor = ui::mojom::CursorType::kAlias;
-      else if (drag_info.drag_operation & ui::DragDropTypes::DRAG_MOVE)
-        cursor = ui::mojom::CursorType::kGrabbing;
-
+      if (is_drop_allowed) {
+        if (drag_info.drag_operation & ui::DragDropTypes::DRAG_COPY)
+          cursor = ui::mojom::CursorType::kCopy;
+        else if (drag_info.drag_operation & ui::DragDropTypes::DRAG_LINK)
+          cursor = ui::mojom::CursorType::kAlias;
+        else if (drag_info.drag_operation & ui::DragDropTypes::DRAG_MOVE)
+          cursor = ui::mojom::CursorType::kGrabbing;
+      } else {
+        drag_info.drag_operation = ui::DragDropTypes::DRAG_NONE;
+      }
       Shell::Get()->cursor_manager()->SetCursor(cursor);
     }
   }
@@ -506,8 +524,6 @@
 
 void DragDropController::Drop(aura::Window* target,
                               const ui::LocatedEvent& event) {
-  Shell::Get()->cursor_manager()->SetCursor(ui::mojom::CursorType::kPointer);
-
   // We must guarantee that a target gets a OnDragEntered before Drop. WebKit
   // depends on not getting a Drop without DragEnter. This behavior is
   // consistent with drag/drop on other platforms.
@@ -515,6 +531,14 @@
     DragUpdate(target, event);
   DCHECK(target == drag_window_);
 
+  if (!IsDragDropAllowed(drag_data_.get(), current_drag_info_,
+                         /*is_drop=*/true)) {
+    DragCancel();
+    return;
+  }
+
+  Shell::Get()->cursor_manager()->SetCursor(ui::mojom::CursorType::kPointer);
+
   aura::client::DragDropDelegate* delegate =
       aura::client::GetDragDropDelegate(target);
   if (delegate) {
diff --git a/ash/drag_drop/drag_drop_controller_unittest.cc b/ash/drag_drop/drag_drop_controller_unittest.cc
index 7310734..8e48223 100644
--- a/ash/drag_drop/drag_drop_controller_unittest.cc
+++ b/ash/drag_drop/drag_drop_controller_unittest.cc
@@ -31,6 +31,7 @@
 #include "ui/base/clipboard/clipboard.h"
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
 #include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_policy_controller.h"
 #include "ui/base/dragdrop/drag_drop_types.h"
 #include "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h"
 #include "ui/base/dragdrop/os_exchange_data.h"
@@ -245,7 +246,8 @@
     kNotInvoked,
     kDragEnteredInvoked,
     kDragUpdateInvoked,
-    kPerformDropInvoked
+    kPerformDropInvoked,
+    kDragExitInvoked
   };
 
   explicit EventTargetTestDelegate(aura::Window* window) : window_(window) {}
@@ -267,7 +269,11 @@
         ui::DragDropTypes::DRAG_MOVE,
         ui::DataTransferEndpoint(ui::EndpointType::kDefault));
   }
-  void OnDragExited() override { ADD_FAILURE(); }
+  void OnDragExited() override {
+    EXPECT_TRUE(State::kDragEnteredInvoked == state_ ||
+                State::kDragUpdateInvoked == state_);
+    state_ = State::kDragExitInvoked;
+  }
   int OnPerformDrop(const ui::DropTargetEvent& event,
                     std::unique_ptr<ui::OSExchangeData> data) override {
     EXPECT_EQ(State::kDragUpdateInvoked, state_);
@@ -1474,4 +1480,95 @@
   }
 }
 
+namespace {
+
+class MockDataTransferPolicyController
+    : public ui::DataTransferPolicyController {
+ public:
+  MOCK_METHOD2(IsClipboardReadAllowed,
+               bool(const ui::DataTransferEndpoint* const data_src,
+                    const ui::DataTransferEndpoint* const data_dst));
+  MOCK_METHOD3(IsDragDropAllowed,
+               bool(const ui::DataTransferEndpoint* const data_src,
+                    const ui::DataTransferEndpoint* const data_dst,
+                    const bool is_drop));
+};
+
+}  // namespace
+
+TEST_F(DragDropControllerTest, DlpAllowDragDrop) {
+  std::unique_ptr<aura::Window> window(CreateTestWindowInShellWithDelegate(
+      aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate(), -1,
+      gfx::Rect(0, 0, 100, 100)));
+  EventTargetTestDelegate delegate(window.get());
+  aura::client::SetDragDropDelegate(window.get(), &delegate);
+
+  MockDataTransferPolicyController dlp_contoller;
+
+  // Posted task will be run when the inner loop runs in StartDragAndDrop.
+  ui::test::EventGenerator generator(window->GetRootWindow(), window.get());
+  generator.PressLeftButton();
+
+  auto data(std::make_unique<ui::OSExchangeData>());
+  data->SetString(base::UTF8ToUTF16("I am being dragged"));
+
+  // Drag update.
+  EXPECT_CALL(dlp_contoller, IsDragDropAllowed(_, _, /*is_drop=*/false))
+      .WillOnce(::testing::Return(true));
+  // Drop.
+  EXPECT_CALL(dlp_contoller, IsDragDropAllowed(_, _, /*is_drop=*/true))
+      .WillOnce(::testing::Return(true));
+
+  drag_drop_controller_->StartDragAndDrop(
+      std::move(data), window->GetRootWindow(), window.get(), gfx::Point(5, 5),
+      ui::DragDropTypes::DRAG_MOVE, ui::mojom::DragEventSource::kMouse);
+
+  // For drag enter
+  generator.MoveMouseBy(0, 1);
+  // For drag update
+  generator.MoveMouseBy(0, 1);
+  // For perform drop
+  generator.ReleaseLeftButton();
+
+  EXPECT_EQ(EventTargetTestDelegate::State::kPerformDropInvoked,
+            delegate.state());
+}
+
+TEST_F(DragDropControllerTest, DlpDisallowDragDrop) {
+  std::unique_ptr<aura::Window> window(CreateTestWindowInShellWithDelegate(
+      aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate(), -1,
+      gfx::Rect(0, 0, 100, 100)));
+  EventTargetTestDelegate delegate(window.get());
+  aura::client::SetDragDropDelegate(window.get(), &delegate);
+
+  MockDataTransferPolicyController dlp_contoller;
+
+  // Posted task will be run when the inner loop runs in StartDragAndDrop.
+  ui::test::EventGenerator generator(window->GetRootWindow(), window.get());
+  generator.PressLeftButton();
+
+  auto data(std::make_unique<ui::OSExchangeData>());
+  data->SetString(base::UTF8ToUTF16("I am being dragged"));
+
+  // Drag update.
+  EXPECT_CALL(dlp_contoller, IsDragDropAllowed(_, _, /*is_drop=*/false))
+      .WillOnce(::testing::Return(false));
+  // Drop.
+  EXPECT_CALL(dlp_contoller, IsDragDropAllowed(_, _, /*is_drop=*/true))
+      .WillOnce(::testing::Return(false));
+
+  drag_drop_controller_->StartDragAndDrop(
+      std::move(data), window->GetRootWindow(), window.get(), gfx::Point(5, 5),
+      ui::DragDropTypes::DRAG_MOVE, ui::mojom::DragEventSource::kMouse);
+
+  // For drag enter
+  generator.MoveMouseBy(0, 1);
+  // For drag update
+  generator.MoveMouseBy(0, 1);
+  // For perform drop
+  generator.ReleaseLeftButton();
+
+  EXPECT_EQ(EventTargetTestDelegate::State::kDragExitInvoked, delegate.state());
+}
+
 }  // namespace ash
diff --git a/ash/media/media_controller_impl.cc b/ash/media/media_controller_impl.cc
index 0cd8d9e5..1ef88de 100644
--- a/ash/media/media_controller_impl.cc
+++ b/ash/media/media_controller_impl.cc
@@ -93,9 +93,10 @@
 }
 
 void MediaControllerImpl::NotifyVmMediaNotificationState(bool camera,
-                                                         bool mic) {
+                                                         bool mic,
+                                                         bool camera_and_mic) {
   for (auto& observer : observers_)
-    observer.OnVmMediaNotificationChanged(camera, mic);
+    observer.OnVmMediaNotificationChanged(camera, mic, camera_and_mic);
 }
 
 void MediaControllerImpl::HandleMediaPlayPause() {
diff --git a/ash/media/media_controller_impl.h b/ash/media/media_controller_impl.h
index 22ce112..c280434 100644
--- a/ash/media/media_controller_impl.h
+++ b/ash/media/media_controller_impl.h
@@ -26,8 +26,13 @@
   // Called when media capture state has changed.
   virtual void OnMediaCaptureChanged(
       const base::flat_map<AccountId, MediaCaptureState>& capture_states) {}
-  // Called when a VM's media notifications have changed.
-  virtual void OnVmMediaNotificationChanged(bool camera, bool mic) {}
+  // Called when VMs' media capture notifications change. Each VM can have 0 or
+  // 1 media notification. It can either be a "camera", "mic", or "camera and
+  // mic" notification. Each of the argument is true if a notification of the
+  // corresponding type is active.
+  virtual void OnVmMediaNotificationChanged(bool camera,
+                                            bool mic,
+                                            bool camera_and_mic) {}
 
  protected:
   virtual ~MediaCaptureObserver() {}
@@ -57,7 +62,9 @@
   void SetForceMediaClientKeyHandling(bool enabled) override;
   void NotifyCaptureState(const base::flat_map<AccountId, MediaCaptureState>&
                               capture_states) override;
-  void NotifyVmMediaNotificationState(bool camera, bool mic) override;
+  void NotifyVmMediaNotificationState(bool camera,
+                                      bool mic,
+                                      bool camera_and_mic) override;
 
   // If media session accelerators are enabled then these methods will use the
   // media session service to control playback. Otherwise it will forward to
diff --git a/ash/public/cpp/media_controller.h b/ash/public/cpp/media_controller.h
index 86a47a3..160d57b 100644
--- a/ash/public/cpp/media_controller.h
+++ b/ash/public/cpp/media_controller.h
@@ -41,9 +41,16 @@
   // MediaCaptureState representing every user's state.
   virtual void NotifyCaptureState(
       const base::flat_map<AccountId, MediaCaptureState>& capture_states) = 0;
-  // Called when a VM's media notifications change. There is no `AccountId` in
-  // the argument because only the primary account/profile can launch a VM.
-  virtual void NotifyVmMediaNotificationState(bool camera, bool mic) = 0;
+  // Called when VMs' media capture notifications change. Each VM can have 0 or
+  // 1 media notification. It can either be a "camera", "mic", or "camera and
+  // mic" notification. Each of the argument is true if a notification of the
+  // corresponding type is active.
+  //
+  // There is no `AccountId` in the argument because only the primary
+  // account/profile can launch a VM.
+  virtual void NotifyVmMediaNotificationState(bool camera,
+                                              bool mic,
+                                              bool camera_and_mic) = 0;
 
  protected:
   MediaController();
diff --git a/ash/system/unified/camera_mic_tray_item_view.cc b/ash/system/unified/camera_mic_tray_item_view.cc
index ae713d2..45eaf8a 100644
--- a/ash/system/unified/camera_mic_tray_item_view.cc
+++ b/ash/system/unified/camera_mic_tray_item_view.cc
@@ -59,10 +59,13 @@
 }
 
 void CameraMicTrayItemView::OnVmMediaNotificationChanged(bool camera,
-                                                         bool mic) {
+                                                         bool mic,
+                                                         bool camera_and_mic) {
   switch (type_) {
     case Type::kCamera:
-      active_ = camera;
+      active_ = camera || camera_and_mic;
+      with_mic_ = camera_and_mic;
+      FetchMessage();
       break;
     case Type::kMic:
       active_ = mic;
@@ -110,7 +113,9 @@
 void CameraMicTrayItemView::FetchMessage() {
   switch (type_) {
     case Type::kCamera:
-      message_ = l10n_util::GetStringUTF16(IDS_ASH_CAMERA_MIC_VM_USING_CAMERA);
+      message_ = l10n_util::GetStringUTF16(
+          with_mic_ ? IDS_ASH_CAMERA_MIC_VM_USING_CAMERA_AND_MIC
+                    : IDS_ASH_CAMERA_MIC_VM_USING_CAMERA);
       break;
     case Type::kMic:
       message_ = l10n_util::GetStringUTF16(IDS_ASH_CAMERA_MIC_VM_USING_MIC);
diff --git a/ash/system/unified/camera_mic_tray_item_view.h b/ash/system/unified/camera_mic_tray_item_view.h
index 9cfa9a3..6a66aac5 100644
--- a/ash/system/unified/camera_mic_tray_item_view.h
+++ b/ash/system/unified/camera_mic_tray_item_view.h
@@ -43,7 +43,9 @@
   void HandleLocaleChange() override;
 
   // MediaCaptureObserver:
-  void OnVmMediaNotificationChanged(bool camera, bool mic) override;
+  void OnVmMediaNotificationChanged(bool camera,
+                                    bool mic,
+                                    bool camera_and_mic) override;
 
  private:
   void Update();
@@ -51,6 +53,7 @@
 
   const Type type_;
   bool active_ = false;
+  bool with_mic_ = false;  // Only for `type_ == kCamera`.
   bool is_primary_session_ = false;
   base::string16 message_;
 };
diff --git a/ash/system/unified/camera_mic_tray_item_view_unittest.cc b/ash/system/unified/camera_mic_tray_item_view_unittest.cc
index c68de5e..eec6fb2 100644
--- a/ash/system/unified/camera_mic_tray_item_view_unittest.cc
+++ b/ash/system/unified/camera_mic_tray_item_view_unittest.cc
@@ -8,10 +8,12 @@
 #include <utility>
 
 #include "ash/public/cpp/media_controller.h"
+#include "ash/strings/grit/ash_strings.h"
 #include "ash/test/ash_test_base.h"
 #include "base/test/scoped_feature_list.h"
 #include "chromeos/constants/chromeos_features.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/l10n/l10n_util.h"
 
 namespace ash {
 
@@ -19,17 +21,15 @@
 using Type = CameraMicTrayItemView::Type;
 }  // namespace
 
-class CameraMicTrayItemViewTest : public AshTestBase,
-                                  public testing::WithParamInterface<Type> {
+class BaseCameraMicTrayItemViewTest : public AshTestBase {
  public:
-  // AshTestBase:
-  void SetUp() override {
+  void SetUpWithType(Type type) {
     scoped_feature_list_.InitAndEnableFeature(
         chromeos::features::kVmCameraMicIndicatorsAndNotifications);
     AshTestBase::SetUp();
 
     camera_mic_tray_item_view_ =
-        std::make_unique<CameraMicTrayItemView>(GetPrimaryShelf(), GetParam());
+        std::make_unique<CameraMicTrayItemView>(GetPrimaryShelf(), type);
 
     // Relogin to make sure `OnActiveUserSessionChanged` is triggered.
     ClearLogin();
@@ -46,30 +46,59 @@
   std::unique_ptr<CameraMicTrayItemView> camera_mic_tray_item_view_;
 };
 
-TEST_P(CameraMicTrayItemViewTest, OnVmMediaNotificationChanged) {
+class CameraMicTrayItemViewTest : public BaseCameraMicTrayItemViewTest,
+                                  public testing::WithParamInterface<Type> {
+ public:
+  // AshTestBase:
+  void SetUp() override { SetUpWithType(GetParam()); }
+};
+
+TEST_P(CameraMicTrayItemViewTest, GetVisible) {
   Type type = GetParam();
   EXPECT_FALSE(camera_mic_tray_item_view_->GetVisible());
 
-  camera_mic_tray_item_view_->OnVmMediaNotificationChanged(/*camera=*/true,
-                                                           /*mic=*/false);
+  camera_mic_tray_item_view_->OnVmMediaNotificationChanged(
+      /*camera=*/true,
+      /*mic=*/false,
+      /*camera_and_mic=*/false);
   EXPECT_EQ(camera_mic_tray_item_view_->GetVisible(), type == Type::kCamera);
 
-  camera_mic_tray_item_view_->OnVmMediaNotificationChanged(/*camera=*/false,
-                                                           /*mic=*/true);
+  camera_mic_tray_item_view_->OnVmMediaNotificationChanged(
+      /*camera=*/false,
+      /*mic=*/false,
+      /*camera_and_mic=*/true);
+  EXPECT_EQ(camera_mic_tray_item_view_->GetVisible(), type == Type::kCamera);
+
+  camera_mic_tray_item_view_->OnVmMediaNotificationChanged(
+      /*camera=*/false,
+      /*mic=*/true,
+      /*camera_and_mic=*/false);
   EXPECT_EQ(camera_mic_tray_item_view_->GetVisible(), type == Type::kMic);
 
-  camera_mic_tray_item_view_->OnVmMediaNotificationChanged(/*camera=*/true,
-                                                           /*mic=*/true);
+  camera_mic_tray_item_view_->OnVmMediaNotificationChanged(
+      /*camera=*/true,
+      /*mic=*/true,
+      /*camera_and_mic=*/false);
   EXPECT_TRUE(camera_mic_tray_item_view_->GetVisible());
 
-  camera_mic_tray_item_view_->OnVmMediaNotificationChanged(/*camera=*/false,
-                                                           /*mic=*/false);
+  camera_mic_tray_item_view_->OnVmMediaNotificationChanged(
+      /*camera=*/true,
+      /*mic=*/true,
+      /*camera_and_mic=*/true);
+  EXPECT_TRUE(camera_mic_tray_item_view_->GetVisible());
+
+  camera_mic_tray_item_view_->OnVmMediaNotificationChanged(
+      /*camera=*/false,
+      /*mic=*/false,
+      /*camera_and_mic=*/false);
   EXPECT_FALSE(camera_mic_tray_item_view_->GetVisible());
 }
 
 TEST_P(CameraMicTrayItemViewTest, HideForNonPrimaryUser) {
-  camera_mic_tray_item_view_->OnVmMediaNotificationChanged(/*camera=*/true,
-                                                           /*mic=*/true);
+  camera_mic_tray_item_view_->OnVmMediaNotificationChanged(
+      /*camera=*/true,
+      /*mic=*/true,
+      /*camera_and_mic=*/true);
   EXPECT_TRUE(camera_mic_tray_item_view_->GetVisible());
 
   SimulateUserLogin("user2@test.com");
@@ -80,4 +109,36 @@
                          CameraMicTrayItemViewTest,
                          testing::Values(Type::kCamera, Type::kMic));
 
+// For testing that the camera tray item switch the message depending on whether
+// the "camera and mic" notification is active.
+class CameraMicTrayItemViewMessageTest : public BaseCameraMicTrayItemViewTest {
+  // AshTestBase:
+  void SetUp() override { SetUpWithType(Type::kCamera); }
+};
+
+TEST_F(CameraMicTrayItemViewMessageTest, Message) {
+  camera_mic_tray_item_view_->OnVmMediaNotificationChanged(
+      /*camera=*/true,
+      /*mic=*/false,
+      /*camera_and_mic=*/false);
+  EXPECT_EQ(camera_mic_tray_item_view_->GetAccessibleNameString(),
+            l10n_util::GetStringUTF16(IDS_ASH_CAMERA_MIC_VM_USING_CAMERA));
+
+  camera_mic_tray_item_view_->OnVmMediaNotificationChanged(
+      /*camera=*/false,
+      /*mic=*/false,
+      /*camera_and_mic=*/true);
+  EXPECT_EQ(
+      camera_mic_tray_item_view_->GetAccessibleNameString(),
+      l10n_util::GetStringUTF16(IDS_ASH_CAMERA_MIC_VM_USING_CAMERA_AND_MIC));
+
+  camera_mic_tray_item_view_->OnVmMediaNotificationChanged(
+      /*camera=*/true,
+      /*mic=*/false,
+      /*camera_and_mic=*/true);
+  EXPECT_EQ(
+      camera_mic_tray_item_view_->GetAccessibleNameString(),
+      l10n_util::GetStringUTF16(IDS_ASH_CAMERA_MIC_VM_USING_CAMERA_AND_MIC));
+}
+
 }  // namespace ash
diff --git a/base/allocator/partition_allocator/partition_root.h b/base/allocator/partition_allocator/partition_root.h
index 51192dd..c594eb0 100644
--- a/base/allocator/partition_allocator/partition_root.h
+++ b/base/allocator/partition_allocator/partition_root.h
@@ -325,7 +325,11 @@
   }
 
   bool UsesGigaCage() const {
-    return features::IsPartitionAllocGigaCageEnabled() && allow_ref_count;
+    return features::IsPartitionAllocGigaCageEnabled()
+#if ENABLE_REF_COUNT_FOR_BACKUP_REF_PTR
+           && allow_ref_count
+#endif
+        ;
   }
 
   ALWAYS_INLINE bool IsScannable() const {
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 5ea2f21..5928c56 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -627,9 +627,6 @@
         # Experimentally determined to yield a reasonable trade-off between
         # build time, run-time performance, and binary size.
         "-mllvm:-import-instr-limit=10",
-
-        # TODO(https://crbug.com/1127713): Investigate, remove.
-        "-mllvm:-enable-dse-memoryssa=false",
       ]
     } else {
       ldflags += [ "-flto=thin" ]
diff --git a/cc/metrics/compositor_frame_reporting_controller.cc b/cc/metrics/compositor_frame_reporting_controller.cc
index d2cbf4a..2ff29e6 100644
--- a/cc/metrics/compositor_frame_reporting_controller.cc
+++ b/cc/metrics/compositor_frame_reporting_controller.cc
@@ -78,9 +78,18 @@
   if (reporters_[PipelineStage::kBeginImplFrame]) {
     auto& reporter = reporters_[PipelineStage::kBeginImplFrame];
     DCHECK(reporter->did_finish_impl_frame());
-    DCHECK(reporter->did_not_produce_frame());
-    reporter->TerminateFrame(FrameTerminationStatus::kDidNotProduceFrame,
-                             reporter->did_not_produce_frame_time());
+    // TODO(1144353): This is a speculative fix. This code should only be
+    // reached after the previous frame have been explicitly marked as 'did not
+    // produce frame', i.e. this code should have a DCHECK instead of a
+    // conditional:
+    //   DCHECK(reporter->did_not_produce_frame()).
+    if (reporter->did_not_produce_frame()) {
+      reporter->TerminateFrame(FrameTerminationStatus::kDidNotProduceFrame,
+                               reporter->did_not_produce_frame_time());
+    } else {
+      reporter->TerminateFrame(FrameTerminationStatus::kReplacedByNewReporter,
+                               Now());
+    }
   }
   auto reporter = std::make_unique<CompositorFrameReporter>(
       active_trackers_, args, latency_ukm_reporter_.get(),
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index 317e970..5eeb0d0c 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -1105,6 +1105,8 @@
       "$root_out_dir/$chrome_product_full_name.app/Contents/MacOS/$chrome_product_full_name",
       "$root_out_dir/AlertNotificationService.xpc/Contents/MacOS/AlertNotificationService",
       "$root_out_dir/chrome_crashpad_handler",
+      "$root_out_dir/libEGL.dylib",
+      "$root_out_dir/libGLESv2.dylib",
       "$root_out_dir/libswiftshader_libEGL.dylib",
       "$root_out_dir/libswiftshader_libGLESv2.dylib",
       _framework_binary_path,
@@ -1137,6 +1139,8 @@
         ":chrome_framework",
         "//chrome/browser/ui/cocoa/notifications:alert_notification_xpc_service",
         "//components/crash/core/app:chrome_crashpad_handler",
+        "//third_party/angle:libEGL",
+        "//third_party/angle:libGLESv2",
         "//third_party/breakpad:dump_syms",
         "//third_party/swiftshader/src/OpenGL/libEGL:swiftshader_libEGL",
         "//third_party/swiftshader/src/OpenGL/libGLESv2:swiftshader_libGLESv2",
@@ -1159,6 +1163,8 @@
         "$root_out_dir/$chrome_framework_name.dSYM",
         "$root_out_dir/$chrome_product_full_name.dSYM",
         "$root_out_dir/chrome_crashpad_handler.dSYM",
+        "$root_out_dir/libEGL.dylib.dSYM",
+        "$root_out_dir/libGLESv2.dylib.dSYM",
         "$root_out_dir/libswiftshader_libEGL.dylib.dSYM",
         "$root_out_dir/libswiftshader_libGLESv2.dylib.dSYM",
       ]
@@ -1168,6 +1174,8 @@
         ":chrome_framework",
         "//chrome/browser/ui/cocoa/notifications:alert_notification_xpc_service",
         "//components/crash/core/app:chrome_crashpad_handler",
+        "//third_party/angle:libEGL",
+        "//third_party/angle:libGLESv2",
         "//third_party/swiftshader/src/OpenGL/libEGL:swiftshader_libEGL",
         "//third_party/swiftshader/src/OpenGL/libGLESv2:swiftshader_libGLESv2",
       ]
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 228d878..2e204a7 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -194,7 +194,6 @@
     "//chrome/android/webapk/libs/common:splash_resources",
     "//chrome/app:java_strings_grd",
     "//chrome/browser/feedback/android:java_resources",
-    "//chrome/browser/incognito/interstitial/android:java_resources",
     "//chrome/browser/password_check/android:java_resources",
     "//chrome/browser/signin/services/android:java_resources",
     "//chrome/browser/signin/ui/android:java_resources",
@@ -318,7 +317,6 @@
     "//chrome/browser/image_descriptions:java",
     "//chrome/browser/image_editor/public:java",
     "//chrome/browser/image_fetcher:java",
-    "//chrome/browser/incognito/interstitial/android:java",
     "//chrome/browser/metrics_settings/android:java",
     "//chrome/browser/notifications/chime/android:java",
     "//chrome/browser/offline_pages/android:java",
diff --git a/chrome/android/chrome_java_resources.gni b/chrome/android/chrome_java_resources.gni
index 1a1ec57..ef945c4 100644
--- a/chrome/android/chrome_java_resources.gni
+++ b/chrome/android/chrome_java_resources.gni
@@ -632,7 +632,6 @@
   "java/res/drawable/ic_error.xml",
   "java/res/drawable/ic_error_googred_36dp.xml",
   "java/res/drawable/ic_event_round.xml",
-  "java/res/drawable/ic_expand_more_in_circle_24dp.xml",
   "java/res/drawable/ic_file_download_scheduled_24dp.xml",
   "java/res/drawable/ic_find_in_page.xml",
   "java/res/drawable/ic_fingerprint_grey500_36dp.xml",
@@ -727,15 +726,6 @@
   "java/res/layout/account_chooser_dialog_title.xml",
   "java/res/layout/account_divider_preference.xml",
   "java/res/layout/account_management_account_row.xml",
-  "java/res/layout/account_picker_bottom_sheet_continue_button.xml",
-  "java/res/layout/account_picker_bottom_sheet_header.xml",
-  "java/res/layout/account_picker_bottom_sheet_view.xml",
-  "java/res/layout/account_picker_state_auth_error.xml",
-  "java/res/layout/account_picker_state_collapsed.xml",
-  "java/res/layout/account_picker_state_expanded.xml",
-  "java/res/layout/account_picker_state_general_error.xml",
-  "java/res/layout/account_picker_state_no_account.xml",
-  "java/res/layout/account_picker_state_signin_in_progress.xml",
   "java/res/layout/add_languages_main.xml",
   "java/res/layout/add_to_homescreen_dialog.xml",
   "java/res/layout/add_to_menu_dialog.xml",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 78afbdf..7c06a37 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -236,6 +236,7 @@
   "java/src/org/chromium/chrome/browser/browserservices/ui/view/DisclosureNotification.java",
   "java/src/org/chromium/chrome/browser/browserservices/ui/view/DisclosureSnackbar.java",
   "java/src/org/chromium/chrome/browser/browserservices/verification/OriginVerifier.java",
+  "java/src/org/chromium/chrome/browser/browserservices/verification/OriginVerifierStatics.java",
   "java/src/org/chromium/chrome/browser/browserservices/verification/Relationship.java",
   "java/src/org/chromium/chrome/browser/browserservices/verification/VerificationResultStore.java",
   "java/src/org/chromium/chrome/browser/browsing_data/BrowsingDataBridge.java",
@@ -1248,11 +1249,6 @@
   "java/src/org/chromium/chrome/browser/signin/SigninPromoUtil.java",
   "java/src/org/chromium/chrome/browser/signin/SigninUtils.java",
   "java/src/org/chromium/chrome/browser/signin/SyncPromoView.java",
-  "java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetCoordinator.java",
-  "java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetMediator.java",
-  "java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetProperties.java",
-  "java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetView.java",
-  "java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetViewBinder.java",
   "java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerDelegateImpl.java",
   "java/src/org/chromium/chrome/browser/site_settings/ChromeSiteSettingsDelegate.java",
   "java/src/org/chromium/chrome/browser/site_settings/CookieControlsServiceBridge.java",
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantBottomsheetTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantBottomsheetTest.java
index 4fc8276..510a15c 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantBottomsheetTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantBottomsheetTest.java
@@ -37,6 +37,7 @@
 import static org.chromium.chrome.browser.autofill_assistant.proto.ConfigureBottomSheetProto.ViewportResizing.RESIZE_VISUAL_VIEWPORT;
 
 import android.graphics.Rect;
+import android.os.Build.VERSION_CODES;
 
 import androidx.test.espresso.Espresso;
 import androidx.test.espresso.ViewAction;
@@ -55,6 +56,7 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Criteria;
 import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.chrome.autofill_assistant.R;
 import org.chromium.chrome.browser.autofill_assistant.proto.ActionProto;
@@ -239,7 +241,10 @@
 
     @Test
     @MediumTest
-    public void testHandleHeader() {
+    @DisableIf.Build(message = "Flaky on Android P, see https://crbug.com/1166168",
+            sdk_is_greater_than = VERSION_CODES.O_MR1, sdk_is_less_than = VERSION_CODES.Q)
+    public void
+    testHandleHeader() {
         AutofillAssistantTestService testService = new AutofillAssistantTestService(
                 Collections.singletonList(makeScript(RESIZE_LAYOUT_VIEWPORT, HANDLE_HEADER, true)));
         startAutofillAssistant(mTestRule.getActivity(), testService);
@@ -261,7 +266,10 @@
 
     @Test
     @MediumTest
-    public void testHandleHeaderCarousels() {
+    @DisableIf.Build(message = "Flaky on Android P, see https://crbug.com/1166168",
+            sdk_is_greater_than = VERSION_CODES.O_MR1, sdk_is_less_than = VERSION_CODES.Q)
+    public void
+    testHandleHeaderCarousels() {
         AutofillAssistantTestService testService =
                 new AutofillAssistantTestService(Collections.singletonList(
                         makeScript(RESIZE_LAYOUT_VIEWPORT, HANDLE_HEADER_CAROUSELS, true)));
diff --git a/chrome/android/java/DEPS b/chrome/android/java/DEPS
index f6f7503..e41acfa 100644
--- a/chrome/android/java/DEPS
+++ b/chrome/android/java/DEPS
@@ -5,6 +5,7 @@
   "+chrome/browser/banners/android/java",
   "+chrome/browser/device",
   "+chrome/browser/privacy",
+  "+chrome/browser/privacy_sandbox",
   "+chrome/browser/profiles/android/java",
   "+chrome/browser/share/android",
   "+chrome/browser/tab",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/verification/OriginVerifierStatics.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/verification/OriginVerifierStatics.java
new file mode 100644
index 0000000..e30397d
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/verification/OriginVerifierStatics.java
@@ -0,0 +1,30 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.browserservices.verification;
+
+import org.chromium.components.embedder_support.util.Origin;
+
+import androidx.annotation.VisibleForTesting;
+
+/**
+ * Adds a layer of indirection to calls to static methods on {@link OriginVerifier}. This allows us
+ * to modify that class a bit more freely without having to worry about downstream relying on its
+ * static methods.
+ *
+ * This should be temporary, see https://crbug.com/1164866
+ */
+class OriginVerifierStatics {
+    /** Calls {@link OriginVerifier#clearCachedVerificationsForTesting}. */
+    @VisibleForTesting
+    public static void clearCachedVerificationsForTesting() {
+        OriginVerifier.clearCachedVerificationsForTesting();
+    }
+
+    /** Calls {@link OriginVerifier#addVerificationOverride}. */
+    public static void addVerificationOverride(
+            String packageName, Origin origin, int relationship) {
+        OriginVerifier.addVerificationOverride(packageName, origin, relationship);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
index ca2f6cb..103b16c6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
@@ -127,6 +127,9 @@
     private static final Object SNAPSHOT_DATABASE_LOCK = new Object();
     private static final String SNAPSHOT_DATABASE_NAME = "snapshots.db";
 
+    // The feature param for determining whether the PhotoPicker should animate thumbnails.
+    private static final String FEATURE_PARAM_ANIMATE_THUMBNAILS = "animate_thumbnails";
+
     private static ProcessInitializationHandler sInstance;
 
     private boolean mInitializedPreNative;
@@ -223,32 +226,31 @@
         ChromeLifetimeController.initialize();
         Clipboard.getInstance().setImageFileProvider(new ClipboardImageFileProvider());
 
-        if (ChromeFeatureList.isEnabled(ChromeFeatureList.NEW_PHOTO_PICKER)) {
-            DecoderServiceHost.setIntentSupplier(() -> {
-                return new Intent(ContextUtils.getApplicationContext(), DecoderService.class);
-            });
+        DecoderServiceHost.setIntentSupplier(() -> {
+            return new Intent(ContextUtils.getApplicationContext(), DecoderService.class);
+        });
 
-            SelectFileDialog.setPhotoPickerDelegate(new PhotoPickerDelegate() {
-                @Override
-                public PhotoPicker showPhotoPicker(WindowAndroid windowAndroid,
-                        PhotoPickerListener listener, boolean allowMultiple,
-                        List<String> mimeTypes) {
-                    PhotoPickerDialog dialog = new PhotoPickerDialog(windowAndroid,
-                            windowAndroid.getContext().get().getContentResolver(), listener,
-                            allowMultiple, mimeTypes);
-                    dialog.getWindow().getAttributes().windowAnimations =
-                            R.style.PickerDialogAnimation;
-                    dialog.show();
-                    return dialog;
-                }
+        SelectFileDialog.setPhotoPickerDelegate(new PhotoPickerDelegate() {
+            @Override
+            public PhotoPicker showPhotoPicker(WindowAndroid windowAndroid,
+                    PhotoPickerListener listener, boolean allowMultiple, List<String> mimeTypes) {
+                PhotoPickerDialog dialog = new PhotoPickerDialog(windowAndroid,
+                        windowAndroid.getContext().get().getContentResolver(), listener,
+                        allowMultiple,
+                        ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean(
+                                ChromeFeatureList.PHOTO_PICKER_VIDEO_SUPPORT,
+                                FEATURE_PARAM_ANIMATE_THUMBNAILS, false),
+                        mimeTypes);
+                dialog.getWindow().getAttributes().windowAnimations = R.style.PickerDialogAnimation;
+                dialog.show();
+                return dialog;
+            }
 
-                @Override
-                public boolean supportsVideos() {
-                    return ChromeFeatureList.isEnabled(
-                            ChromeFeatureList.PHOTO_PICKER_VIDEO_SUPPORT);
-                }
-            });
-        }
+            @Override
+            public boolean supportsVideos() {
+                return ChromeFeatureList.isEnabled(ChromeFeatureList.PHOTO_PICKER_VIDEO_SUPPORT);
+            }
+        });
 
         ContactsPicker.setContactsPickerDelegate(
                 (WindowAndroid windowAndroid, ContactsPickerListener listener,
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 a13690e..1ffc7c4 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
@@ -46,6 +46,8 @@
 import org.chromium.chrome.browser.safety_check.SafetyCheckUpdatesDelegateImpl;
 import org.chromium.chrome.browser.signin.SigninActivityLauncherImpl;
 import org.chromium.chrome.browser.site_settings.ChromeSiteSettingsDelegate;
+import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
+import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager.SnackbarManageable;
 import org.chromium.components.browser_ui.settings.FragmentSettingsLauncher;
 import org.chromium.components.browser_ui.settings.SettingsLauncher;
 import org.chromium.components.browser_ui.settings.SettingsUtils;
@@ -68,7 +70,7 @@
  *    {@link SettingsUtils#getShowShadowOnScrollListener(View, View)}.
  */
 public class SettingsActivity extends ChromeBaseAppCompatActivity
-        implements PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
+        implements PreferenceFragmentCompat.OnPreferenceStartFragmentCallback, SnackbarManageable {
     /**
      * Preference fragments may implement this interface to intercept "Back" button taps in this
      * activity.
@@ -96,6 +98,8 @@
     /** An instance of settings launcher that can be injected into a fragment */
     private SettingsLauncher mSettingsLauncher = new SettingsLauncherImpl();
 
+    private SnackbarManager mSnackbarManager;
+
     @SuppressLint("InlinedApi")
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -165,9 +169,18 @@
     @Override
     public void onAttachedToWindow() {
         super.onAttachedToWindow();
+        ViewGroup contentView = findViewById(android.R.id.content);
+        mSnackbarManager = new SnackbarManager(this, contentView, null);
 
         Fragment fragment = getMainFragment();
 
+        if (fragment instanceof SiteSettingsPreferenceFragment) {
+            ChromeSiteSettingsDelegate delegate =
+                    (ChromeSiteSettingsDelegate) (((SiteSettingsPreferenceFragment) fragment)
+                                                          .getSiteSettingsDelegate());
+            delegate.setSnackbarManager(mSnackbarManager);
+        }
+
         ViewGroup listView = null;
         if (fragment instanceof PreferenceFragmentCompat) {
             listView = ((PreferenceFragmentCompat) fragment).getListView();
@@ -178,8 +191,8 @@
         if (listView == null) return;
 
         // Append action bar shadow to layout.
-        View inflatedView = getLayoutInflater().inflate(
-                R.layout.settings_action_bar_shadow, findViewById(android.R.id.content));
+        View inflatedView =
+                getLayoutInflater().inflate(R.layout.settings_action_bar_shadow, contentView);
 
         // Display shadow on scroll.
         listView.getViewTreeObserver().addOnScrollChangedListener(
@@ -331,6 +344,11 @@
         }
     }
 
+    @Override
+    public SnackbarManager getSnackbarManager() {
+        return mSnackbarManager;
+    }
+
     private void ensureActivityNotExported() {
         if (sActivityNotExportedChecked) return;
         sActivityNotExportedChecked = true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sharing/SharingServiceProxy.java b/chrome/android/java/src/org/chromium/chrome/browser/sharing/SharingServiceProxy.java
index 9e1f9a9..668c88a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sharing/SharingServiceProxy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sharing/SharingServiceProxy.java
@@ -57,20 +57,17 @@
      * Sends a shared clipboard message to the device specified by GUID.
      * @param guid The guid of the receiver device.
      * @param text The text to send.
-     * @param retries The number of retries so far.
      * @param callback The result of the operation. Runs |callback| with a
      *         org.chromium.chrome.browser.sharing.SharingSendMessageResult enum value.
      */
-    public void sendSharedClipboardMessage(
-            String guid, String text, int retries, Callback<Integer> callback) {
+    public void sendSharedClipboardMessage(String guid, String text, Callback<Integer> callback) {
         if (sNativeSharingServiceProxyAndroid == 0) {
             callback.onResult(SharingSendMessageResult.INTERNAL_ERROR);
             return;
         }
 
         Natives jni = SharingServiceProxyJni.get();
-        jni.sendSharedClipboardMessage(
-                sNativeSharingServiceProxyAndroid, guid, text, retries, callback);
+        jni.sendSharedClipboardMessage(sNativeSharingServiceProxyAndroid, guid, text, callback);
     }
 
     /**
@@ -131,7 +128,7 @@
     interface Natives {
         void initSharingService(Profile profile);
         void sendSharedClipboardMessage(long nativeSharingServiceProxyAndroid, String guid,
-                String text, int retries, Callback<Integer> callback);
+                String text, Callback<Integer> callback);
         void getDeviceCandidates(long nativeSharingServiceProxyAndroid,
                 ArrayList<DeviceInfo> deviceInfo, int requiredFeature);
         void addDeviceCandidatesInitializedObserver(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sharing/shared_clipboard/SharedClipboardMessageHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/sharing/shared_clipboard/SharedClipboardMessageHandler.java
index 3ea75c3..2be6986e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sharing/shared_clipboard/SharedClipboardMessageHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sharing/shared_clipboard/SharedClipboardMessageHandler.java
@@ -30,7 +30,6 @@
     private static final String EXTRA_DEVICE_GUID = "SharedClipboard.EXTRA_DEVICE_GUID";
     private static final String EXTRA_DEVICE_CLIENT_NAME =
             "SharedClipboard.EXTRA_DEVICE_CLIENT_NAME";
-    private static final String EXTRA_RETRIES = "SharedClipboard.EXTRA_RETRIES";
 
     /**
      * Handles the tapping of an incoming notification when text is shared with current device.
@@ -54,9 +53,8 @@
             String guid = IntentUtils.safeGetStringExtra(intent, EXTRA_DEVICE_GUID);
             String name = IntentUtils.safeGetStringExtra(intent, EXTRA_DEVICE_CLIENT_NAME);
             String text = IntentUtils.safeGetStringExtra(intent, Intent.EXTRA_TEXT);
-            int retries = IntentUtils.safeGetIntExtra(intent, EXTRA_RETRIES, /*defaultValue=*/1);
 
-            showSendingNotification(guid, name, text, retries);
+            showSendingNotification(guid, name, text);
         }
     }
 
@@ -67,9 +65,8 @@
      * @param guid The guid of the receiver device.
      * @param name The name of the receiver device.
      * @param text The text shared from the sender device.
-     * @param retries The number of retries so far.
      */
-    public static void showSendingNotification(String guid, String name, String text, int retries) {
+    public static void showSendingNotification(String guid, String name, String text) {
         if (TextUtils.isEmpty(guid) || TextUtils.isEmpty(name) || TextUtils.isEmpty(text)) {
             return;
         }
@@ -88,7 +85,7 @@
         // TODO(crbug.com/1015411): Wait for device info in a more central place.
         SharingServiceProxy.getInstance().addDeviceCandidatesInitializedObserver(() -> {
             SharingServiceProxy.getInstance().sendSharedClipboardMessage(
-                    guid, text, retries, result -> {
+                    guid, text, result -> {
                         if (result == SharingSendMessageResult.SUCCESSFUL) {
                             SharingNotificationUtil.dismissNotification(
                                     NotificationConstants.GROUP_SHARED_CLIPBOARD,
@@ -107,8 +104,7 @@
                                         new Intent(context, TryAgainReceiver.class)
                                                 .putExtra(Intent.EXTRA_TEXT, text)
                                                 .putExtra(EXTRA_DEVICE_GUID, guid)
-                                                .putExtra(EXTRA_DEVICE_CLIENT_NAME, name)
-                                                .putExtra(EXTRA_RETRIES, retries + 1),
+                                                .putExtra(EXTRA_DEVICE_CLIENT_NAME, name),
                                         PendingIntent.FLAG_UPDATE_CURRENT);
                             }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sharing/shared_clipboard/SharedClipboardShareActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/sharing/shared_clipboard/SharedClipboardShareActivity.java
index 5cc9539..0e26847 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sharing/shared_clipboard/SharedClipboardShareActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sharing/shared_clipboard/SharedClipboardShareActivity.java
@@ -131,8 +131,7 @@
         SharedClipboardMetrics.recordDeviceClick(position);
         SharedClipboardMetrics.recordTextSize(text != null ? text.length() : 0);
 
-        SharedClipboardMessageHandler.showSendingNotification(
-                device.guid, device.clientName, text, /*retries=*/0);
+        SharedClipboardMessageHandler.showSendingNotification(device.guid, device.clientName, text);
         finish();
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninUtils.java
index d08e5bf..d6da252 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninUtils.java
@@ -19,12 +19,12 @@
 import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.feedback.HelpAndFeedbackLauncherImpl;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.signin.account_picker.AccountPickerBottomSheetCoordinator;
 import org.chromium.chrome.browser.signin.account_picker.AccountPickerDelegateImpl;
 import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
 import org.chromium.chrome.browser.signin.services.SigninManager;
 import org.chromium.chrome.browser.signin.services.SigninMetricsUtils;
 import org.chromium.chrome.browser.signin.services.WebSigninBridge;
+import org.chromium.chrome.browser.signin.ui.account_picker.AccountPickerBottomSheetCoordinator;
 import org.chromium.chrome.browser.sync.settings.AccountManagementFragment;
 import org.chromium.chrome.browser.tabmodel.TabCreator;
 import org.chromium.chrome.browser.tabmodel.TabModel;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/site_settings/ChromeSiteSettingsDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/site_settings/ChromeSiteSettingsDelegate.java
index f93eec5..e931dd0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/site_settings/ChromeSiteSettingsDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/site_settings/ChromeSiteSettingsDelegate.java
@@ -19,10 +19,13 @@
 import org.chromium.chrome.browser.feedback.HelpAndFeedbackLauncherImpl;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.notifications.channels.SiteChannelsManager;
+import org.chromium.chrome.browser.privacy_sandbox.PrivacySandboxSnackbarController;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.settings.ChromeManagedPreferenceDelegate;
+import org.chromium.chrome.browser.settings.SettingsLauncherImpl;
 import org.chromium.chrome.browser.ui.favicon.FaviconHelper;
 import org.chromium.chrome.browser.ui.favicon.FaviconHelper.FaviconImageCallback;
+import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
 import org.chromium.chrome.browser.webapps.WebappRegistry;
 import org.chromium.components.browser_ui.settings.ManagedPreferenceDelegate;
 import org.chromium.components.browser_ui.site_settings.SiteSettingsCategory;
@@ -52,12 +55,23 @@
     private final Context mContext;
     private final BrowserContextHandle mBrowserContext;
     private ManagedPreferenceDelegate mManagedPreferenceDelegate;
+    private PrivacySandboxSnackbarController mPrivacySandboxController;
 
     public ChromeSiteSettingsDelegate(Context context, BrowserContextHandle browserContext) {
         mContext = context;
         mBrowserContext = browserContext;
     }
 
+    /**
+     * Used to set an instance of {@link SnackbarManager} by the parent activity.
+     */
+    public void setSnackbarManager(SnackbarManager manager) {
+        if (manager != null) {
+            mPrivacySandboxController = new PrivacySandboxSnackbarController(
+                    mContext, manager, new SettingsLauncherImpl());
+        }
+    }
+
     @Override
     public BrowserContextHandle getBrowserContextHandle() {
         return mBrowserContext;
@@ -220,4 +234,22 @@
     public Set<String> getAllDelegatedNotificationOrigins() {
         return TrustedWebActivityPermissionManager.get().getAllDelegatedOrigins();
     }
+
+    @Override
+    public void maybeDisplayPrivacySandboxSnackbar() {
+        if (mPrivacySandboxController == null
+                || !ChromeFeatureList.isEnabled(ChromeFeatureList.PRIVACY_SANDBOX_SETTINGS)) {
+            return;
+        }
+        mPrivacySandboxController.showSnackbar();
+    }
+
+    @Override
+    public void dismissPrivacySandboxSnackbar() {
+        if (mPrivacySandboxController == null
+                || !ChromeFeatureList.isEnabled(ChromeFeatureList.PRIVACY_SANDBOX_SETTINGS)) {
+            return;
+        }
+        mPrivacySandboxController.dismissSnackbar();
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/AccountManagementFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/AccountManagementFragment.java
index e9e794f..8d1b68f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/AccountManagementFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/AccountManagementFragment.java
@@ -204,30 +204,27 @@
             }
             signOutPreference.setTitle(getSignOutPreferenceText());
             signOutPreference.setOnPreferenceClickListener(preference -> {
-                if (!isVisible() || !isResumed()) return false;
-
-                if (mSignedInAccountName != null) {
-                    SigninMetricsUtils.logProfileAccountManagementMenu(
-                            ProfileAccountManagementMetrics.TOGGLE_SIGNOUT, mGaiaServiceType);
-
-                    if (IdentityServicesProvider.get()
-                                    .getIdentityManager(Profile.getLastUsedRegularProfile())
-                                    .getPrimaryAccountInfo(ConsentLevel.SYNC)
-                            != null) {
-                        // Only show the sign-out dialog if the user has given sync consent.
-                        SignOutDialogFragment signOutFragment =
-                                SignOutDialogFragment.create(mGaiaServiceType);
-                        signOutFragment.setTargetFragment(AccountManagementFragment.this, 0);
-                        signOutFragment.show(getFragmentManager(), SIGN_OUT_DIALOG_TAG);
-                    } else {
-                        IdentityServicesProvider.get()
-                                .getSigninManager(Profile.getLastUsedRegularProfile())
-                                .signOut(SignoutReason.USER_CLICKED_SIGNOUT_SETTINGS, null, false);
-                    }
-                    return true;
+                if (!isVisible() || !isResumed() || mSignedInAccountName == null) {
+                    return false;
                 }
+                SigninMetricsUtils.logProfileAccountManagementMenu(
+                        ProfileAccountManagementMetrics.TOGGLE_SIGNOUT, mGaiaServiceType);
 
-                return false;
+                if (IdentityServicesProvider.get()
+                                .getIdentityManager(Profile.getLastUsedRegularProfile())
+                                .getPrimaryAccountInfo(ConsentLevel.SYNC)
+                        != null) {
+                    // Only show the sign-out dialog if the user has given sync consent.
+                    SignOutDialogFragment signOutFragment =
+                            SignOutDialogFragment.create(mGaiaServiceType);
+                    signOutFragment.setTargetFragment(AccountManagementFragment.this, 0);
+                    signOutFragment.show(getFragmentManager(), SIGN_OUT_DIALOG_TAG);
+                } else {
+                    IdentityServicesProvider.get()
+                            .getSigninManager(Profile.getLastUsedRegularProfile())
+                            .signOut(SignoutReason.USER_CLICKED_SIGNOUT_SETTINGS, null, false);
+                }
+                return true;
             });
         }
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetRenderTest.java
index a7111eb..c2ad939 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetRenderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetRenderTest.java
@@ -42,7 +42,7 @@
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.incognito.interstitial.IncognitoInterstitialDelegate;
 import org.chromium.chrome.browser.night_mode.ChromeNightModeTestUtils;
-import org.chromium.chrome.browser.signin.account_picker.AccountPickerBottomSheetCoordinator;
+import org.chromium.chrome.browser.signin.ui.account_picker.AccountPickerBottomSheetCoordinator;
 import org.chromium.chrome.browser.signin.ui.account_picker.AccountPickerDelegate;
 import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetTest.java
index bc8c081..2ca3d1a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetTest.java
@@ -49,14 +49,14 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.MetricsUtils.HistogramDelta;
-import org.chromium.chrome.R;
 import org.chromium.chrome.browser.feedback.HelpAndFeedbackLauncher;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.incognito.interstitial.IncognitoInterstitialDelegate;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
-import org.chromium.chrome.browser.signin.account_picker.AccountPickerBottomSheetCoordinator;
+import org.chromium.chrome.browser.signin.ui.R;
+import org.chromium.chrome.browser.signin.ui.account_picker.AccountPickerBottomSheetCoordinator;
 import org.chromium.chrome.browser.signin.ui.account_picker.AccountPickerDelegate;
 import org.chromium.chrome.browser.tabmodel.TabCreator;
 import org.chromium.chrome.browser.tabmodel.TabModel;
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 70c7ad6..4ba908a4 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -5014,16 +5014,13 @@
 
   <!-- Strings for Oobe fingerprint enrollment screen -->
   <message name="IDS_OOBE_FINGERPINT_SETUP_SCREEN_TITLE" desc="The title of the dialog that allow users to register their fingerprint.">
-    Set up your fingerprint to unlock your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> faster
+    Unlock faster with your fingerprint
   </message>
   <message name="IDS_OOBE_FINGERPINT_SETUP_SCREEN_SENSOR_POWER_BUTTON_DESCRIPTION" desc="The label that explains that the fingerprint sensor is in the power button.">
-    Touch the power button with your finger
+    Touch the power button with your finger. Your data is stored securely and never leaves your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>.
   </message>
   <message name="IDS_OOBE_FINGERPINT_SETUP_SCREEN_SENSOR_GENERAL_DESCRIPTION" desc="The label that explains the location of the fingerprint sensor on the device.">
-      Touch the fingerprint sensor with your finger
-  </message>
-  <message name="IDS_OOBE_FINGERPINT_SETUP_SCREEN_ENROLLMENT_FOOTER" desc="Footer message for the fingerprint setup screen">
-      Your fingerprint data is stored securely and never leaves your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>.
+    Touch the fingerprint sensor with your finger. Your data is stored securely and never leaves your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>.
   </message>
   <message name="IDS_OOBE_FINGERPINT_SETUP_SCREEN_ENROLLMENT_PROGRESS_TITLE" desc="The title of the dialog that shows where the fingerprint sensor is.">
     Lift, then touch again
@@ -5052,10 +5049,10 @@
   <message name="IDS_OOBE_FINGERPINT_SETUP_SCREEN_NEW_FINGERPRINT_DEFAULT_NAME_3" desc="The default name for third newly added fingerprint.">
     Finger 3
   </message>
-  <message name="IDS_OOBE_FINGERPINT_SETUP_SCREEN_INSTRUCTION_MOVE_FINGER" desc="Text in the fingerprint setup screen telling users what to move finger to capture the different parts of fingerprint.">
-    Move your finger slightly to add the different parts of your fingerprint.
+  <message name="IDS_OOBE_FINGERPINT_SETUP_SCREEN_INSTRUCTION_MOVE_FINGER" desc="Text in the fingerprint setup screen telling users to lift their finger to capture the different parts of fingerprint.">
+    Keep lifting your finger to add the different parts of your fingerprint
   </message>
-  <message name="IDS_OOBE_FINGERPINT_SETUP_SCREEN_INSTRUCTION_TRY_AGAIN" desc="Text in the fingerprint setup screen telling users what to scan their finger again.">
+  <message name="IDS_OOBE_FINGERPINT_SETUP_SCREEN_INSTRUCTION_TRY_AGAIN" desc="Text in the fingerprint setup screen telling users to scan their finger again.">
     Try again.
   </message>
 
diff --git a/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_ENROLLMENT_FOOTER.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_ENROLLMENT_FOOTER.png.sha1
deleted file mode 100644
index adbbc65..0000000
--- a/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_ENROLLMENT_FOOTER.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-11bc40ec49d69e06a5f1129da1ec43891c20d10e
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_INSTRUCTION_MOVE_FINGER.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_INSTRUCTION_MOVE_FINGER.png.sha1
index 4e1bc54..47b8d26f 100644
--- a/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_INSTRUCTION_MOVE_FINGER.png.sha1
+++ b/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_INSTRUCTION_MOVE_FINGER.png.sha1
@@ -1 +1 @@
-0aa420cbdd6f271aa13288688e3fe83347f649b2
\ No newline at end of file
+40eafc15947667ce759612e53e37039ab57fde3a
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_SENSOR_DESCRIPTION.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_SENSOR_DESCRIPTION.png.sha1
deleted file mode 100644
index 4e1bc54..0000000
--- a/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_SENSOR_DESCRIPTION.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-0aa420cbdd6f271aa13288688e3fe83347f649b2
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_SENSOR_GENERAL_DESCRIPTION.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_SENSOR_GENERAL_DESCRIPTION.png.sha1
new file mode 100644
index 0000000..cf369e6
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_SENSOR_GENERAL_DESCRIPTION.png.sha1
@@ -0,0 +1 @@
+fc343e6f384fb9347d483de80e0722e70cb8540a
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_SENSOR_POWER_BUTTON_DESCRIPTION.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_SENSOR_POWER_BUTTON_DESCRIPTION.png.sha1
new file mode 100644
index 0000000..e5315d4
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_SENSOR_POWER_BUTTON_DESCRIPTION.png.sha1
@@ -0,0 +1 @@
+4b1e922d26d25d7bbd1d4f99c44a802f619a8116
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_TITLE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_TITLE.png.sha1
index 64b6172..e5315d4 100644
--- a/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_TITLE.png.sha1
+++ b/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_TITLE.png.sha1
@@ -1 +1 @@
-f256e5b231840df1d529f5694ef395226cdc477a
\ No newline at end of file
+4b1e922d26d25d7bbd1d4f99c44a802f619a8116
\ No newline at end of file
diff --git a/chrome/app/profiles_strings.grdp b/chrome/app/profiles_strings.grdp
index eff833b..2dff859d 100644
--- a/chrome/app/profiles_strings.grdp
+++ b/chrome/app/profiles_strings.grdp
@@ -765,7 +765,10 @@
       ...
     </message>
     <message name="IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_PROFILE_TYPE_CHOICE_SUBTITLE" desc="Profile picker profile type choice subtitle">
-      Sign in to Sync your bookmarks, passwords, history and more on all your devices
+      To access your Chrome stuff across all your devices, sign in, then turn on sync.
+    </message>
+    <message name="IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_PROFILE_TYPE_CHOICE_SUBTITLE_V2" desc="Profile picker profile type choice subtitle">
+      To access your Chrome stuff across all your devices, sign in so that you can turn on sync.
     </message>
     <message name="IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_SIGNIN_BUTTON_LABEL" desc="Label for a button that prompts user to sign in">
       Turn on sync...
@@ -785,11 +788,8 @@
     <message name="IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_DONE" desc="Label of a button to finish the profile creation.">
       Done
     </message>
-    <message name="IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_AVATAR_OK" desc="Label of a button to confirm avatar selection.">
-      OK
-    </message>
-    <message name="IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_AVATAR_CANCEL" desc="Label of a button to cancel avatar selection.">
-      Cancel
+    <message name="IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_AVATAR_DONE" desc="Label of a button to close avatar selection.">
+      Done
     </message>
     <message name="IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_INPUT_NAME" desc="Name of the input to configure the profile name in the profile customization window.">
       Add a name or a label like Work, Personal, or Kids
diff --git a/chrome/app/profiles_strings_grdp/IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_AVATAR_CANCEL.png.sha1 b/chrome/app/profiles_strings_grdp/IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_AVATAR_CANCEL.png.sha1
deleted file mode 100644
index 41c8f387..0000000
--- a/chrome/app/profiles_strings_grdp/IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_AVATAR_CANCEL.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-16bfabb2890a322b958bc80c683251f779fdb9dd
\ No newline at end of file
diff --git a/chrome/app/profiles_strings_grdp/IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_AVATAR_DONE.png.sha1 b/chrome/app/profiles_strings_grdp/IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_AVATAR_DONE.png.sha1
new file mode 100644
index 0000000..3b93cc9
--- /dev/null
+++ b/chrome/app/profiles_strings_grdp/IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_AVATAR_DONE.png.sha1
@@ -0,0 +1 @@
+5ba0789ffe586195c0e4a1e43480da46d73e44e7
\ No newline at end of file
diff --git a/chrome/app/profiles_strings_grdp/IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_AVATAR_OK.png.sha1 b/chrome/app/profiles_strings_grdp/IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_AVATAR_OK.png.sha1
deleted file mode 100644
index 41c8f387..0000000
--- a/chrome/app/profiles_strings_grdp/IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_AVATAR_OK.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-16bfabb2890a322b958bc80c683251f779fdb9dd
\ No newline at end of file
diff --git a/chrome/app/profiles_strings_grdp/IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_PROFILE_TYPE_CHOICE_SUBTITLE.png.sha1 b/chrome/app/profiles_strings_grdp/IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_PROFILE_TYPE_CHOICE_SUBTITLE.png.sha1
index 6fcb86e1..188313ce 100644
--- a/chrome/app/profiles_strings_grdp/IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_PROFILE_TYPE_CHOICE_SUBTITLE.png.sha1
+++ b/chrome/app/profiles_strings_grdp/IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_PROFILE_TYPE_CHOICE_SUBTITLE.png.sha1
@@ -1 +1 @@
-ff9106fc0cc3efef5eb51f7ba2ab0b799fa9b256
\ No newline at end of file
+d11144bc8bc505baf22f44152b590dc96c796574
\ No newline at end of file
diff --git a/chrome/app/profiles_strings_grdp/IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_PROFILE_TYPE_CHOICE_SUBTITLE_V2.png.sha1 b/chrome/app/profiles_strings_grdp/IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_PROFILE_TYPE_CHOICE_SUBTITLE_V2.png.sha1
new file mode 100644
index 0000000..4a2c007
--- /dev/null
+++ b/chrome/app/profiles_strings_grdp/IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_PROFILE_TYPE_CHOICE_SUBTITLE_V2.png.sha1
@@ -0,0 +1 @@
+6cdbd1b209a8657e0a790d1ec671d522e0c54344
\ No newline at end of file
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index 0144889..fae08de 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -59,6 +59,7 @@
   "+components/bookmarks/common",
   "+components/bookmarks/managed",
   "+components/bookmarks/test",
+  "+components/browser_ui/photo_picker",
   "+components/browser_ui/settings",
   "+components/browser_ui/util",
   "+components/browser_ui/widget",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 89e5fcc..12c9c4c 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -200,6 +200,7 @@
 #include "chrome/browser/flags/android/chrome_feature_list.h"
 #include "chrome/browser/notifications/chime/android/features.h"
 #include "chrome/browser/webapps/android/features.h"
+#include "components/browser_ui/photo_picker/android/features.h"
 #include "components/browser_ui/site_settings/android/features.h"
 #include "components/external_intents/android/external_intents_feature_list.h"
 #else  // OS_ANDROID
@@ -2003,6 +2004,16 @@
          base::size(kOmniboxSearchEngineLogoLoupeEverywhereVariationConstant),
          nullptr}};
 
+const FeatureEntry::FeatureParam
+    kPhotoPickerVideoSupportEnabledWithAnimatedThumbnails[] = {
+        {"animate_thumbnails", "true"}};
+const FeatureEntry::FeatureVariation
+    kPhotoPickerVideoSupportFeatureVariations[] = {
+        {"(with animated thumbnails)",
+         kPhotoPickerVideoSupportEnabledWithAnimatedThumbnails,
+         base::size(kPhotoPickerVideoSupportEnabledWithAnimatedThumbnails),
+         nullptr}};
+
 const FeatureEntry::FeatureParam kTabbedAppOverflowMenuRegroupBackward[] = {
     {"action_bar", "backward_button"}};
 const FeatureEntry::FeatureParam kTabbedAppOverflowMenuRegroupShare[] = {
@@ -6252,7 +6263,10 @@
     {"photo-picker-video-support",
      flag_descriptions::kPhotoPickerVideoSupportName,
      flag_descriptions::kPhotoPickerVideoSupportDescription, kOsAndroid,
-     FEATURE_VALUE_TYPE(chrome::android::kPhotoPickerVideoSupport)},
+     FEATURE_WITH_PARAMS_VALUE_TYPE(
+         photo_picker::features::kPhotoPickerVideoSupport,
+         kPhotoPickerVideoSupportFeatureVariations,
+         "PhotoPickerVideoSupportFeatureVariations")},
 #endif  // defined(OS_ANDROID)
 
     {"freeze-user-agent", flag_descriptions::kFreezeUserAgentName,
diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.cc b/chrome/browser/android/bookmarks/bookmark_bridge.cc
index 52ef509..5cef7cc 100644
--- a/chrome/browser/android/bookmarks/bookmark_bridge.cc
+++ b/chrome/browser/android/bookmarks/bookmark_bridge.cc
@@ -757,7 +757,12 @@
   if (partner_bookmarks_shim_->IsPartnerBookmark(node)) {
     partner_bookmarks_shim_->RemoveBookmark(node);
   } else if (type == BookmarkType::BOOKMARK_TYPE_READING_LIST) {
-    reading_list_manager_->Delete(node->url());
+    // Inside the Delete method, node will be destroyed and node->url will be
+    // also destroyed. This causes heap-use-after-free at
+    // ReadingListModelImpl::RemoveEntryByURLImpl. To avoid the
+    // heap-use-after-free, make a copy of node->url() and use it.
+    GURL url(node->url());
+    reading_list_manager_->Delete(url);
   } else {
     bookmark_model_->Remove(node);
   }
diff --git a/chrome/browser/autofill/android/personal_data_manager_android.cc b/chrome/browser/autofill/android/personal_data_manager_android.cc
index 6609905..d05901b 100644
--- a/chrome/browser/autofill/android/personal_data_manager_android.cc
+++ b/chrome/browser/autofill/android/personal_data_manager_android.cc
@@ -648,7 +648,7 @@
   AutofillProfile* profile = personal_data_manager_->GetProfileByGUID(
       ConvertJavaStringToUTF8(env, jguid));
   if (profile)
-    personal_data_manager_->RecordUseOf(*profile);
+    personal_data_manager_->RecordUseOf(profile);
 }
 
 void PersonalDataManagerAndroid::SetProfileUseStatsForTesting(
@@ -692,7 +692,7 @@
   CreditCard* card = personal_data_manager_->GetCreditCardByGUID(
       ConvertJavaStringToUTF8(env, jguid));
   if (card)
-    personal_data_manager_->RecordUseOf(*card);
+    personal_data_manager_->RecordUseOf(card);
 }
 
 void PersonalDataManagerAndroid::SetCreditCardUseStatsForTesting(
diff --git a/chrome/browser/autofill/automated_tests/cache_replayer.cc b/chrome/browser/autofill/automated_tests/cache_replayer.cc
index 3b63617..ba98e55 100644
--- a/chrome/browser/autofill/automated_tests/cache_replayer.cc
+++ b/chrome/browser/autofill/automated_tests/cache_replayer.cc
@@ -218,11 +218,11 @@
     const std::vector<network::DataElement>* data_elements) {
   std::string result;
   for (const network::DataElement& element : *data_elements) {
-    DCHECK_EQ(element.type(), network::mojom::DataElementType::kBytes);
+    DCHECK_EQ(element.type(), network::DataElement::Tag::kBytes);
     // Provide the length of the bytes explicitly, not to rely on the null
     // termination.
-    result.append(element.bytes(),
-                  base::checked_cast<size_t>(element.length()));
+    const auto piece = element.As<network::DataElementBytes>().AsStringPiece();
+    result.append(piece.data(), piece.size());
   }
   return result;
 }
diff --git a/chrome/browser/chromeos/camera_mic/vm_camera_mic_manager.cc b/chrome/browser/chromeos/camera_mic/vm_camera_mic_manager.cc
index b5e8a5d..7b53b00 100644
--- a/chrome/browser/chromeos/camera_mic/vm_camera_mic_manager.cc
+++ b/chrome/browser/chromeos/camera_mic/vm_camera_mic_manager.cc
@@ -62,7 +62,7 @@
 constexpr VmCameraMicManager::NotificationType
     VmCameraMicManager::kCameraNotification;
 constexpr VmCameraMicManager::NotificationType
-    VmCameraMicManager::kCameraWithMicNotification;
+    VmCameraMicManager::kCameraAndMicNotification;
 
 VmCameraMicManager* VmCameraMicManager::Get() {
   static base::NoDestructor<VmCameraMicManager> manager;
@@ -169,23 +169,11 @@
   return false;
 }
 
-bool VmCameraMicManager::IsNotificationActive(DeviceType device) const {
+bool VmCameraMicManager::IsNotificationActive(
+    NotificationType notification) const {
   for (const auto& vm_info : vm_info_map_) {
-    const NotificationType& notification_type =
-        vm_info.second.notification_type();
-    switch (device) {
-      case DeviceType::kMic:
-        if (notification_type == kMicNotification) {
-          return true;
-        }
-        break;
-      case DeviceType::kCamera:
-        // Both the "camera only" and "camera and mic" notifications use the
-        // camera icon.
-        if (notification_type[static_cast<size_t>(DeviceType::kCamera)]) {
-          return true;
-        }
-        break;
+    if (vm_info.second.notification_type() == notification) {
+      return true;
     }
   }
   return false;
diff --git a/chrome/browser/chromeos/camera_mic/vm_camera_mic_manager.h b/chrome/browser/chromeos/camera_mic/vm_camera_mic_manager.h
index 04f8fb7..1a4a092 100644
--- a/chrome/browser/chromeos/camera_mic/vm_camera_mic_manager.h
+++ b/chrome/browser/chromeos/camera_mic/vm_camera_mic_manager.h
@@ -43,6 +43,16 @@
     kMaxValue = kCamera,
   };
 
+  using NotificationType =
+      std::bitset<static_cast<size_t>(DeviceType::kMaxValue) + 1>;
+  static constexpr NotificationType kMicNotification{
+      1 << static_cast<size_t>(DeviceType::kMic)};
+  static constexpr NotificationType kCameraNotification{
+      1 << static_cast<size_t>(DeviceType::kCamera)};
+  static constexpr NotificationType kCameraAndMicNotification{
+      (1 << static_cast<size_t>(DeviceType::kMic)) |
+      (1 << static_cast<size_t>(DeviceType::kCamera))};
+
   class Observer : public base::CheckedObserver {
    public:
     virtual void OnVmCameraMicActiveChanged(VmCameraMicManager*) {}
@@ -64,27 +74,13 @@
   // Return true if any of the VMs is using the device. Note that if the camera
   // privacy switch is on, this always returns false for `kCamera`.
   bool IsDeviceActive(DeviceType device) const;
+  // Return true if any of the VMs is displaying the `notification`.
+  bool IsNotificationActive(NotificationType notification) const;
 
-  // When a VM is using both camera and mic, we only show a single "camera and
-  // mic" notification, which is considered a camera notification but not a mic
-  // notification because it uses the camera icon. So, if only "camera only" or
-  // "camera and mic" notifications are shown, this function returns true for
-  // `kCamera` but false for `kMic`. If a "mic only" notification is shown, this
-  // function returns true for `kMic`.
-  bool IsNotificationActive(DeviceType device) const;
  private:
   friend class VmCameraMicManagerTest;
 
-  using NotificationType =
-      std::bitset<static_cast<size_t>(DeviceType::kMaxValue) + 1>;
   static constexpr NotificationType kNoNotification{};
-  static constexpr NotificationType kMicNotification{
-      1 << static_cast<size_t>(DeviceType::kMic)};
-  static constexpr NotificationType kCameraNotification{
-      1 << static_cast<size_t>(DeviceType::kCamera)};
-  static constexpr NotificationType kCameraWithMicNotification{
-      (1 << static_cast<size_t>(DeviceType::kMic)) |
-      (1 << static_cast<size_t>(DeviceType::kCamera))};
 
   class VmInfo {
    public:
diff --git a/chrome/browser/chromeos/camera_mic/vm_camera_mic_manager_unittest.cc b/chrome/browser/chromeos/camera_mic/vm_camera_mic_manager_unittest.cc
index 778b2df..43274fc 100644
--- a/chrome/browser/chromeos/camera_mic/vm_camera_mic_manager_unittest.cc
+++ b/chrome/browser/chromeos/camera_mic/vm_camera_mic_manager_unittest.cc
@@ -27,6 +27,7 @@
 using testing::UnorderedElementsAre;
 using VmType = chromeos::VmCameraMicManager::VmType;
 using DeviceType = chromeos::VmCameraMicManager::DeviceType;
+using NotificationType = chromeos::VmCameraMicManager::NotificationType;
 
 constexpr VmType kCrostiniVm = VmType::kCrostiniVm;
 constexpr VmType kPluginVm = VmType::kPluginVm;
@@ -34,6 +35,13 @@
 constexpr DeviceType kCamera = DeviceType::kCamera;
 constexpr DeviceType kMic = DeviceType::kMic;
 
+constexpr NotificationType kMicNotification =
+    chromeos::VmCameraMicManager::kMicNotification;
+constexpr NotificationType kCameraNotification =
+    chromeos::VmCameraMicManager::kCameraNotification;
+constexpr NotificationType kCameraAndMicNotification =
+    chromeos::VmCameraMicManager::kCameraAndMicNotification;
+
 class FakeNotificationDisplayService : public NotificationDisplayService {
  public:
   FakeNotificationDisplayService() = default;
@@ -67,10 +75,18 @@
 
 struct IsActiveTestParam {
   ActiveMap active_map;
-  DeviceActiveMap device_expectations;
-  DeviceActiveMap notification_expectations;
+  // Device types that are expected to be active.
+  std::vector<DeviceType> device_expectations;
+  // Notification types that are expected to be active.
+  std::vector<NotificationType> notification_expectations;
 };
 
+template <typename T, typename V>
+bool contains(const T& container, const V& value) {
+  return std::find(container.begin(), container.end(), value) !=
+         container.end();
+}
+
 }  // namespace
 
 namespace chromeos {
@@ -78,25 +94,19 @@
 class VmCameraMicManagerTest : public testing::Test {
  public:
   // Define here to access `VmCameraMicManager` private members.
-  using NotificationType = VmCameraMicManager::NotificationType;
-  static constexpr NotificationType kMicNotification =
-      VmCameraMicManager::kMicNotification;
-  static constexpr NotificationType kCameraNotification =
-      VmCameraMicManager::kCameraNotification;
-  static constexpr NotificationType kCameraWithMicNotification =
-      VmCameraMicManager::kCameraWithMicNotification;
   struct NotificationTestParam {
     ActiveMap active_map;
     std::set<std::string> expected_notifications;
 
     NotificationTestParam(
         const ActiveMap& active_map,
-        const std::vector<std::pair<VmType, NotificationType>>& notifications) {
+        const std::vector<std::pair<VmType, NotificationType>>&
+            expected_notifications) {
       this->active_map = active_map;
-      for (const auto& vm_notification : notifications) {
-        auto result =
-            expected_notifications.insert(VmCameraMicManager::GetNotificationId(
-                vm_notification.first, vm_notification.second));
+      for (const auto& vm_notification : expected_notifications) {
+        auto result = this->expected_notifications.insert(
+            VmCameraMicManager::GetNotificationId(vm_notification.first,
+                                                  vm_notification.second));
         CHECK(result.second);
       }
     }
@@ -178,22 +188,26 @@
   SetCameraAccessing(kPluginVm, false);
   SetCameraPrivacyIsOn(kPluginVm, false);
   EXPECT_FALSE(vm_camera_mic_manager_->IsDeviceActive(kCamera));
-  EXPECT_FALSE(vm_camera_mic_manager_->IsNotificationActive(kCamera));
+  EXPECT_FALSE(
+      vm_camera_mic_manager_->IsNotificationActive(kCameraNotification));
 
   SetCameraAccessing(kPluginVm, true);
   SetCameraPrivacyIsOn(kPluginVm, false);
   EXPECT_TRUE(vm_camera_mic_manager_->IsDeviceActive(kCamera));
-  EXPECT_TRUE(vm_camera_mic_manager_->IsNotificationActive(kCamera));
+  EXPECT_TRUE(
+      vm_camera_mic_manager_->IsNotificationActive(kCameraNotification));
 
   SetCameraAccessing(kPluginVm, false);
   SetCameraPrivacyIsOn(kPluginVm, true);
   EXPECT_FALSE(vm_camera_mic_manager_->IsDeviceActive(kCamera));
-  EXPECT_FALSE(vm_camera_mic_manager_->IsNotificationActive(kCamera));
+  EXPECT_FALSE(
+      vm_camera_mic_manager_->IsNotificationActive(kCameraNotification));
 
   SetCameraAccessing(kPluginVm, true);
   SetCameraPrivacyIsOn(kPluginVm, true);
   EXPECT_FALSE(vm_camera_mic_manager_->IsDeviceActive(kCamera));
-  EXPECT_FALSE(vm_camera_mic_manager_->IsNotificationActive(kCamera));
+  EXPECT_FALSE(
+      vm_camera_mic_manager_->IsNotificationActive(kCameraNotification));
 }
 
 // Test `IsDeviceActive()` and `IsNotificationActive()`.
@@ -204,17 +218,15 @@
 TEST_P(VmCameraMicManagerIsActiveTest, IsNotificationActive) {
   SetActive(GetParam().active_map);
 
-  for (const auto& device_and_expectation : GetParam().device_expectations) {
-    EXPECT_EQ(
-        vm_camera_mic_manager_->IsDeviceActive(device_and_expectation.first),
-        device_and_expectation.second);
+  for (auto device : {kCamera, kMic}) {
+    EXPECT_EQ(vm_camera_mic_manager_->IsDeviceActive(device),
+              contains(GetParam().device_expectations, device));
   }
 
-  for (const auto& device_and_expectation :
-       GetParam().notification_expectations) {
-    EXPECT_EQ(vm_camera_mic_manager_->IsNotificationActive(
-                  device_and_expectation.first),
-              device_and_expectation.second);
+  for (auto notification :
+       {kCameraNotification, kMicNotification, kCameraAndMicNotification}) {
+    EXPECT_EQ(vm_camera_mic_manager_->IsNotificationActive(notification),
+              contains(GetParam().notification_expectations, notification));
   }
 }
 
@@ -227,32 +239,32 @@
                 {kCrostiniVm, {{kCamera, 0}, {kMic, 0}}},
                 {kPluginVm, {{kCamera, 0}, {kMic, 0}}},
             },
-            /*device_expectations=*/{{kCamera, 0}, {kMic, 0}},
-            /*notificatoin_expectations=*/{{kCamera, 0}, {kMic, 0}},
+            /*device_expectations=*/{},
+            /*notificatoin_expectations=*/{},
         },
         IsActiveTestParam{
             /*active_map=*/{
                 {kCrostiniVm, {{kCamera, 0}, {kMic, 0}}},
                 {kPluginVm, {{kCamera, 1}, {kMic, 0}}},
             },
-            /*device_expectations=*/{{kCamera, 1}, {kMic, 0}},
-            /*notificatoin_expectations=*/{{kCamera, 1}, {kMic, 0}},
+            /*device_expectations=*/{kCamera},
+            /*notificatoin_expectations=*/{kCameraNotification},
         },
         IsActiveTestParam{
             /*active_map=*/{
                 {kCrostiniVm, {{kCamera, 1}, {kMic, 0}}},
                 {kPluginVm, {{kCamera, 0}, {kMic, 0}}},
             },
-            /*device_expectations=*/{{kCamera, 1}, {kMic, 0}},
-            /*notificatoin_expectations=*/{{kCamera, 1}, {kMic, 0}},
+            /*device_expectations=*/{kCamera},
+            /*notificatoin_expectations=*/{kCameraNotification},
         },
         IsActiveTestParam{
             /*active_map=*/{
                 {kCrostiniVm, {{kCamera, 0}, {kMic, 1}}},
                 {kPluginVm, {{kCamera, 0}, {kMic, 0}}},
             },
-            /*device_expectations=*/{{kCamera, 0}, {kMic, 1}},
-            /*notificatoin_expectations=*/{{kCamera, 0}, {kMic, 1}},
+            /*device_expectations=*/{kMic},
+            /*notificatoin_expectations=*/{kMicNotification},
         },
         // Only a crostini "camera icon" notification is displayed.
         IsActiveTestParam{
@@ -260,8 +272,8 @@
                 {kCrostiniVm, {{kCamera, 1}, {kMic, 1}}},
                 {kPluginVm, {{kCamera, 0}, {kMic, 0}}},
             },
-            /*device_expectations=*/{{kCamera, 1}, {kMic, 1}},
-            /*notificatoin_expectations=*/{{kCamera, 1}, {kMic, 0}},
+            /*device_expectations=*/{kCamera, kMic},
+            /*notificatoin_expectations=*/{kCameraAndMicNotification},
         },
         // Crostini "camera icon" notification and pluginvm mic notification are
         // displayed.
@@ -270,8 +282,9 @@
                 {kCrostiniVm, {{kCamera, 1}, {kMic, 1}}},
                 {kPluginVm, {{kCamera, 0}, {kMic, 1}}},
             },
-            /*device_expectations=*/{{kCamera, 1}, {kMic, 1}},
-            /*notificatoin_expectations=*/{{kCamera, 1}, {kMic, 1}},
+            /*device_expectations=*/{kCamera, kMic},
+            /*notificatoin_expectations=*/
+            {kCameraAndMicNotification, kMicNotification},
         },
         // Crostini "camera icon" notification and pluginvm camera notification
         // are displayed.
@@ -280,8 +293,9 @@
                 {kCrostiniVm, {{kCamera, 1}, {kMic, 1}}},
                 {kPluginVm, {{kCamera, 1}, {kMic, 0}}},
             },
-            /*device_expectations=*/{{kCamera, 1}, {kMic, 1}},
-            /*notificatoin_expectations=*/{{kCamera, 1}, {kMic, 0}},
+            /*device_expectations=*/{kCamera, kMic},
+            /*notificatoin_expectations=*/
+            {kCameraAndMicNotification, kCameraNotification},
         },
         // Crostini camera notification and pluginvm mic notification are
         // displayed.
@@ -290,8 +304,9 @@
                 {kCrostiniVm, {{kCamera, 1}, {kMic, 0}}},
                 {kPluginVm, {{kCamera, 0}, {kMic, 1}}},
             },
-            /*device_expectations=*/{{kCamera, 1}, {kMic, 1}},
-            /*notificatoin_expectations=*/{{kCamera, 1}, {kMic, 1}},
+            /*device_expectations=*/{kCamera, kMic},
+            /*notificatoin_expectations=*/
+            {kCameraNotification, kMicNotification},
         },
         // Crostini and pluginvm "camera icon" notifications are displayed.
         IsActiveTestParam{
@@ -299,8 +314,8 @@
                 {kCrostiniVm, {{kCamera, 1}, {kMic, 1}}},
                 {kPluginVm, {{kCamera, 1}, {kMic, 1}}},
             },
-            /*device_expectations=*/{{kCamera, 1}, {kMic, 1}},
-            /*notificatoin_expectations=*/{{kCamera, 1}, {kMic, 0}},
+            /*device_expectations=*/{kCamera, kMic},
+            /*notificatoin_expectations=*/{kCameraAndMicNotification},
         }));
 
 class VmCameraMicManagerNotificationTest
@@ -343,7 +358,7 @@
             /*expected_notifications=*/
             {
                 {kCrostiniVm, kCameraNotification},
-                {kPluginVm, kCameraWithMicNotification},
+                {kPluginVm, kCameraAndMicNotification},
             },
         },
     };
diff --git a/chrome/browser/chromeos/crosapi/ash_chrome_service_impl.cc b/chrome/browser/chromeos/crosapi/ash_chrome_service_impl.cc
index 83fc0f2..9bdadfc 100644
--- a/chrome/browser/chromeos/crosapi/ash_chrome_service_impl.cc
+++ b/chrome/browser/chromeos/crosapi/ash_chrome_service_impl.cc
@@ -44,17 +44,12 @@
 AshChromeServiceImpl::AshChromeServiceImpl(
     mojo::PendingReceiver<mojom::AshChromeService> pending_receiver)
     : receiver_(this, std::move(pending_receiver)),
-      file_manager_ash_(std::make_unique<FileManagerAsh>()),
-      keystore_service_ash_(std::make_unique<KeystoreServiceAsh>()),
-      message_center_ash_(std::make_unique<MessageCenterAsh>()),
       metrics_reporting_ash_(std::make_unique<MetricsReportingAsh>(
           g_browser_process->local_state())),
       prefs_ash_(std::make_unique<PrefsAsh>(
           g_browser_process->local_state(),
           ProfileManager::GetPrimaryUserProfile()->GetPrefs())),
       screen_manager_ash_(std::make_unique<ScreenManagerAsh>()),
-      select_file_ash_(std::make_unique<SelectFileAsh>()),
-      feedback_ash_(std::make_unique<FeedbackAsh>()),
       cert_database_ash_(std::make_unique<CertDatabaseAsh>()),
       test_controller_ash_(std::make_unique<TestControllerAsh>()),
       clipboard_ash_(std::make_unique<ClipboardAsh>()) {
@@ -103,17 +98,25 @@
 
 void AshChromeServiceImpl::BindFileManager(
     mojo::PendingReceiver<crosapi::mojom::FileManager> receiver) {
-  file_manager_ash_->BindReceiver(std::move(receiver));
+  // TODO(https://crbug.com/1148448): Convert this to allow multiple,
+  // simultaneous crosapi clients. See BindScreenManager for an example.
+  file_manager_ash_ =
+      std::make_unique<crosapi::FileManagerAsh>(std::move(receiver));
 }
 
 void AshChromeServiceImpl::BindKeystoreService(
     mojo::PendingReceiver<crosapi::mojom::KeystoreService> receiver) {
-  keystore_service_ash_->BindReceiver(std::move(receiver));
+  // TODO(https://crbug.com/1148448): Convert this to allow multiple,
+  // simultaneous crosapi clients. See BindScreenManager for an example.
+  keystore_service_ash_ =
+      std::make_unique<crosapi::KeystoreServiceAsh>(std::move(receiver));
 }
 
 void AshChromeServiceImpl::BindMessageCenter(
     mojo::PendingReceiver<mojom::MessageCenter> receiver) {
-  message_center_ash_->BindReceiver(std::move(receiver));
+  // TODO(https://crbug.com/1148448): Convert this to allow multiple,
+  // simultaneous crosapi clients. See BindScreenManager for an example.
+  message_center_ash_ = std::make_unique<MessageCenterAsh>(std::move(receiver));
 }
 
 void AshChromeServiceImpl::BindMetricsReporting(
@@ -123,7 +126,9 @@
 
 void AshChromeServiceImpl::BindSelectFile(
     mojo::PendingReceiver<mojom::SelectFile> receiver) {
-  select_file_ash_->BindReceiver(std::move(receiver));
+  // TODO(https://crbug.com/1148448): Convert this to allow multiple,
+  // simultaneous crosapi clients. See BindScreenManager for an example.
+  select_file_ash_ = std::make_unique<SelectFileAsh>(std::move(receiver));
 }
 
 void AshChromeServiceImpl::BindScreenManager(
@@ -138,7 +143,9 @@
 
 void AshChromeServiceImpl::BindFeedback(
     mojo::PendingReceiver<mojom::Feedback> receiver) {
-  feedback_ash_->BindReceiver(std::move(receiver));
+  // TODO(https://crbug.com/1148448): Convert this to allow multiple,
+  // simultaneous crosapi clients. See BindScreenManager for an example.
+  feedback_ash_ = std::make_unique<FeedbackAsh>(std::move(receiver));
 }
 
 void AshChromeServiceImpl::BindMediaSessionController(
diff --git a/chrome/browser/chromeos/crosapi/feedback_ash.cc b/chrome/browser/chromeos/crosapi/feedback_ash.cc
index c558a86..5db2962 100644
--- a/chrome/browser/chromeos/crosapi/feedback_ash.cc
+++ b/chrome/browser/chromeos/crosapi/feedback_ash.cc
@@ -23,15 +23,11 @@
 
 }  // namespace
 
-FeedbackAsh::FeedbackAsh() = default;
+FeedbackAsh::FeedbackAsh(mojo::PendingReceiver<mojom::Feedback> receiver)
+    : receiver_(this, std::move(receiver)) {}
 
 FeedbackAsh::~FeedbackAsh() = default;
 
-void FeedbackAsh::BindReceiver(
-    mojo::PendingReceiver<mojom::Feedback> receiver) {
-  receivers_.Add(this, std::move(receiver));
-}
-
 void FeedbackAsh::ShowFeedbackPage(mojom::FeedbackInfoPtr feedback_info) {
   const user_manager::User* user =
       user_manager::UserManager::Get()->GetPrimaryUser();
diff --git a/chrome/browser/chromeos/crosapi/feedback_ash.h b/chrome/browser/chromeos/crosapi/feedback_ash.h
index 5695813..10e1cef 100644
--- a/chrome/browser/chromeos/crosapi/feedback_ash.h
+++ b/chrome/browser/chromeos/crosapi/feedback_ash.h
@@ -7,7 +7,7 @@
 
 #include "chromeos/crosapi/mojom/feedback.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 
 namespace crosapi {
 
@@ -15,18 +15,16 @@
 // UI thread. Shows feedback page in response to mojo IPCs from lacros-chrome.
 class FeedbackAsh : public mojom::Feedback {
  public:
-  FeedbackAsh();
+  explicit FeedbackAsh(mojo::PendingReceiver<mojom::Feedback> receiver);
   FeedbackAsh(const FeedbackAsh&) = delete;
   FeedbackAsh& operator=(const FeedbackAsh&) = delete;
   ~FeedbackAsh() override;
 
-  void BindReceiver(mojo::PendingReceiver<mojom::Feedback> receiver);
-
   // crosapi::mojom::Feedback:
   void ShowFeedbackPage(mojom::FeedbackInfoPtr feedback_info) override;
 
  private:
-  mojo::ReceiverSet<mojom::Feedback> receivers_;
+  mojo::Receiver<mojom::Feedback> receiver_;
 };
 
 }  // namespace crosapi
diff --git a/chrome/browser/chromeos/crosapi/file_manager_ash.cc b/chrome/browser/chromeos/crosapi/file_manager_ash.cc
index 5154446..7312bfb 100644
--- a/chrome/browser/chromeos/crosapi/file_manager_ash.cc
+++ b/chrome/browser/chromeos/crosapi/file_manager_ash.cc
@@ -67,15 +67,12 @@
 
 }  // namespace
 
-FileManagerAsh::FileManagerAsh() = default;
+FileManagerAsh::FileManagerAsh(
+    mojo::PendingReceiver<mojom::FileManager> receiver)
+    : receiver_(this, std::move(receiver)) {}
 
 FileManagerAsh::~FileManagerAsh() = default;
 
-void FileManagerAsh::BindReceiver(
-    mojo::PendingReceiver<mojom::FileManager> receiver) {
-  receivers_.Add(this, std::move(receiver));
-}
-
 void FileManagerAsh::DeprecatedShowItemInFolder(const base::FilePath& path) {
   Profile* primary_profile = ProfileManager::GetPrimaryUserProfile();
   base::FilePath final_path = ExpandPath(primary_profile, path);
diff --git a/chrome/browser/chromeos/crosapi/file_manager_ash.h b/chrome/browser/chromeos/crosapi/file_manager_ash.h
index 61e1c41..cf5e325 100644
--- a/chrome/browser/chromeos/crosapi/file_manager_ash.h
+++ b/chrome/browser/chromeos/crosapi/file_manager_ash.h
@@ -7,7 +7,7 @@
 
 #include "chromeos/crosapi/mojom/file_manager.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 
 namespace crosapi {
 
@@ -16,13 +16,11 @@
 // manager, for example to open a folder or highlight a file.
 class FileManagerAsh : public mojom::FileManager {
  public:
-  FileManagerAsh();
+  explicit FileManagerAsh(mojo::PendingReceiver<mojom::FileManager> receiver);
   FileManagerAsh(const FileManagerAsh&) = delete;
   FileManagerAsh& operator=(const FileManagerAsh&) = delete;
   ~FileManagerAsh() override;
 
-  void BindReceiver(mojo::PendingReceiver<mojom::FileManager> receiver);
-
   // crosapi::mojom::FileManager:
   void DeprecatedShowItemInFolder(const base::FilePath& path) override;
   void ShowItemInFolder(const base::FilePath& path,
@@ -32,7 +30,7 @@
   void OpenFile(const base::FilePath& path, OpenFileCallback callback) override;
 
  private:
-  mojo::ReceiverSet<mojom::FileManager> receivers_;
+  mojo::Receiver<mojom::FileManager> receiver_;
 };
 
 }  // namespace crosapi
diff --git a/chrome/browser/chromeos/crosapi/keystore_service_ash.cc b/chrome/browser/chromeos/crosapi/keystore_service_ash.cc
index 2c07ac9..d6289bce 100644
--- a/chrome/browser/chromeos/crosapi/keystore_service_ash.cc
+++ b/chrome/browser/chromeos/crosapi/keystore_service_ash.cc
@@ -62,7 +62,9 @@
 
 }  // namespace
 
-KeystoreServiceAsh::KeystoreServiceAsh() {
+KeystoreServiceAsh::KeystoreServiceAsh(
+    mojo::PendingReceiver<mojom::KeystoreService> receiver)
+    : receiver_(this, std::move(receiver)) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 }
 
@@ -70,11 +72,6 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 }
 
-void KeystoreServiceAsh::BindReceiver(
-    mojo::PendingReceiver<mojom::KeystoreService> receiver) {
-  receivers_.Add(this, std::move(receiver));
-}
-
 void KeystoreServiceAsh::ChallengeAttestationOnlyKeystore(
     const std::string& challenge,
     mojom::KeystoreType type,
diff --git a/chrome/browser/chromeos/crosapi/keystore_service_ash.h b/chrome/browser/chromeos/crosapi/keystore_service_ash.h
index df5b729..e9f56fc 100644
--- a/chrome/browser/chromeos/crosapi/keystore_service_ash.h
+++ b/chrome/browser/chromeos/crosapi/keystore_service_ash.h
@@ -12,7 +12,7 @@
 #include "chrome/browser/chromeos/platform_keys/platform_keys.h"
 #include "chromeos/crosapi/mojom/keystore_service.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 
 namespace chromeos {
 namespace attestation {
@@ -28,13 +28,12 @@
 // system keystores. This class is affine to the UI thread.
 class KeystoreServiceAsh : public mojom::KeystoreService {
  public:
-  KeystoreServiceAsh();
+  explicit KeystoreServiceAsh(
+      mojo::PendingReceiver<mojom::KeystoreService> receiver);
   KeystoreServiceAsh(const KeystoreServiceAsh&) = delete;
   KeystoreServiceAsh& operator=(const KeystoreServiceAsh&) = delete;
   ~KeystoreServiceAsh() override;
 
-  void BindReceiver(mojo::PendingReceiver<mojom::KeystoreService> receiver);
-
   // mojom::KeystoreService:
   using KeystoreType = mojom::KeystoreType;
   void ChallengeAttestationOnlyKeystore(
@@ -82,7 +81,7 @@
   // Container to keep outstanding challenges alive.
   std::vector<std::unique_ptr<chromeos::attestation::TpmChallengeKey>>
       outstanding_challenges_;
-  mojo::ReceiverSet<mojom::KeystoreService> receivers_;
+  mojo::Receiver<mojom::KeystoreService> receiver_;
 
   base::WeakPtrFactory<KeystoreServiceAsh> weak_factory_{this};
 };
diff --git a/chrome/browser/chromeos/crosapi/message_center_ash.cc b/chrome/browser/chromeos/crosapi/message_center_ash.cc
index 2127758..e9dbf42 100644
--- a/chrome/browser/chromeos/crosapi/message_center_ash.cc
+++ b/chrome/browser/chromeos/crosapi/message_center_ash.cc
@@ -156,15 +156,12 @@
 
 }  // namespace
 
-MessageCenterAsh::MessageCenterAsh() = default;
+MessageCenterAsh::MessageCenterAsh(
+    mojo::PendingReceiver<mojom::MessageCenter> receiver)
+    : receiver_(this, std::move(receiver)) {}
 
 MessageCenterAsh::~MessageCenterAsh() = default;
 
-void MessageCenterAsh::BindReceiver(
-    mojo::PendingReceiver<mojom::MessageCenter> receiver) {
-  receivers_.Add(this, std::move(receiver));
-}
-
 void MessageCenterAsh::DisplayNotification(
     mojom::NotificationPtr notification,
     mojo::PendingRemote<mojom::NotificationDelegate> delegate) {
diff --git a/chrome/browser/chromeos/crosapi/message_center_ash.h b/chrome/browser/chromeos/crosapi/message_center_ash.h
index 2464166..7379e53 100644
--- a/chrome/browser/chromeos/crosapi/message_center_ash.h
+++ b/chrome/browser/chromeos/crosapi/message_center_ash.h
@@ -7,7 +7,7 @@
 
 #include "chromeos/crosapi/mojom/message_center.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 
 namespace crosapi {
 
@@ -16,13 +16,12 @@
 // Sends reply IPCs when the user interacts with the notifications.
 class MessageCenterAsh : public mojom::MessageCenter {
  public:
-  MessageCenterAsh();
+  explicit MessageCenterAsh(
+      mojo::PendingReceiver<mojom::MessageCenter> receiver);
   MessageCenterAsh(const MessageCenterAsh&) = delete;
   MessageCenterAsh& operator=(const MessageCenterAsh&) = delete;
   ~MessageCenterAsh() override;
 
-  void BindReceiver(mojo::PendingReceiver<mojom::MessageCenter> receiver);
-
   // crosapi::mojom::MessageCenter:
   void DisplayNotification(
       mojom::NotificationPtr notification,
@@ -32,7 +31,7 @@
       GetDisplayedNotificationsCallback callback) override;
 
  private:
-  mojo::ReceiverSet<mojom::MessageCenter> receivers_;
+  mojo::Receiver<mojom::MessageCenter> receiver_;
 };
 
 }  // namespace crosapi
diff --git a/chrome/browser/chromeos/crosapi/message_center_ash_unittest.cc b/chrome/browser/chromeos/crosapi/message_center_ash_unittest.cc
index a9c98bf..27a5b43 100644
--- a/chrome/browser/chromeos/crosapi/message_center_ash_unittest.cc
+++ b/chrome/browser/chromeos/crosapi/message_center_ash_unittest.cc
@@ -84,8 +84,7 @@
   // testing::Test:
   void SetUp() override {
     message_center::MessageCenter::Initialize();
-    message_center_ash_ = std::make_unique<MessageCenterAsh>();
-    message_center_ash_->BindReceiver(
+    message_center_ash_ = std::make_unique<MessageCenterAsh>(
         message_center_remote_.BindNewPipeAndPassReceiver());
   }
 
diff --git a/chrome/browser/chromeos/crosapi/select_file_ash.cc b/chrome/browser/chromeos/crosapi/select_file_ash.cc
index 77e36eee8..d109e02 100644
--- a/chrome/browser/chromeos/crosapi/select_file_ash.cc
+++ b/chrome/browser/chromeos/crosapi/select_file_ash.cc
@@ -167,15 +167,12 @@
 
 }  // namespace
 
-SelectFileAsh::SelectFileAsh() = default;
+// TODO(https://crbug.com/1090587): Connection error handling.
+SelectFileAsh::SelectFileAsh(mojo::PendingReceiver<mojom::SelectFile> receiver)
+    : receiver_(this, std::move(receiver)) {}
 
 SelectFileAsh::~SelectFileAsh() = default;
 
-void SelectFileAsh::BindReceiver(
-    mojo::PendingReceiver<mojom::SelectFile> receiver) {
-  receivers_.Add(this, std::move(receiver));
-}
-
 void SelectFileAsh::Select(mojom::SelectFileOptionsPtr options,
                            SelectCallback callback) {
   aura::Window* owner_window = nullptr;
diff --git a/chrome/browser/chromeos/crosapi/select_file_ash.h b/chrome/browser/chromeos/crosapi/select_file_ash.h
index 58c78ce..28509dc 100644
--- a/chrome/browser/chromeos/crosapi/select_file_ash.h
+++ b/chrome/browser/chromeos/crosapi/select_file_ash.h
@@ -7,7 +7,7 @@
 
 #include "chromeos/crosapi/mojom/select_file.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 
 namespace crosapi {
 
@@ -16,19 +16,17 @@
 // file manager to provide the dialogs. Lives on the UI thread.
 class SelectFileAsh : public mojom::SelectFile {
  public:
-  SelectFileAsh();
+  explicit SelectFileAsh(mojo::PendingReceiver<mojom::SelectFile> receiver);
   SelectFileAsh(const SelectFileAsh&) = delete;
   SelectFileAsh& operator=(const SelectFileAsh&) = delete;
   ~SelectFileAsh() override;
 
-  void BindReceiver(mojo::PendingReceiver<mojom::SelectFile> receiver);
-
   // crosapi::mojom::SelectFile:
   void Select(mojom::SelectFileOptionsPtr options,
               SelectCallback callback) override;
 
  private:
-  mojo::ReceiverSet<mojom::SelectFile> receivers_;
+  mojo::Receiver<mojom::SelectFile> receiver_;
 };
 
 }  // namespace crosapi
diff --git a/chrome/browser/chromeos/file_manager/file_manager_jstest.cc b/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
index 138eab9..8ecebe1 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
@@ -25,11 +25,11 @@
 }
 
 IN_PROC_BROWSER_TEST_F(FileManagerJsTest, ActionsSubmenuTest) {
-  RunTestURL("foreground/js/ui/actions_submenu_unittest_gen.html");
+  RunTestURL("foreground/js/ui/actions_submenu_unittest.m_gen.html");
 }
 
 IN_PROC_BROWSER_TEST_F(FileManagerJsTest, Breadcrumb) {
-  RunTestURL("foreground/js/ui/breadcrumb_unittest_gen.html");
+  RunTestURL("foreground/js/ui/breadcrumb_unittest.m_gen.html");
 }
 
 IN_PROC_BROWSER_TEST_F(FileManagerJsTest, ContentMetadataProvider) {
@@ -169,7 +169,8 @@
 }
 
 IN_PROC_BROWSER_TEST_F(FileManagerJsTest, InstallLinuxPackageDialogTest) {
-  RunTestURL("foreground/js/ui/install_linux_package_dialog_unittest_gen.html");
+  RunTestURL(
+      "foreground/js/ui/install_linux_package_dialog_unittest.m_gen.html");
 }
 
 IN_PROC_BROWSER_TEST_F(FileManagerJsTest, ListThumbnailLoader) {
diff --git a/chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller.cc b/chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller.cc
index 1e469df7..04f2a7e 100644
--- a/chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller.cc
+++ b/chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller.cc
@@ -17,11 +17,84 @@
 
 namespace {
 
-bool IsFilesApp(const GURL& url) {
+bool IsFilesApp(const ui::DataTransferEndpoint* const data_dst) {
+  if (!data_dst || !data_dst->IsUrlType())
+    return false;
+
+  GURL url = data_dst->origin()->GetURL();
   return url.has_scheme() && url.SchemeIs(extensions::kExtensionScheme) &&
          url.has_host() && url.host() == extension_misc::kFilesManagerAppId;
 }
 
+bool IsClipboardHistory(const ui::DataTransferEndpoint* const data_dst) {
+  return data_dst && data_dst->type() == ui::EndpointType::kClipboardHistory;
+}
+
+DlpRulesManager::Level IsDataTransferAllowed(
+    const DlpRulesManager& dlp_rules_manager,
+    const ui::DataTransferEndpoint* const data_src,
+    const ui::DataTransferEndpoint* const data_dst) {
+  if (!data_src || !data_src->IsUrlType()) {  // Currently we only handle URLs.
+    return DlpRulesManager::Level::kAllow;
+  }
+
+  const GURL src_url = data_src->origin()->GetURL();
+  ui::EndpointType dst_type =
+      data_dst ? data_dst->type() : ui::EndpointType::kDefault;
+
+  DlpRulesManager::Level level = DlpRulesManager::Level::kAllow;
+
+  switch (dst_type) {
+    case ui::EndpointType::kDefault:
+    case ui::EndpointType::kUnknownVm:
+    case ui::EndpointType::kBorealis: {
+      // Passing empty URL will return restricted if there's a rule restricting
+      // the src against any dst (*), otherwise it will return ALLOW.
+      level = dlp_rules_manager.IsRestrictedDestination(
+          src_url, GURL(), DlpRulesManager::Restriction::kClipboard);
+      break;
+    }
+
+    case ui::EndpointType::kUrl: {
+      GURL dst_url = data_dst->origin()->GetURL();
+      level = dlp_rules_manager.IsRestrictedDestination(
+          src_url, dst_url, DlpRulesManager::Restriction::kClipboard);
+      break;
+    }
+
+    case ui::EndpointType::kCrostini: {
+      level = dlp_rules_manager.IsRestrictedComponent(
+          src_url, DlpRulesManager::Component::kCrostini,
+          DlpRulesManager::Restriction::kClipboard);
+      break;
+    }
+
+    case ui::EndpointType::kPluginVm: {
+      level = dlp_rules_manager.IsRestrictedComponent(
+          src_url, DlpRulesManager::Component::kPluginVm,
+          DlpRulesManager::Restriction::kClipboard);
+      break;
+    }
+
+    case ui::EndpointType::kArc: {
+      level = dlp_rules_manager.IsRestrictedComponent(
+          src_url, DlpRulesManager::Component::kArc,
+          DlpRulesManager::Restriction::kClipboard);
+      break;
+    }
+
+    case ui::EndpointType::kClipboardHistory: {
+      level = DlpRulesManager::Level::kAllow;
+      break;
+    }
+
+    default:
+      NOTREACHED();
+  }
+
+  return level;
+}
+
 }  // namespace
 
 // static
@@ -33,70 +106,17 @@
 bool DataTransferDlpController::IsClipboardReadAllowed(
     const ui::DataTransferEndpoint* const data_src,
     const ui::DataTransferEndpoint* const data_dst) {
-  if (!data_src || !data_src->IsUrlType()) {  // Currently we only handle URLs.
-    return true;
-  }
+  DlpRulesManager::Level level =
+      IsDataTransferAllowed(dlp_rules_manager_, data_src, data_dst);
 
-  const GURL src_url = data_src->origin()->GetURL();
-  DlpRulesManager::Level level = DlpRulesManager::Level::kAllow;
   bool notify_on_paste = !data_dst || data_dst->notify_if_restricted();
-  ui::EndpointType dst_type =
-      data_dst ? data_dst->type() : ui::EndpointType::kDefault;
-
-  switch (dst_type) {
-    case ui::EndpointType::kDefault:
-    case ui::EndpointType::kUnknownVm:
-    case ui::EndpointType::kBorealis: {
-      // Passing empty URL will return restricted if there's a rule restricting
-      // the src against any dst (*), otherwise it will return ALLOW.
-      level = dlp_rules_manager_.IsRestrictedDestination(
-          src_url, GURL(), DlpRulesManager::Restriction::kClipboard);
-      break;
-    }
-
-    case ui::EndpointType::kUrl: {
-      GURL dst_url = data_dst->origin()->GetURL();
-      level = dlp_rules_manager_.IsRestrictedDestination(
-          src_url, dst_url, DlpRulesManager::Restriction::kClipboard);
-      // Files Apps continously reads the clipboard data which triggers a lot of
-      // notifications while the user isn't actually initiating any copy/paste.
-      // TODO(crbug.com/1152475): Find a better way to handle File app.
-      if (IsFilesApp(dst_url))
-        notify_on_paste = false;
-      break;
-    }
-
-    case ui::EndpointType::kCrostini: {
-      level = dlp_rules_manager_.IsRestrictedComponent(
-          src_url, DlpRulesManager::Component::kCrostini,
-          DlpRulesManager::Restriction::kClipboard);
-      break;
-    }
-
-    case ui::EndpointType::kPluginVm: {
-      level = dlp_rules_manager_.IsRestrictedComponent(
-          src_url, DlpRulesManager::Component::kPluginVm,
-          DlpRulesManager::Restriction::kClipboard);
-      break;
-    }
-
-    case ui::EndpointType::kArc: {
-      level = dlp_rules_manager_.IsRestrictedComponent(
-          src_url, DlpRulesManager::Component::kArc,
-          DlpRulesManager::Restriction::kClipboard);
-      break;
-    }
-
-    case ui::EndpointType::kClipboardHistory: {
-      // When ClipboardHistory tries to read the clipboard we should allow it
-      // silently.
-      notify_on_paste = false;
-      break;
-    }
-
-    default:
-      NOTREACHED();
-  }
+  // Files Apps continuously reads the clipboard data which triggers a lot of
+  // notifications while the user isn't actually initiating any copy/paste.
+  // TODO(crbug.com/1152475): Find a better way to handle File app.
+  // When ClipboardHistory tries to read the clipboard we should allow it
+  // silently.
+  if (IsFilesApp(data_dst) || IsClipboardHistory(data_dst))
+    notify_on_paste = false;
 
   if (level == DlpRulesManager::Level::kBlock && notify_on_paste) {
     DoNotifyBlockedPaste(data_src, data_dst);
@@ -107,9 +127,16 @@
 
 bool DataTransferDlpController::IsDragDropAllowed(
     const ui::DataTransferEndpoint* const data_src,
-    const ui::DataTransferEndpoint* const data_dst) {
-  // TODO(crbug.com/1160656): Migrate off using `IsClipboardReadAllowed`.
-  return IsClipboardReadAllowed(data_src, data_dst);
+    const ui::DataTransferEndpoint* const data_dst,
+    const bool is_drop) {
+  DlpRulesManager::Level level =
+      IsDataTransferAllowed(dlp_rules_manager_, data_src, data_dst);
+
+  if (level == DlpRulesManager::Level::kBlock && is_drop) {
+    DoNotifyBlockedPaste(data_src, data_dst);
+  }
+
+  return level == DlpRulesManager::Level::kAllow;
 }
 
 DataTransferDlpController::DataTransferDlpController(
diff --git a/chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller.h b/chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller.h
index 7e132ba..19d8f91 100644
--- a/chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller.h
+++ b/chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller.h
@@ -36,9 +36,9 @@
   bool IsClipboardReadAllowed(
       const ui::DataTransferEndpoint* const data_src,
       const ui::DataTransferEndpoint* const data_dst) override;
-  bool IsDragDropAllowed(
-      const ui::DataTransferEndpoint* const data_src,
-      const ui::DataTransferEndpoint* const data_dst) override;
+  bool IsDragDropAllowed(const ui::DataTransferEndpoint* const data_src,
+                         const ui::DataTransferEndpoint* const data_dst,
+                         const bool is_drop) override;
 
  protected:
   explicit DataTransferDlpController(const DlpRulesManager& dlp_rules_manager);
diff --git a/chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller_unittest.cc b/chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller_unittest.cc
index 7d93a88..eee3b22 100644
--- a/chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller_unittest.cc
+++ b/chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller_unittest.cc
@@ -82,34 +82,53 @@
 
 TEST_F(DataTransferDlpControllerTest, NullSrc) {
   EXPECT_EQ(true, dlp_controller_.IsClipboardReadAllowed(nullptr, nullptr));
+  EXPECT_EQ(true, dlp_controller_.IsDragDropAllowed(nullptr, nullptr,
+                                                    /*is_drop=*/false));
 }
 
 TEST_F(DataTransferDlpControllerTest, NullDst) {
   ui::DataTransferEndpoint data_src(url::Origin::Create(GURL(kGoogleUrl)));
-  EXPECT_CALL(rules_manager_, IsRestrictedDestination)
-      .WillOnce(testing::Return(DlpRulesManager::Level::kBlock));
-  EXPECT_CALL(dlp_controller_, DoNotifyBlockedPaste);
-  EXPECT_EQ(false, dlp_controller_.IsClipboardReadAllowed(&data_src, nullptr));
+  {
+    EXPECT_CALL(rules_manager_, IsRestrictedDestination)
+        .WillOnce(testing::Return(DlpRulesManager::Level::kBlock));
+    EXPECT_CALL(dlp_controller_, DoNotifyBlockedPaste);
+    EXPECT_EQ(false,
+              dlp_controller_.IsClipboardReadAllowed(&data_src, nullptr));
+  }
+  {
+    EXPECT_CALL(rules_manager_, IsRestrictedDestination)
+        .WillOnce(testing::Return(DlpRulesManager::Level::kBlock));
+    EXPECT_EQ(false, dlp_controller_.IsDragDropAllowed(&data_src, nullptr,
+                                                       /*is_drop=*/false));
+  }
 }
 
 TEST_F(DataTransferDlpControllerTest, DefaultDst) {
   ui::DataTransferEndpoint data_src(url::Origin::Create(GURL(kGoogleUrl)));
-  ui::DataTransferEndpoint data_dst_1(ui::EndpointType::kDefault);
-  EXPECT_CALL(rules_manager_, IsRestrictedDestination)
-      .WillOnce(testing::Return(DlpRulesManager::Level::kBlock));
-  EXPECT_CALL(dlp_controller_, DoNotifyBlockedPaste);
-  EXPECT_EQ(false,
-            dlp_controller_.IsClipboardReadAllowed(&data_src, &data_dst_1));
-  testing::Mock::VerifyAndClearExpectations(&rules_manager_);
-  testing::Mock::VerifyAndClearExpectations(&dlp_controller_);
-
-  // Turn off notifications
-  ui::DataTransferEndpoint data_dst_2(ui::EndpointType::kDefault,
-                                      /*notify_if_restricted=*/false);
-  EXPECT_CALL(rules_manager_, IsRestrictedDestination)
-      .WillOnce(testing::Return(DlpRulesManager::Level::kBlock));
-  EXPECT_EQ(false,
-            dlp_controller_.IsClipboardReadAllowed(&data_src, &data_dst_2));
+  ui::DataTransferEndpoint data_dst(ui::EndpointType::kDefault);
+  {
+    EXPECT_CALL(rules_manager_, IsRestrictedDestination)
+        .WillOnce(testing::Return(DlpRulesManager::Level::kBlock));
+    EXPECT_CALL(dlp_controller_, DoNotifyBlockedPaste);
+    EXPECT_EQ(false,
+              dlp_controller_.IsClipboardReadAllowed(&data_src, &data_dst));
+  }
+  {
+    // Turn off notifications
+    ui::DataTransferEndpoint data_dst_2(ui::EndpointType::kDefault,
+                                        /*notify_if_restricted=*/false);
+    EXPECT_CALL(rules_manager_, IsRestrictedDestination)
+        .WillOnce(testing::Return(DlpRulesManager::Level::kBlock));
+    EXPECT_EQ(false,
+              dlp_controller_.IsClipboardReadAllowed(&data_src, &data_dst_2));
+  }
+  {
+    EXPECT_CALL(rules_manager_, IsRestrictedDestination)
+        .WillOnce(testing::Return(DlpRulesManager::Level::kBlock));
+    EXPECT_CALL(dlp_controller_, DoNotifyBlockedPaste);
+    EXPECT_EQ(false, dlp_controller_.IsDragDropAllowed(&data_src, &data_dst,
+                                                       /*is_drop=*/true));
+  }
 }
 
 TEST_F(DataTransferDlpControllerTest, ClipboardHistoryDst) {
@@ -120,42 +139,67 @@
 
 TEST_F(DataTransferDlpControllerTest, UrlSrcDst) {
   ui::DataTransferEndpoint data_src(url::Origin::Create(GURL(kGoogleUrl)));
-  ui::DataTransferEndpoint data_dst_1(url::Origin::Create(GURL(kYoutubeUrl)));
-  EXPECT_CALL(rules_manager_, IsRestrictedDestination)
-      .WillOnce(testing::Return(DlpRulesManager::Level::kBlock));
-  EXPECT_CALL(dlp_controller_, DoNotifyBlockedPaste);
-  EXPECT_EQ(false,
-            dlp_controller_.IsClipboardReadAllowed(&data_src, &data_dst_1));
-  testing::Mock::VerifyAndClearExpectations(&rules_manager_);
-  testing::Mock::VerifyAndClearExpectations(&dlp_controller_);
-
-  // Turn off notifications
-  ui::DataTransferEndpoint data_dst_2(url::Origin::Create(GURL(kYoutubeUrl)),
-                                      /*notify_if_restricted=*/false);
-  EXPECT_CALL(rules_manager_, IsRestrictedDestination)
-      .WillOnce(testing::Return(DlpRulesManager::Level::kBlock));
-  EXPECT_EQ(false,
-            dlp_controller_.IsClipboardReadAllowed(&data_src, &data_dst_2));
+  ui::DataTransferEndpoint data_dst(url::Origin::Create(GURL(kYoutubeUrl)));
+  {
+    EXPECT_CALL(rules_manager_, IsRestrictedDestination)
+        .WillOnce(testing::Return(DlpRulesManager::Level::kBlock));
+    EXPECT_CALL(dlp_controller_, DoNotifyBlockedPaste);
+    EXPECT_EQ(false,
+              dlp_controller_.IsClipboardReadAllowed(&data_src, &data_dst));
+  }
+  {
+    // Turn off notifications
+    ui::DataTransferEndpoint data_dst_2(url::Origin::Create(GURL(kYoutubeUrl)),
+                                        /*notify_if_restricted=*/false);
+    EXPECT_CALL(rules_manager_, IsRestrictedDestination)
+        .WillOnce(testing::Return(DlpRulesManager::Level::kBlock));
+    EXPECT_EQ(false,
+              dlp_controller_.IsClipboardReadAllowed(&data_src, &data_dst_2));
+  }
+  {
+    EXPECT_CALL(rules_manager_, IsRestrictedDestination)
+        .WillOnce(testing::Return(DlpRulesManager::Level::kBlock));
+    EXPECT_EQ(false, dlp_controller_.IsDragDropAllowed(&data_src, &data_dst,
+                                                       /*is_drop=*/false));
+  }
 }
 
 TEST_F(DataTransferDlpControllerTest, ArcDst) {
   ui::DataTransferEndpoint data_src(url::Origin::Create(GURL(kGoogleUrl)));
   ui::DataTransferEndpoint data_dst(ui::EndpointType::kArc);
-  EXPECT_CALL(rules_manager_, IsRestrictedComponent)
-      .WillOnce(testing::Return(DlpRulesManager::Level::kBlock));
-  EXPECT_CALL(dlp_controller_, DoNotifyBlockedPaste);
-  EXPECT_EQ(false,
-            dlp_controller_.IsClipboardReadAllowed(&data_src, &data_dst));
+  {
+    EXPECT_CALL(rules_manager_, IsRestrictedComponent)
+        .WillOnce(testing::Return(DlpRulesManager::Level::kBlock));
+    EXPECT_CALL(dlp_controller_, DoNotifyBlockedPaste);
+    EXPECT_EQ(false,
+              dlp_controller_.IsClipboardReadAllowed(&data_src, &data_dst));
+  }
+  {
+    EXPECT_CALL(rules_manager_, IsRestrictedComponent)
+        .WillOnce(testing::Return(DlpRulesManager::Level::kBlock));
+    EXPECT_CALL(dlp_controller_, DoNotifyBlockedPaste);
+    EXPECT_EQ(false, dlp_controller_.IsDragDropAllowed(&data_src, &data_dst,
+                                                       /*is_drop=*/true));
+  }
 }
 
 TEST_F(DataTransferDlpControllerTest, CrostiniDst) {
   ui::DataTransferEndpoint data_src(url::Origin::Create(GURL(kGoogleUrl)));
   ui::DataTransferEndpoint data_dst(ui::EndpointType::kCrostini);
-  EXPECT_CALL(rules_manager_, IsRestrictedComponent)
-      .WillOnce(testing::Return(DlpRulesManager::Level::kBlock));
-  EXPECT_CALL(dlp_controller_, DoNotifyBlockedPaste);
-  EXPECT_EQ(false,
-            dlp_controller_.IsClipboardReadAllowed(&data_src, &data_dst));
+  {
+    EXPECT_CALL(rules_manager_, IsRestrictedComponent)
+        .WillOnce(testing::Return(DlpRulesManager::Level::kBlock));
+    EXPECT_CALL(dlp_controller_, DoNotifyBlockedPaste);
+    EXPECT_EQ(false,
+              dlp_controller_.IsClipboardReadAllowed(&data_src, &data_dst));
+  }
+  {
+    EXPECT_CALL(rules_manager_, IsRestrictedComponent)
+        .WillOnce(testing::Return(DlpRulesManager::Level::kBlock));
+    EXPECT_CALL(dlp_controller_, DoNotifyBlockedPaste);
+    EXPECT_EQ(false, dlp_controller_.IsDragDropAllowed(&data_src, &data_dst,
+                                                       /*is_drop=*/true));
+  }
 }
 
 }  // namespace policy
diff --git a/chrome/browser/devtools/devtools_ui_bindings.cc b/chrome/browser/devtools/devtools_ui_bindings.cc
index dbb6472..d1f684b 100644
--- a/chrome/browser/devtools/devtools_ui_bindings.cc
+++ b/chrome/browser/devtools/devtools_ui_bindings.cc
@@ -140,6 +140,8 @@
 static const char kDevToolsCssEditorOpenedHistogram[] =
     "DevTools.CssEditorOpened";
 static const char kDevToolsIssueCreatedHistogram[] = "DevTools.IssueCreated";
+static const char kDevToolsDeveloperResourceLoadedHistogram[] =
+    "DevTools.DeveloperResourceLoaded";
 
 static const char kRemotePageActionInspect[] = "inspect";
 static const char kRemotePageActionReload[] = "reload";
@@ -1315,7 +1317,8 @@
       name == kDevtoolsIssuesPanelResourceOpenedHistogram ||
       name == kDevToolsGridOverlayOpenedFromHistogram ||
       name == kDevToolsCssEditorOpenedHistogram ||
-      name == kDevToolsIssueCreatedHistogram)
+      name == kDevToolsIssueCreatedHistogram ||
+      name == kDevToolsDeveloperResourceLoadedHistogram)
     base::UmaHistogramExactLinear(name, sample, boundary_value);
   else
     frontend_host_->BadMessageReceived();
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index a072dac..8c8f6d9 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -25,6 +25,7 @@
 #include "components/autofill/core/common/autofill_payments_features.h"
 #include "components/autofill_assistant/browser/features.h"
 #include "components/browser_sync/browser_sync_switches.h"
+#include "components/browser_ui/photo_picker/android/features.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
 #include "components/download/public/common/download_features.h"
 #include "components/embedder_support/android/util/cdn_utils.h"
@@ -191,12 +192,9 @@
     &kInlineUpdateFlow,
     &kInstantStart,
     &kKitKatSupported,
-    &kNewPhotoPicker,
     &kNotificationSuspender,
     &kOfflineIndicatorV2,
     &kOmniboxSpareRenderer,
-    &kPhotoPickerVideoSupport,
-    &kPhotoPickerZoom,
     &kProbabilisticCryptidRenderer,
     &kReachedCodeProfiler,
     &kReaderModeInCCT,
@@ -283,6 +281,7 @@
     &password_manager::features::kRecoverFromNeverSaveAndroid,
     &performance_hints::features::kContextMenuPerformanceInfo,
     &performance_hints::features::kPageInfoPerformanceHints,
+    &photo_picker::features::kPhotoPickerVideoSupport,
     &query_tiles::features::kQueryTilesGeoFilter,
     &query_tiles::features::kQueryTiles,
     &query_tiles::features::kQueryTilesInNTP,
@@ -542,9 +541,6 @@
 const base::Feature kSearchEnginePromoNewDevice{
     "SearchEnginePromo.NewDevice", base::FEATURE_ENABLED_BY_DEFAULT};
 
-const base::Feature kNewPhotoPicker{"NewPhotoPicker",
-                                    base::FEATURE_ENABLED_BY_DEFAULT};
-
 // TODO(knollr): This is a temporary kill switch, it can be removed once we feel
 // okay about leaving it on.
 const base::Feature kNotificationSuspender{"NotificationSuspender",
@@ -556,12 +552,6 @@
 const base::Feature kOmniboxSpareRenderer{"OmniboxSpareRenderer",
                                           base::FEATURE_DISABLED_BY_DEFAULT};
 
-const base::Feature kPhotoPickerVideoSupport{"PhotoPickerVideoSupport",
-                                             base::FEATURE_DISABLED_BY_DEFAULT};
-
-const base::Feature kPhotoPickerZoom{"PhotoPickerZoom",
-                                     base::FEATURE_ENABLED_BY_DEFAULT};
-
 const base::Feature kProbabilisticCryptidRenderer{
     "ProbabilisticCryptidRenderer", base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h
index 740781d9..458f9e14 100644
--- a/chrome/browser/flags/android/chrome_feature_list.h
+++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -90,12 +90,9 @@
 extern const base::Feature kInstantStart;
 extern const base::Feature kKitKatSupported;
 extern const base::Feature kLanguagesPreference;
-extern const base::Feature kNewPhotoPicker;
 extern const base::Feature kNotificationSuspender;
 extern const base::Feature kOfflineIndicatorV2;
 extern const base::Feature kOmniboxSpareRenderer;
-extern const base::Feature kPhotoPickerVideoSupport;
-extern const base::Feature kPhotoPickerZoom;
 extern const base::Feature kProbabilisticCryptidRenderer;
 extern const base::Feature kReachedCodeProfiler;
 extern const base::Feature kReengagementNotification;
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 42fbe65..5c09279 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
@@ -345,7 +345,6 @@
     public static final String MOBILE_IDENTITY_CONSISTENCY_VAR = "MobileIdentityConsistencyVar";
     public static final String MODAL_PERMISSION_DIALOG_VIEW = "ModalPermissionDialogView";
     public static final String METRICS_SETTINGS_ANDROID = "MetricsSettingsAndroid";
-    public static final String NEW_PHOTO_PICKER = "NewPhotoPicker";
     public static final String NOTIFICATION_SUSPENDER = "NotificationSuspender";
     public static final String OFFLINE_INDICATOR = "OfflineIndicator";
     public static final String OFFLINE_INDICATOR_ALWAYS_HTTP_PROBE =
@@ -377,7 +376,6 @@
     public static final String PASSWORD_SCRIPTS_FETCHING = "PasswordScriptsFetching";
     public static final String PERMISSION_DELEGATION = "PermissionDelegation";
     public static final String PHOTO_PICKER_VIDEO_SUPPORT = "PhotoPickerVideoSupport";
-    public static final String PHOTO_PICKER_ZOOM = "PhotoPickerZoom";
     public static final String PORTALS = "Portals";
     public static final String PORTALS_CROSS_ORIGIN = "PortalsCrossOrigin";
     public static final String PREDICTIVE_PREFETCHING_ALLOWED_ON_ALL_CONNECTION_TYPES =
diff --git a/chrome/browser/privacy_sandbox/android/BUILD.gn b/chrome/browser/privacy_sandbox/android/BUILD.gn
index 34e0cfc..c2393f1 100644
--- a/chrome/browser/privacy_sandbox/android/BUILD.gn
+++ b/chrome/browser/privacy_sandbox/android/BUILD.gn
@@ -10,9 +10,14 @@
     "//chrome/android:chrome_all_java",
     "//chrome/android:chrome_java",
   ]
-  sources = [ "java/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxSettingsFragment.java" ]
+  sources = [
+    "java/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxSettingsFragment.java",
+    "java/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxSnackbarController.java",
+  ]
   deps = [
     ":java_resources",
+    "//base:base_java",
+    "//chrome/browser/ui/messages/android:java",
     "//components/browser_ui/settings/android:java",
     "//third_party/android_deps:androidx_fragment_fragment_java",
     "//third_party/android_deps:androidx_preference_preference_java",
diff --git a/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxSnackbarController.java b/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxSnackbarController.java
new file mode 100644
index 0000000..813ef55
--- /dev/null
+++ b/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxSnackbarController.java
@@ -0,0 +1,60 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.privacy_sandbox;
+
+import android.content.Context;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.chrome.browser.ui.messages.snackbar.Snackbar;
+import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
+import org.chromium.components.browser_ui.settings.SettingsLauncher;
+
+/**
+ * Shows the snackbar for Privacy Sandbox settings, allowing the user to quickly navigate there.
+ */
+public class PrivacySandboxSnackbarController implements SnackbarManager.SnackbarController {
+    private Context mContext;
+    private SettingsLauncher mSettingsLauncher;
+    private SnackbarManager mSnackbarManager;
+
+    /**
+     * Creates an instance of the controller given a SnackbarManager and a SettingsLauncher.
+     */
+    public PrivacySandboxSnackbarController(
+            Context context, SnackbarManager manager, SettingsLauncher launcher) {
+        ThreadUtils.assertOnUiThread();
+        assert manager != null;
+        mContext = context;
+        mSnackbarManager = manager;
+        mSettingsLauncher = launcher;
+    }
+
+    /**
+     * Displays a snackbar, showing the user an option to go to Privacy Sandbox settings.
+     */
+    public void showSnackbar() {
+        mSnackbarManager.dismissSnackbars(this);
+        mSnackbarManager.showSnackbar(
+                Snackbar.make(mContext.getString(R.string.privacy_sandbox_snackbar_message), this,
+                                Snackbar.TYPE_ACTION, Snackbar.UMA_PRIVACY_SANDBOX_PAGE_OPEN)
+                        .setAction(mContext.getString(R.string.more), null));
+    }
+
+    /**
+     * Dismisses the snackbar, if it is active.
+     */
+    public void dismissSnackbar() {
+        mSnackbarManager.dismissSnackbars(this);
+    }
+
+    // Implement SnackbarController.
+    @Override
+    public void onAction(Object actionData) {
+        mSettingsLauncher.launchSettingsActivity(mContext, PrivacySandboxSettingsFragment.class);
+    }
+
+    @Override
+    public void onDismissNoAction(Object actionData) {}
+}
diff --git a/chrome/browser/resources/chromeos/login/fingerprint_setup.html b/chrome/browser/resources/chromeos/login/fingerprint_setup.html
index c4ed9ad..8198dd4 100644
--- a/chrome/browser/resources/chromeos/login/fingerprint_setup.html
+++ b/chrome/browser/resources/chromeos/login/fingerprint_setup.html
@@ -37,9 +37,6 @@
             <div id="sensorLocation"></div>
           </template>
         </div>
-        <div id="footer-text" class="content self-stretch" >
-          [[i18nDynamic(locale, 'setupFingerprintScreenFooter')]]
-        </div>
       </div>
       <div slot="bottom-buttons" class="layout horizontal end-justified">
         <oobe-text-button id="skipStart"
diff --git a/chrome/browser/resources/extensions/BUILD.gn b/chrome/browser/resources/extensions/BUILD.gn
index db0b18a..83764adf 100644
--- a/chrome/browser/resources/extensions/BUILD.gn
+++ b/chrome/browser/resources/extensions/BUILD.gn
@@ -4,6 +4,7 @@
 
 import("//build/config/chromeos/ui_mode.gni")
 import("//chrome/common/features.gni")
+import("//extensions/buildflags/buildflags.gni")
 import("//third_party/closure_compiler/compile_js.gni")
 import("//tools/grit/grit_rule.gni")
 import("//tools/grit/preprocess_if_expr.gni")
@@ -11,6 +12,8 @@
 import("//ui/webui/resources/tools/generate_grd.gni")
 import("../tools/optimize_webui.gni")
 
+assert(enable_extensions, "enable extensions check failed")
+
 preprocess_folder = "preprocessed"
 preprocess_manifest = "preprocessed_manifest.json"
 preprocess_gen_manifest = "preprocessed_gen_manifest.json"
diff --git a/chrome/browser/resources/new_tab_page/modules/module_descriptor.js b/chrome/browser/resources/new_tab_page/modules/module_descriptor.js
index 8032f59..8ebce26 100644
--- a/chrome/browser/resources/new_tab_page/modules/module_descriptor.js
+++ b/chrome/browser/resources/new_tab_page/modules/module_descriptor.js
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 import {BrowserProxy} from '../browser_proxy.js';
+import {mojoTimeDelta} from '../utils.js';
 
 /**
  * @fileoverview Provides the module descriptor. Each module must create a
@@ -47,11 +48,13 @@
   }
 
   async initialize() {
+    const loadStartTime = BrowserProxy.getInstance().now();
     this.element_ = await this.initializeCallback_();
     if (!this.element_) {
       return;
     }
+    const loadEndTime = BrowserProxy.getInstance().now();
     BrowserProxy.getInstance().handler.onModuleLoaded(
-        this.id_, BrowserProxy.getInstance().now());
+        this.id_, loadEndTime, mojoTimeDelta(loadEndTime - loadStartTime));
   }
 }
diff --git a/chrome/browser/resources/settings/lazy_load.js b/chrome/browser/resources/settings/lazy_load.js
index 1c0bdd6..86f910e 100644
--- a/chrome/browser/resources/settings/lazy_load.js
+++ b/chrome/browser/resources/settings/lazy_load.js
@@ -94,7 +94,7 @@
 export {ContentSettingProvider, DefaultContentSetting, RawChooserException, RawSiteException, RecentSitePermissions, SiteException, SiteGroup, SiteSettingsPrefsBrowserProxy, SiteSettingsPrefsBrowserProxyImpl, ZoomLevelEntry} from './site_settings/site_settings_prefs_browser_proxy.js';
 export {WebsiteUsageBrowserProxyImpl} from './site_settings/website_usage_browser_proxy.js';
 export {defaultSettingLabel} from './site_settings_page/site_settings_list.js';
-// <if expr="not chromeos">
+// <if expr="not chromeos and not lacros">
 export {SystemPageBrowserProxyImpl} from './system_page/system_page_browser_proxy.js';
 
 // </if>
diff --git a/chrome/browser/resources/signin/profile_picker/manage_profiles_browser_proxy.js b/chrome/browser/resources/signin/profile_picker/manage_profiles_browser_proxy.js
index c953358..d2e4df8 100644
--- a/chrome/browser/resources/signin/profile_picker/manage_profiles_browser_proxy.js
+++ b/chrome/browser/resources/signin/profile_picker/manage_profiles_browser_proxy.js
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {AvatarIcon} from 'chrome://resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.m.js';
 import {addSingletonGetter, sendWithPromise} from 'chrome://resources/js/cr.m.js';
 
 /**
@@ -113,15 +114,19 @@
   loadSignInProfileCreationFlow(profileColor) {}
 
   /**
+   * Retrieves custom avatar list for the select avatar dialog.
+   * * @return {!Promise<!Array<!AvatarIcon>>}
+   */
+  getAvailableIcons() {}
+
+  /**
    * Creates local profile
    * @param {string} profileName
    * @param {number} profileColor
-   * @param {string} avatarUrl
-   * @param {boolean} isGeneric
+   * @param {number} avatarIndex
    * @param {boolean} createShortcut
    */
-  createProfile(
-      profileName, profileColor, avatarUrl, isGeneric, createShortcut) {}
+  createProfile(profileName, profileColor, avatarIndex, createShortcut) {}
 
   /**
    * Sets the local profile name.
@@ -187,11 +192,15 @@
   }
 
   /** @override */
-  createProfile(
-      profileName, profileColor, avatarUrl, isGeneric, createShortcut) {
+  getAvailableIcons() {
+    return sendWithPromise('getAvailableIcons');
+  }
+
+  /** @override */
+  createProfile(profileName, profileColor, avatarIndex, createShortcut) {
     chrome.send(
         'createProfile',
-        [profileName, profileColor, avatarUrl, isGeneric, createShortcut]);
+        [profileName, profileColor, avatarIndex, createShortcut]);
   }
 
   /** @override */
diff --git a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/BUILD.gn b/chrome/browser/resources/signin/profile_picker/profile_creation_flow/BUILD.gn
index b4b3748..2b189f2 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/BUILD.gn
+++ b/chrome/browser/resources/signin/profile_picker/profile_creation_flow/BUILD.gn
@@ -34,8 +34,10 @@
     "//ui/webui/resources/cr_components/customize_themes",
     "//ui/webui/resources/cr_elements/cr_button:cr_button.m",
     "//ui/webui/resources/cr_elements/cr_checkbox:cr_checkbox.m",
+    "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog.m",
     "//ui/webui/resources/cr_elements/cr_icon_button:cr_icon_button.m",
     "//ui/webui/resources/cr_elements/cr_input:cr_input.m",
+    "//ui/webui/resources/cr_elements/cr_profile_avatar_selector:cr_profile_avatar_selector.m",
     "//ui/webui/resources/js:load_time_data.m",
     "//ui/webui/resources/js:web_ui_listener_behavior.m",
   ]
diff --git a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/local_profile_customization.html b/chrome/browser/resources/signin/profile_picker/profile_creation_flow/local_profile_customization.html
index 24defbe..dbf5ea7 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/local_profile_customization.html
+++ b/chrome/browser/resources/signin/profile_picker/profile_creation_flow/local_profile_customization.html
@@ -1,4 +1,4 @@
-<style include="profile-creation-shared">
+<style include="profile-creation-shared profile-picker-shared">
   :host {
     --vertical-gap: 24px;
   }
@@ -65,21 +65,6 @@
     overflow: auto;
   }
 
-  #wrapperContainer::-webkit-scrollbar {
-    width: var(--scrollbar-width);
-  }
-
-  /* Track */
-  #wrapperContainer::-webkit-scrollbar-track {
-    border-radius: var(--scrollbar-width);
-  }
-
-  /* Handle */
-  #wrapperContainer::-webkit-scrollbar-thumb {
-    background: var(--scrollbar-background);
-    border-radius: var(--scrollbar-width);
-  }
-
   #wrapper > * {
     flex-grow: 0;
     flex-shrink: 0;
@@ -143,6 +128,32 @@
     width: 111px;
   }
 
+  cr-profile-avatar-selector {
+    --avatar-size: 72px;
+    --avatar-spacing: 18px;
+    --avatar-grid-columns: 5;
+    height: fit-content;
+    padding-bottom: 15px;
+    padding-inline-start: 15px;
+    padding-top: 15px;
+    width: fit-content;
+  }
+
+  #selectAvatarWrapper {
+    height: 394px;
+    overflow-x: hidden;
+    overflow-y: auto;
+  }
+
+  #buttonContainer {
+    display: flex;
+    justify-content: flex-end;
+  }
+
+  #doneButton {
+    width : 32px;
+  }
+
   @media (prefers-color-scheme: dark) {
     #nameInput {
       --cr-input-placeholder-color: rgba(var(--google-grey-200-rgb), .5);
@@ -164,11 +175,11 @@
             --theme-shape-color:[[profileThemeInfo.themeShapeColor]]">
   <iron-icon class="banner" icon="profiles:customize-banner"></iron-icon>
   <cr-icon-button id="backButton" class="icon-arrow-back"
-        on-click="onClickBack_" aria-label="$i18n{backButtonLabel}">
+      on-click="onClickBack_" aria-label="$i18n{backButtonLabel}">
   </cr-icon-button>
   <h2 id="title">$i18n{localProfileCreationTitle}</h2>
   <div id="avatarContainer">
-    <img class="avatar" alt="" src$="[[profileThemeInfo.themeGenericAvatar]]">
+    <img class="avatar" alt="" src$="[[selectedAvatar_.url]]">
     <div id="customizeAvatarEllipse"></div>
     <cr-icon-button id="customizeAvatarIcon"
         iron-icon="profiles:create" on-click="onCustomizeAvatarClick_"
@@ -177,7 +188,7 @@
   </div>
 </div>
 
-<div id="wrapperContainer">
+<div id="wrapperContainer" class="custom-scrollbar">
   <div id="wrapper">
     <cr-input id="nameInput" value="{{profileName_}}" pattern="[[pattern_]]"
         placeholder="$i18n{createProfileNamePlaceholder}"
@@ -198,11 +209,28 @@
 <div class="footer">
   <cr-checkbox checked="{{createShortcut_}}"
       hidden="[[!isProfileShortcutsEnabled_]]">
-      $i18n{createDesktopShortcutLabel}
+    $i18n{createDesktopShortcutLabel}
   </cr-checkbox>
 
   <cr-button id="save" class="action-button" on-click="onSaveClick_"
-            disabled="[[isSaveDisabled_(createInProgress_, profileName_)]]">
+      disabled="[[isSaveDisabled_(createInProgress_, profileName_)]]">
     $i18n{createProfileConfirm}
   </cr-button>
 </div>
+
+<cr-dialog id="selectAvatarDialog">
+  <div slot="title">$i18n{selectAnAvatarDialogTitle}</div>
+  <div slot="body">
+    <div id="selectAvatarWrapper" class="custom-scrollbar">
+      <cr-profile-avatar-selector avatars="[[availableIcons_]]"
+          selected-avatar="{{selectedAvatar_}}">
+      </cr-profile-avatar-selector>
+    </div>
+  </div>
+  <div id="buttonContainer" slot="button-container">
+    <cr-button id="doneButton" class="action-button"
+        on-click="onDoneSelectAvatarClick_">
+      $i18n{selectAvatarDoneButtonLabel}
+    </cr-button>
+  </div>
+</cr-dialog>
diff --git a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/local_profile_customization.js b/chrome/browser/resources/signin/profile_picker/profile_creation_flow/local_profile_customization.js
index 57751048..41de377 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/local_profile_customization.js
+++ b/chrome/browser/resources/signin/profile_picker/profile_creation_flow/local_profile_customization.js
@@ -3,15 +3,20 @@
 // found in the LICENSE file.
 
 import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.m.js';
+import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js';
 import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
 import 'chrome://resources/cr_elements/cr_input/cr_input.m.js';
 import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js';
 import 'chrome://resources/cr_elements/shared_vars_css.m.js';
 import 'chrome://resources/cr_components/customize_themes/customize_themes.js';
+import 'chrome://resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.m.js';
 import './shared_css.js';
 import '../icons.js';
+import '../profile_picker_shared_css.js';
 
 import {Theme, ThemeType} from 'chrome://resources/cr_components/customize_themes/customize_themes.mojom-webui.js';
+import {AvatarIcon} from 'chrome://resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.m.js';
+import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {WebUIListenerBehavior} from 'chrome://resources/js/web_ui_listener_behavior.m.js';
 import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
@@ -25,7 +30,7 @@
 
   _template: html`{__html_template__}`,
 
-  behaviors: [WebUIListenerBehavior],
+  behaviors: [I18nBehavior, WebUIListenerBehavior],
 
   properties: {
     /**
@@ -58,6 +63,34 @@
     },
 
     /**
+     * Colored default generic avatar in the format expected by
+     * 'cr-profile-avatar-selector'
+     * @private {AvatarIcon}
+     */
+    genericDefaultAvatar_: {
+      type: Object,
+      computed: 'getGenericDefaultAvatar_(profileThemeInfo.themeGenericAvatar)',
+      observer: 'onGenericDefaultAvatarChange_',
+    },
+
+    /**
+     * List of available profile icon Urls and labels.
+     * @private {!Array<!AvatarIcon>}
+     */
+    availableIcons_: {
+      type: Array,
+      value() {
+        return [];
+      },
+    },
+
+    /**
+     * The currently selected profile avatar, if any.
+     * @private {?AvatarIcon}
+     */
+    selectedAvatar_: Object,
+
+    /**
      * The current profile name.
      * @private {string}
      */
@@ -98,6 +131,12 @@
       type: String,
       value: '.*\\S.*',
     },
+
+    /** @private */
+    defaultAvatarIndex_: {
+      type: Number,
+      value: () => loadTimeData.getInteger('placeholderAvatarIndex'),
+    },
   },
 
   listeners: {
@@ -118,6 +157,8 @@
     this.sanityCheck_();
     this.addWebUIListener(
         'create-profile-finished', () => this.handleCreateProfileFinished_());
+    this.manageProfilesBrowserProxy_.getAvailableIcons().then(
+        icons => this.setAvailableIcons_(icons));
   },
 
   /** @private */
@@ -172,10 +213,9 @@
     this.createInProgress_ = true;
     const createShortcut =
         this.isProfileShortcutsEnabled_ && this.createShortcut_;
-    // TODO(crbug.com/1115056): Support avatar selection.
     this.manageProfilesBrowserProxy_.createProfile(
-        this.profileName_, this.profileThemeInfo.color, '', true,
-        createShortcut);
+        this.profileName_, this.profileThemeInfo.color,
+        this.selectedAvatar_.index, createShortcut);
   },
 
   /** @private */
@@ -185,7 +225,49 @@
 
   /** @private */
   onCustomizeAvatarClick_() {
-    // TODO(msalama): Open select avatar dialog.
+    this.$.selectAvatarDialog.showModal();
+  },
+
+  /** @private */
+  onDoneSelectAvatarClick_() {
+    this.$.selectAvatarDialog.close();
+  },
+
+  /**
+   * @return {AvatarIcon}
+   * @private
+   */
+  getGenericDefaultAvatar_() {
+    return /** @type {!AvatarIcon} */ ({
+      url: this.profileThemeInfo.themeGenericAvatar,
+      label: this.i18n('defaultAvatarLabel'),
+      index: this.defaultAvatarIndex_,
+      isGaiaAvatar: false,
+      selected: false,
+    });
+  },
+
+  /** @private */
+  onGenericDefaultAvatarChange_() {
+    this.setAvailableIcons_([...this.availableIcons_]);
+    if (!this.selectedAvatar_ ||
+        this.selectedAvatar_.index === this.defaultAvatarIndex_) {
+      this.selectedAvatar_ = this.genericDefaultAvatar_;
+    }
+  },
+
+  /**
+   * @param {!Array<!AvatarIcon>} icons
+   * @private
+   */
+  setAvailableIcons_(icons) {
+    if (!this.genericDefaultAvatar_) {
+      this.availableIcons_ = icons;
+      return;
+    }
+    const offset =
+        icons.length > 0 && icons[0].index === this.defaultAvatarIndex_ ? 1 : 0;
+    this.availableIcons_ = [this.genericDefaultAvatar_, ...icons.slice(offset)];
   },
 
   /** @private */
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.html b/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.html
index b7de3118..fa4d01d 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.html
+++ b/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.html
@@ -72,21 +72,6 @@
     width: 100%;
   }
 
-  .profiles-container::-webkit-scrollbar {
-    width: var(--scrollbar-width);
-  }
-
-  /* Track */
-  .profiles-container::-webkit-scrollbar-track {
-    border-radius: var(--scrollbar-width);
-  }
-
-  /* Handle */
-  .profiles-container::-webkit-scrollbar-thumb {
-    background: var(--scrollbar-background);
-    border-radius: var(--scrollbar-width);
-  }
-
   .profile-item {
     align-items: center;
     border-radius: 12px;
@@ -168,7 +153,7 @@
   <h3>$i18n{mainViewSubtitle}</h3>
 </div>
 <div id="wrapper" hidden$="[[!profilesListLoaded_]]">
-  <div class="profiles-container">
+  <div class="profiles-container custom-scrollbar">
     <template is="dom-repeat" items="[[profilesList_]]">
       <profile-card
           class="profile-item" profile-state="[[item]]">
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker_shared_css.html b/chrome/browser/resources/signin/profile_picker/profile_picker_shared_css.html
index 80be335..f6a222e 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_picker_shared_css.html
+++ b/chrome/browser/resources/signin/profile_picker/profile_picker_shared_css.html
@@ -51,5 +51,20 @@
       position: absolute;
       width: 100%;
     }
+
+    .custom-scrollbar::-webkit-scrollbar {
+      width: var(--scrollbar-width);
+    }
+
+    /* Track */
+    .custom-scrollbar::-webkit-scrollbar-track {
+      border-radius: var(--scrollbar-width);
+    }
+
+    /* Handle */
+    .custom-scrollbar::-webkit-scrollbar-thumb {
+      background: var(--scrollbar-background);
+      border-radius: var(--scrollbar-width);
+    }
   </style>
 </template>
diff --git a/chrome/browser/sharing/sharing_message_sender.cc b/chrome/browser/sharing/sharing_message_sender.cc
index 630a1d0..b990c01 100644
--- a/chrome/browser/sharing/sharing_message_sender.cc
+++ b/chrome/browser/sharing/sharing_message_sender.cc
@@ -42,15 +42,13 @@
   chrome_browser_sharing::MessageType message_type =
       SharingPayloadCaseToMessageType(message.payload_case());
   SharingDevicePlatform receiver_device_platform = GetDevicePlatform(device);
-  base::TimeDelta last_updated_age =
-      base::Time::Now() - device.last_updated_timestamp();
 
   auto inserted = base::InsertOrAssign(
       message_metadata_, message_guid,
-      SentMessageMetadata(
-          std::move(callback), base::TimeTicks::Now(), message_type,
-          receiver_device_platform, last_updated_age, trace_id,
-          SharingChannelType::kUnknown, device.pulse_interval()));
+      SentMessageMetadata(std::move(callback), base::TimeTicks::Now(),
+                          message_type, receiver_device_platform, trace_id,
+                          SharingChannelType::kUnknown,
+                          device.pulse_interval()));
   DCHECK(inserted.second);
 
   auto delegate_iter = send_delegates_.find(delegate_type);
@@ -84,9 +82,6 @@
                          /*response=*/nullptr),
           response_timeout);
 
-  LogSharingDeviceLastUpdatedAge(message_type, last_updated_age);
-  LogSharingVersionComparison(message_type, device.chrome_version());
-
   message.set_sender_guid(local_device_info->guid());
   message.set_sender_device_name(
       send_tab_to_self::GetSharingDeviceNames(local_device_info).full_name);
@@ -184,7 +179,6 @@
   LogSendSharingMessageResult(metadata.type, metadata.receiver_device_platform,
                               metadata.channel_type,
                               metadata.receiver_pulse_interval, result);
-  LogSharingDeviceLastUpdatedAgeWithResult(result, metadata.last_updated_age);
   TRACE_EVENT_NESTABLE_ASYNC_END1("sharing", "SharingMessageSender.SendMessage",
                                   TRACE_ID_LOCAL(metadata.trace_id), "result",
                                   SharingSendMessageResultToString(result));
@@ -195,7 +189,6 @@
     base::TimeTicks timestamp,
     chrome_browser_sharing::MessageType type,
     SharingDevicePlatform receiver_device_platform,
-    base::TimeDelta last_updated_age,
     int trace_id,
     SharingChannelType channel_type,
     base::TimeDelta receiver_pulse_interval)
@@ -203,7 +196,6 @@
       timestamp(timestamp),
       type(type),
       receiver_device_platform(receiver_device_platform),
-      last_updated_age(last_updated_age),
       trace_id(trace_id),
       channel_type(channel_type),
       receiver_pulse_interval(receiver_pulse_interval) {}
diff --git a/chrome/browser/sharing/sharing_message_sender.h b/chrome/browser/sharing/sharing_message_sender.h
index 652b347..82ce0311 100644
--- a/chrome/browser/sharing/sharing_message_sender.h
+++ b/chrome/browser/sharing/sharing_message_sender.h
@@ -89,7 +89,6 @@
                         base::TimeTicks timestamp,
                         chrome_browser_sharing::MessageType type,
                         SharingDevicePlatform receiver_device_platform,
-                        base::TimeDelta last_updated_age,
                         int trace_id,
                         SharingChannelType channel_type,
                         base::TimeDelta receiver_pulse_interval);
@@ -101,7 +100,6 @@
     base::TimeTicks timestamp;
     chrome_browser_sharing::MessageType type;
     SharingDevicePlatform receiver_device_platform;
-    base::TimeDelta last_updated_age;
     int trace_id;
     SharingChannelType channel_type;
     base::TimeDelta receiver_pulse_interval;
diff --git a/chrome/browser/sharing/sharing_metrics.cc b/chrome/browser/sharing/sharing_metrics.cc
index 76912f1..dfbca18 100644
--- a/chrome/browser/sharing/sharing_metrics.cc
+++ b/chrome/browser/sharing/sharing_metrics.cc
@@ -287,55 +287,6 @@
       time_taken);
 }
 
-void LogSharingDeviceLastUpdatedAge(
-    chrome_browser_sharing::MessageType message_type,
-    base::TimeDelta age) {
-  constexpr char kBase[] = "Sharing.DeviceLastUpdatedAge";
-  int hours = age.InHours();
-  base::UmaHistogramCounts1000(kBase, hours);
-  base::UmaHistogramCounts1000(
-      base::StrCat({kBase, ".", SharingMessageTypeToString(message_type)}),
-      hours);
-}
-
-void LogSharingDeviceLastUpdatedAgeWithResult(SharingSendMessageResult result,
-                                              base::TimeDelta age) {
-  base::UmaHistogramCounts1000(
-      base::StrCat({"Sharing.DeviceLastUpdatedAgeWithResult.",
-                    SharingSendMessageResultToString(result)}),
-      age.InHours());
-}
-
-void LogSharingVersionComparison(
-    chrome_browser_sharing::MessageType message_type,
-    const std::string& receiver_version) {
-  int sender_major = 0;
-  base::StringToInt(version_info::GetMajorVersionNumber(), &sender_major);
-
-  // The |receiver_version| has optional modifiers e.g. "1.2.3.4 canary" so we
-  // do not parse it with base::Version.
-  int receiver_major = 0;
-  base::StringToInt(receiver_version, &receiver_major);
-
-  SharingMajorVersionComparison result;
-  if (sender_major == 0 || sender_major == INT_MIN || sender_major == INT_MAX ||
-      receiver_major == 0 || receiver_major == INT_MIN ||
-      receiver_major == INT_MAX) {
-    result = SharingMajorVersionComparison::kUnknown;
-  } else if (sender_major < receiver_major) {
-    result = SharingMajorVersionComparison::kSenderIsLower;
-  } else if (sender_major == receiver_major) {
-    result = SharingMajorVersionComparison::kSame;
-  } else {
-    result = SharingMajorVersionComparison::kSenderIsHigher;
-  }
-  constexpr char kBase[] = "Sharing.MajorVersionComparison";
-  base::UmaHistogramEnumeration(kBase, result);
-  base::UmaHistogramEnumeration(
-      base::StrCat({kBase, ".", SharingMessageTypeToString(message_type)}),
-      result);
-}
-
 void LogSharingDialogShown(SharingFeatureName feature, SharingDialogType type) {
   base::UmaHistogramEnumeration(
       base::StrCat({"Sharing.", GetEnumStringValue(feature), "DialogShown"}),
@@ -423,15 +374,6 @@
                                  size);
 }
 
-void LogSharedClipboardRetries(int retries, SharingSendMessageResult result) {
-  constexpr char kBase[] = "Sharing.SharedClipboardRetries";
-  base::UmaHistogramExactLinear(kBase, retries, /*value_max=*/20);
-  base::UmaHistogramExactLinear(
-      base::StrCat({kBase, ".", SharingSendMessageResultToString(result)}),
-      retries,
-      /*value_max=*/20);
-}
-
 void LogRemoteCopyHandleMessageResult(RemoteCopyHandleMessageResult result) {
   base::UmaHistogramEnumeration("Sharing.RemoteCopyHandleMessageResult",
                                 result);
@@ -480,7 +422,3 @@
   else
     base::UmaHistogramTimes("Sharing.RemoteCopyWriteTextDetectionTime", time);
 }
-
-void LogSharingDeviceInfoAvailable(bool available) {
-  base::UmaHistogramBoolean("Sharing.DeviceInfoAvailable", available);
-}
diff --git a/chrome/browser/sharing/sharing_metrics.h b/chrome/browser/sharing/sharing_metrics.h
index 2c6135e..f872429 100644
--- a/chrome/browser/sharing/sharing_metrics.h
+++ b/chrome/browser/sharing/sharing_metrics.h
@@ -107,26 +107,6 @@
     chrome_browser_sharing::MessageType message_type,
     base::TimeDelta time_taken);
 
-// Logs to UMA the number of hours since the target device timestamp was last
-// updated. Logged when a message is sent to the device.
-void LogSharingDeviceLastUpdatedAge(
-    chrome_browser_sharing::MessageType message_type,
-    base::TimeDelta age);
-
-// Logs to UMA the number of hours since the target device timestamp was last
-// updated. Logged when a message is sent to the device and the result is known.
-void LogSharingDeviceLastUpdatedAgeWithResult(SharingSendMessageResult result,
-                                              base::TimeDelta age);
-
-// Logs to UMA the comparison of the major version of Chrome on this
-// (the sender) device and the receiver device. Logged when a message is sent.
-// The |receiver_version| should be a dotted version number with optional
-// modifiers e.g. "1.2.3.4 canary" as generated by
-// version_info::GetVersionStringWithModifier.
-void LogSharingVersionComparison(
-    chrome_browser_sharing::MessageType message_type,
-    const std::string& receiver_version);
-
 // Logs to UMA the |type| of dialog shown for sharing feature.
 void LogSharingDialogShown(SharingFeatureName feature, SharingDialogType type);
 
@@ -149,9 +129,6 @@
 // Logs to UMA the size of the selected text for Shared Clipboard.
 void LogSharedClipboardSelectedTextSize(size_t text_size);
 
-// Logs to UMA the number of retries for sending a Shared Clipboard message.
-void LogSharedClipboardRetries(int retries, SharingSendMessageResult result);
-
 // Logs to UMA the result of handling a Remote Copy message.
 void LogRemoteCopyHandleMessageResult(RemoteCopyHandleMessageResult result);
 
@@ -182,7 +159,4 @@
 // Logs to UMA the time to detect a clipboard write for Remote Copy.
 void LogRemoteCopyWriteDetectionTime(base::TimeDelta time, bool is_image);
 
-// Logs to UMA if the DeviceInfo for a guid was available locally.
-void LogSharingDeviceInfoAvailable(bool available);
-
 #endif  // CHROME_BROWSER_SHARING_SHARING_METRICS_H_
diff --git a/chrome/browser/sharing/sharing_service_proxy_android.cc b/chrome/browser/sharing/sharing_service_proxy_android.cc
index 310cf1d..a6b2fcf 100644
--- a/chrome/browser/sharing/sharing_service_proxy_android.cc
+++ b/chrome/browser/sharing/sharing_service_proxy_android.cc
@@ -44,7 +44,6 @@
     JNIEnv* env,
     const base::android::JavaParamRef<jstring>& j_guid,
     const base::android::JavaParamRef<jstring>& j_text,
-    const jint j_retries,
     const base::android::JavaParamRef<jobject>& j_runnable) {
   auto callback =
       base::BindOnce(base::android::RunIntCallbackAndroid,
@@ -55,7 +54,6 @@
 
   std::unique_ptr<syncer::DeviceInfo> device =
       sharing_service_->GetDeviceByGuid(guid);
-  LogSharingDeviceInfoAvailable(device != nullptr);
 
   if (!device) {
     std::move(callback).Run(
@@ -71,14 +69,13 @@
       *device, base::TimeDelta::FromSeconds(kSharingMessageTTLSeconds.Get()),
       std::move(sharing_message),
       base::BindOnce(
-          [](int retries, base::OnceCallback<void(int)> callback,
+          [](base::OnceCallback<void(int)> callback,
              SharingSendMessageResult result,
              std::unique_ptr<chrome_browser_sharing::ResponseMessage>
                  response) {
-            LogSharedClipboardRetries(retries, result);
             std::move(callback).Run(static_cast<int>(result));
           },
-          j_retries, std::move(callback)));
+          std::move(callback)));
 }
 
 void SharingServiceProxyAndroid::GetDeviceCandidates(
diff --git a/chrome/browser/sharing/sharing_service_proxy_android.h b/chrome/browser/sharing/sharing_service_proxy_android.h
index 2c86753..81af31b 100644
--- a/chrome/browser/sharing/sharing_service_proxy_android.h
+++ b/chrome/browser/sharing/sharing_service_proxy_android.h
@@ -20,7 +20,6 @@
       JNIEnv* env,
       const base::android::JavaParamRef<jstring>& j_guid,
       const base::android::JavaParamRef<jstring>& j_text,
-      const jint j_retries,
       const base::android::JavaParamRef<jobject>& j_runnable);
 
   void GetDeviceCandidates(
diff --git a/chrome/browser/sharing/web_push/web_push_sender_unittest.cc b/chrome/browser/sharing/web_push/web_push_sender_unittest.cc
index af931c7..6f04570 100644
--- a/chrome/browser/sharing/web_push/web_push_sender_unittest.cc
+++ b/chrome/browser/sharing/web_push/web_push_sender_unittest.cc
@@ -141,7 +141,8 @@
       pendingRequest->request.request_body->elements();
   ASSERT_EQ(1UL, body_elements->size());
   const network::DataElement& body = body_elements->back();
-  EXPECT_EQ("payload", std::string(body.bytes(), body.length()));
+  ASSERT_EQ(network::DataElement::Tag::kBytes, body.type());
+  EXPECT_EQ("payload", body.As<network::DataElementBytes>().AsStringPiece());
 
   auto response_head = network::CreateURLResponseHead(net::HTTP_OK);
   response_head->headers->AddHeader("location",
diff --git a/chrome/browser/signin/dice_web_signin_interceptor.cc b/chrome/browser/signin/dice_web_signin_interceptor.cc
index a6e1c1dc..ce9d9bc 100644
--- a/chrome/browser/signin/dice_web_signin_interceptor.cc
+++ b/chrome/browser/signin/dice_web_signin_interceptor.cc
@@ -88,11 +88,35 @@
   return chrome::FindBrowserWithWebContents(web_contents) == nullptr;
 }
 
-bool GuestOptionAvailable() {
-  return Profile::IsEphemeralGuestProfileEnabled() &&
-         !ProfileManager::GuestProfileExists() &&
-         g_browser_process->local_state()->GetBoolean(
-             prefs::kBrowserGuestModeEnabled);
+// Different conditions which make Guest option available or not.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class SigninInterceptGuestAvailability {
+  kAvailable = 0,
+  kGuestAlreadyOpen = 1,
+  kGuestBlocked = 2,
+  kEphemeralGuestDisabled = 3,
+  kMaxValue = kEphemeralGuestDisabled
+};
+
+SigninInterceptGuestAvailability GetGuestOptionAvailablity() {
+  if (!Profile::IsEphemeralGuestProfileEnabled())
+    return SigninInterceptGuestAvailability::kEphemeralGuestDisabled;
+
+  if (ProfileManager::GuestProfileExists())
+    return SigninInterceptGuestAvailability::kGuestAlreadyOpen;
+
+  if (!g_browser_process->local_state()->GetBoolean(
+          prefs::kBrowserGuestModeEnabled)) {
+    return SigninInterceptGuestAvailability::kGuestBlocked;
+  }
+  return SigninInterceptGuestAvailability::kAvailable;
+}
+
+void RecordGuestOptionAvailablity(
+    SigninInterceptGuestAvailability availability) {
+  base::UmaHistogramEnumeration("Signin.Intercept.Guest.Availability",
+                                availability);
 }
 
 }  // namespace
@@ -407,10 +431,12 @@
       ->GetProfileAttributesStorage()
       .GetProfileAttributesWithPath(profile_->GetPath(), &entry);
   SkColor profile_color = GenerateNewProfileColor(entry).color;
+  auto guest_option_availability = GetGuestOptionAvailablity();
   Delegate::BubbleParameters bubble_parameters{
       *interception_type, info, GetPrimaryAccountInfo(identity_manager_),
       GetAutogeneratedThemeColors(profile_color).frame_color,
-      GuestOptionAvailable()};
+      guest_option_availability ==
+          SigninInterceptGuestAvailability::kAvailable};
   interception_bubble_handle_ = delegate_->ShowSigninInterceptionBubble(
       web_contents(), bubble_parameters,
       base::BindOnce(&DiceWebSigninInterceptor::OnProfileCreationChoice,
@@ -420,6 +446,7 @@
       *interception_type == SigninInterceptionType::kEnterprise
           ? SigninInterceptionHeuristicOutcome::kInterceptEnterprise
           : SigninInterceptionHeuristicOutcome::kInterceptMultiUser);
+  RecordGuestOptionAvailablity(guest_option_availability);
 }
 
 void DiceWebSigninInterceptor::OnExtendedAccountInfoFetchTimeout() {
diff --git a/chrome/browser/signin/ui/android/BUILD.gn b/chrome/browser/signin/ui/android/BUILD.gn
index 787e962d..638b7ef 100644
--- a/chrome/browser/signin/ui/android/BUILD.gn
+++ b/chrome/browser/signin/ui/android/BUILD.gn
@@ -9,10 +9,14 @@
     ":java_resources",
     "//base:base_java",
     "//chrome/browser/consent_auditor/android:java",
+    "//chrome/browser/feedback/android:java",
     "//chrome/browser/flags:java",
+    "//chrome/browser/incognito/interstitial/android:java",
     "//chrome/browser/preferences:java",
     "//chrome/browser/profiles/android:java",
     "//chrome/browser/signin/services/android:java",
+    "//chrome/browser/tabmodel:java",
+    "//components/browser_ui/android/bottomsheet:java",
     "//components/browser_ui/settings/android:java",
     "//components/browser_ui/widget/android:java",
     "//components/embedder_support/android:util_java",
@@ -42,6 +46,11 @@
     "java/src/org/chromium/chrome/browser/signin/ui/SigninPromoController.java",
     "java/src/org/chromium/chrome/browser/signin/ui/SigninScrollView.java",
     "java/src/org/chromium/chrome/browser/signin/ui/SigninView.java",
+    "java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetCoordinator.java",
+    "java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetMediator.java",
+    "java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetProperties.java",
+    "java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetView.java",
+    "java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetViewBinder.java",
     "java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerCoordinator.java",
     "java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerDelegate.java",
     "java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerDialogFragment.java",
@@ -61,12 +70,22 @@
     "java/res/drawable-xhdpi/chrome_sync_logo.png",
     "java/res/drawable-xxhdpi/chrome_sync_logo.png",
     "java/res/drawable-xxxhdpi/chrome_sync_logo.png",
+    "java/res/drawable/ic_expand_more_in_circle_24dp.xml",
+    "java/res/layout/account_picker_bottom_sheet_continue_button.xml",
+    "java/res/layout/account_picker_bottom_sheet_header.xml",
+    "java/res/layout/account_picker_bottom_sheet_view.xml",
     "java/res/layout/account_picker_dialog_body.xml",
     "java/res/layout/account_picker_incognito_row.xml",
     "java/res/layout/account_picker_new_account_row.xml",
     "java/res/layout/account_picker_new_account_row_legacy.xml",
     "java/res/layout/account_picker_row.xml",
     "java/res/layout/account_picker_row_legacy.xml",
+    "java/res/layout/account_picker_state_auth_error.xml",
+    "java/res/layout/account_picker_state_collapsed.xml",
+    "java/res/layout/account_picker_state_expanded.xml",
+    "java/res/layout/account_picker_state_general_error.xml",
+    "java/res/layout/account_picker_state_no_account.xml",
+    "java/res/layout/account_picker_state_signin_in_progress.xml",
     "java/res/layout/confirm_import_sync_data.xml",
     "java/res/layout/personalized_signin_promo_view_body.xml",
     "java/res/layout/personalized_signin_promo_view_bookmarks.xml",
@@ -80,6 +99,7 @@
     "java/res/values/dimens.xml",
   ]
   deps = [
+    "//chrome/browser/incognito/interstitial/android:java_resources",
     "//chrome/browser/signin/services/android:java_resources",
     "//chrome/browser/ui/android/strings:ui_strings_grd",
     "//components/browser_ui/strings/android:browser_ui_strings_grd",
diff --git a/chrome/browser/signin/ui/android/DEPS b/chrome/browser/signin/ui/android/DEPS
new file mode 100644
index 0000000..7295e24
--- /dev/null
+++ b/chrome/browser/signin/ui/android/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+components/browser_ui/android/bottomsheet",
+]
diff --git a/chrome/android/java/res/drawable/ic_expand_more_in_circle_24dp.xml b/chrome/browser/signin/ui/android/java/res/drawable/ic_expand_more_in_circle_24dp.xml
similarity index 100%
rename from chrome/android/java/res/drawable/ic_expand_more_in_circle_24dp.xml
rename to chrome/browser/signin/ui/android/java/res/drawable/ic_expand_more_in_circle_24dp.xml
diff --git a/chrome/android/java/res/layout/account_picker_bottom_sheet_continue_button.xml b/chrome/browser/signin/ui/android/java/res/layout/account_picker_bottom_sheet_continue_button.xml
similarity index 100%
rename from chrome/android/java/res/layout/account_picker_bottom_sheet_continue_button.xml
rename to chrome/browser/signin/ui/android/java/res/layout/account_picker_bottom_sheet_continue_button.xml
diff --git a/chrome/android/java/res/layout/account_picker_bottom_sheet_header.xml b/chrome/browser/signin/ui/android/java/res/layout/account_picker_bottom_sheet_header.xml
similarity index 100%
rename from chrome/android/java/res/layout/account_picker_bottom_sheet_header.xml
rename to chrome/browser/signin/ui/android/java/res/layout/account_picker_bottom_sheet_header.xml
diff --git a/chrome/android/java/res/layout/account_picker_bottom_sheet_view.xml b/chrome/browser/signin/ui/android/java/res/layout/account_picker_bottom_sheet_view.xml
similarity index 100%
rename from chrome/android/java/res/layout/account_picker_bottom_sheet_view.xml
rename to chrome/browser/signin/ui/android/java/res/layout/account_picker_bottom_sheet_view.xml
diff --git a/chrome/android/java/res/layout/account_picker_state_auth_error.xml b/chrome/browser/signin/ui/android/java/res/layout/account_picker_state_auth_error.xml
similarity index 100%
rename from chrome/android/java/res/layout/account_picker_state_auth_error.xml
rename to chrome/browser/signin/ui/android/java/res/layout/account_picker_state_auth_error.xml
diff --git a/chrome/android/java/res/layout/account_picker_state_collapsed.xml b/chrome/browser/signin/ui/android/java/res/layout/account_picker_state_collapsed.xml
similarity index 100%
rename from chrome/android/java/res/layout/account_picker_state_collapsed.xml
rename to chrome/browser/signin/ui/android/java/res/layout/account_picker_state_collapsed.xml
diff --git a/chrome/android/java/res/layout/account_picker_state_expanded.xml b/chrome/browser/signin/ui/android/java/res/layout/account_picker_state_expanded.xml
similarity index 100%
rename from chrome/android/java/res/layout/account_picker_state_expanded.xml
rename to chrome/browser/signin/ui/android/java/res/layout/account_picker_state_expanded.xml
diff --git a/chrome/android/java/res/layout/account_picker_state_general_error.xml b/chrome/browser/signin/ui/android/java/res/layout/account_picker_state_general_error.xml
similarity index 100%
rename from chrome/android/java/res/layout/account_picker_state_general_error.xml
rename to chrome/browser/signin/ui/android/java/res/layout/account_picker_state_general_error.xml
diff --git a/chrome/android/java/res/layout/account_picker_state_no_account.xml b/chrome/browser/signin/ui/android/java/res/layout/account_picker_state_no_account.xml
similarity index 100%
rename from chrome/android/java/res/layout/account_picker_state_no_account.xml
rename to chrome/browser/signin/ui/android/java/res/layout/account_picker_state_no_account.xml
diff --git a/chrome/android/java/res/layout/account_picker_state_signin_in_progress.xml b/chrome/browser/signin/ui/android/java/res/layout/account_picker_state_signin_in_progress.xml
similarity index 100%
rename from chrome/android/java/res/layout/account_picker_state_signin_in_progress.xml
rename to chrome/browser/signin/ui/android/java/res/layout/account_picker_state_signin_in_progress.xml
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetCoordinator.java b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetCoordinator.java
similarity index 95%
rename from chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetCoordinator.java
rename to chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetCoordinator.java
index 63e0ad0..04446a7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetCoordinator.java
+++ b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetCoordinator.java
@@ -2,7 +2,7 @@
 // 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.signin.account_picker;
+package org.chromium.chrome.browser.signin.ui.account_picker;
 
 import android.app.Activity;
 import android.view.View;
@@ -15,8 +15,6 @@
 import org.chromium.chrome.browser.incognito.interstitial.IncognitoInterstitialDelegate;
 import org.chromium.chrome.browser.signin.services.SigninMetricsUtils;
 import org.chromium.chrome.browser.signin.services.SigninPreferencesManager;
-import org.chromium.chrome.browser.signin.ui.account_picker.AccountPickerCoordinator;
-import org.chromium.chrome.browser.signin.ui.account_picker.AccountPickerDelegate;
 import org.chromium.chrome.browser.tabmodel.TabCreator;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetMediator.java b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetMediator.java
similarity index 97%
rename from chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetMediator.java
rename to chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetMediator.java
index 90811afd..0d62dd6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetMediator.java
+++ b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetMediator.java
@@ -2,7 +2,7 @@
 // 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.signin.account_picker;
+package org.chromium.chrome.browser.signin.ui.account_picker;
 
 import android.accounts.Account;
 import android.content.Context;
@@ -12,12 +12,10 @@
 import androidx.annotation.Nullable;
 
 import org.chromium.base.task.AsyncTask;
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.signin.account_picker.AccountPickerBottomSheetProperties.ViewState;
 import org.chromium.chrome.browser.signin.services.ProfileDataCache;
 import org.chromium.chrome.browser.signin.services.SigninMetricsUtils;
-import org.chromium.chrome.browser.signin.ui.account_picker.AccountPickerCoordinator;
-import org.chromium.chrome.browser.signin.ui.account_picker.AccountPickerDelegate;
+import org.chromium.chrome.browser.signin.ui.R;
+import org.chromium.chrome.browser.signin.ui.account_picker.AccountPickerBottomSheetProperties.ViewState;
 import org.chromium.components.signin.AccountManagerFacade;
 import org.chromium.components.signin.AccountManagerFacadeProvider;
 import org.chromium.components.signin.AccountUtils;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetProperties.java b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetProperties.java
similarity index 98%
rename from chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetProperties.java
rename to chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetProperties.java
index 3b050c0..6ab9eba 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetProperties.java
+++ b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetProperties.java
@@ -2,7 +2,7 @@
 // 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.signin.account_picker;
+package org.chromium.chrome.browser.signin.ui.account_picker;
 
 import android.view.View.OnClickListener;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetView.java b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetView.java
similarity index 96%
rename from chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetView.java
rename to chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetView.java
index 12d4f873..94d31da 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetView.java
+++ b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetView.java
@@ -2,7 +2,7 @@
 // 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.signin.account_picker;
+package org.chromium.chrome.browser.signin.ui.account_picker;
 
 import android.app.Activity;
 import android.view.LayoutInflater;
@@ -18,11 +18,9 @@
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
 
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.signin.account_picker.AccountPickerBottomSheetProperties.ViewState;
 import org.chromium.chrome.browser.signin.services.DisplayableProfileData;
-import org.chromium.chrome.browser.signin.ui.account_picker.AccountPickerFeatureUtils;
-import org.chromium.chrome.browser.signin.ui.account_picker.ExistingAccountRowViewBinder;
+import org.chromium.chrome.browser.signin.ui.R;
+import org.chromium.chrome.browser.signin.ui.account_picker.AccountPickerBottomSheetProperties.ViewState;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;
 import org.chromium.ui.widget.ButtonCompat;
 
@@ -170,7 +168,6 @@
         continueButton.setText(continueAsButtonText);
     }
 
-
     @Override
     public View getContentView() {
         return mContentView;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetViewBinder.java b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetViewBinder.java
similarity index 91%
rename from chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetViewBinder.java
rename to chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetViewBinder.java
index 63fd12f..be36425 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetViewBinder.java
+++ b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetViewBinder.java
@@ -2,10 +2,10 @@
 // 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.signin.account_picker;
+package org.chromium.chrome.browser.signin.ui.account_picker;
 
-import org.chromium.chrome.browser.signin.account_picker.AccountPickerBottomSheetProperties.ViewState;
 import org.chromium.chrome.browser.signin.services.DisplayableProfileData;
+import org.chromium.chrome.browser.signin.ui.account_picker.AccountPickerBottomSheetProperties.ViewState;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
 
diff --git a/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerCoordinator.java b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerCoordinator.java
index 794c45e..730b258 100644
--- a/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerCoordinator.java
+++ b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerCoordinator.java
@@ -57,9 +57,8 @@
      *                 account.
      * @param selectedAccountName The name of the account that should be marked as selected.
      * @param showIncognitoRow whether to show the incognito row in the account picker.
-     * TODO(crbug/1155123): Change this method to package private after modularization.
      */
-    public AccountPickerCoordinator(RecyclerView view, Listener listener,
+    AccountPickerCoordinator(RecyclerView view, Listener listener,
             @Nullable String selectedAccountName, boolean showIncognitoRow) {
         assert listener != null : "The argument AccountPickerCoordinator.Listener cannot be null!";
 
@@ -90,9 +89,8 @@
 
     /**
      * Destroys the resources used by the coordinator.
-     * TODO(crbug/1155123): Change this method to package private after modularization.
      */
-    public void destroy() {
+    void destroy() {
         mMediator.destroy();
     }
 
diff --git a/chrome/browser/subresource_filter/subresource_filter_browsertest.cc b/chrome/browser/subresource_filter/subresource_filter_browsertest.cc
index 41a8607b..ea4de6c2 100644
--- a/chrome/browser/subresource_filter/subresource_filter_browsertest.cc
+++ b/chrome/browser/subresource_filter/subresource_filter_browsertest.cc
@@ -370,7 +370,7 @@
   proto::UrlRule rule = testing::CreateSuffixRule("included_script.html");
   proto::UrlRule allowlist_rule = testing::CreateSuffixRule(kAllowlistedDomain);
   allowlist_rule.set_anchor_right(proto::ANCHOR_TYPE_NONE);
-  allowlist_rule.set_semantics(proto::RULE_SEMANTICS_WHITELIST);
+  allowlist_rule.set_semantics(proto::RULE_SEMANTICS_ALLOWLIST);
   ASSERT_NO_FATAL_FAILURE(SetRulesetWithRules({rule, allowlist_rule}));
 
   ui_test_utils::NavigateToURL(browser(), url);
diff --git a/chrome/browser/sync/test/integration/single_client_sync_invalidations_test.cc b/chrome/browser/sync/test/integration/single_client_sync_invalidations_test.cc
index f048331..fbc3aa8 100644
--- a/chrome/browser/sync/test/integration/single_client_sync_invalidations_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_sync_invalidations_test.cc
@@ -11,17 +11,23 @@
 #include "chrome/browser/sync/test/integration/sync_test.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/sync/base/model_type.h"
+#include "components/sync/base/time.h"
 #include "components/sync/invalidations/switches.h"
 #include "components/sync/invalidations/sync_invalidations_service.h"
 #include "components/sync/protocol/sync.pb.h"
 #include "components/sync/test/fake_server/bookmark_entity_builder.h"
 #include "components/sync/test/fake_server/entity_builder_factory.h"
+#include "components/sync_device_info/device_info_util.h"
 #include "content/public/test/browser_test.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
 
+using bookmarks::BookmarkNode;
+using bookmarks_helper::AddFolder;
+using bookmarks_helper::GetBookmarkBarNode;
+using bookmarks_helper::ServerBookmarksEqualityChecker;
 using testing::AllOf;
 using testing::ElementsAre;
 using testing::Not;
@@ -76,6 +82,23 @@
              .instance_id_token() == expected_token;
 }
 
+sync_pb::DeviceInfoSpecifics CreateDeviceInfoSpecifics(
+    const std::string& cache_guid,
+    const std::string& fcm_registration_token) {
+  sync_pb::DeviceInfoSpecifics specifics;
+  specifics.set_cache_guid(cache_guid);
+  specifics.set_client_name("client name");
+  specifics.set_device_type(sync_pb::SyncEnums_DeviceType_TYPE_LINUX);
+  specifics.set_sync_user_agent("user agent");
+  specifics.set_chrome_version("chrome version");
+  specifics.set_signin_scoped_device_id("scoped device id");
+  specifics.set_last_updated_timestamp(
+      syncer::TimeToProtoTime(base::Time::Now()));
+  specifics.mutable_invalidation_fields()->set_instance_id_token(
+      fcm_registration_token);
+  return specifics;
+}
+
 class SingleClientWithSyncSendInterestedDataTypesTest : public SyncTest {
  public:
   SingleClientWithSyncSendInterestedDataTypesTest() : SyncTest(SINGLE_CLIENT) {
@@ -134,6 +157,24 @@
   }
   ~SingleClientWithUseSyncInvalidationsTest() override = default;
 
+  // Injects a test DeviceInfo entity to the fake server.
+  void InjectDeviceInfoEntityToServer(
+      const std::string& cache_guid,
+      const std::string& fcm_registration_token) {
+    sync_pb::EntitySpecifics specifics;
+    *specifics.mutable_device_info() =
+        CreateDeviceInfoSpecifics(cache_guid, fcm_registration_token);
+    GetFakeServer()->InjectEntity(
+        syncer::PersistentUniqueClientEntity::CreateFromSpecificsForTesting(
+            /*non_unique_name=*/"",
+            /*client_tag=*/
+            syncer::DeviceInfoUtil::SpecificsToTag(specifics.device_info()),
+            specifics,
+            /*creation_time=*/specifics.device_info().last_updated_timestamp(),
+            /*last_modified_time=*/
+            specifics.device_info().last_updated_timestamp()));
+  }
+
  private:
   base::test::ScopedFeatureList override_features_;
 
@@ -172,6 +213,33 @@
           .Wait());
 }
 
+IN_PROC_BROWSER_TEST_F(SingleClientWithUseSyncInvalidationsTest,
+                       ShouldPopulateFCMRegistrationTokens) {
+  const std::string kTitle = "title";
+  const std::string kRemoteDeviceCacheGuid = "other_cache_guid";
+  const std::string kRemoteFCMRegistrationToken = "other_fcm_token";
+
+  // Simulate the case when the server already knows one other device.
+  InjectDeviceInfoEntityToServer(kRemoteDeviceCacheGuid,
+                                 kRemoteFCMRegistrationToken);
+  ASSERT_TRUE(SetupSync());
+
+  // Commit a new bookmark to check if the next commit message has FCM
+  // registration tokens.
+  AddFolder(0, GetBookmarkBarNode(0), 0, kTitle);
+  ASSERT_TRUE(ServerBookmarksEqualityChecker(GetSyncService(0), GetFakeServer(),
+                                             {{kTitle, GURL()}},
+                                             /*cryptographer=*/nullptr)
+                  .Wait());
+
+  sync_pb::ClientToServerMessage message;
+  GetFakeServer()->GetLastCommitMessage(&message);
+
+  EXPECT_THAT(
+      message.commit().config_params().devices_fcm_registration_tokens(),
+      ElementsAre(kRemoteFCMRegistrationToken));
+}
+
 class SingleClientWithUseSyncInvalidationsForWalletAndOfferTest
     : public SyncTest {
  public:
diff --git a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
index e5ee3d8..0f26dd3 100644
--- a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
@@ -665,11 +665,11 @@
   autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
   std::vector<CreditCard*> cards = pdm->GetCreditCards();
   ASSERT_EQ(1uL, cards.size());
-  pdm->RecordUseOf(*cards[0]);
+  pdm->RecordUseOf(cards[0]);
   std::vector<AutofillProfile*> profiles = pdm->GetServerProfiles();
   ASSERT_EQ(1uL, profiles.size());
   // TODO(crbug.com/941498): Server profiles are not recorded.
-  pdm->RecordUseOf(*profiles[0]);
+  pdm->RecordUseOf(profiles[0]);
 
   // Keep the same data (only change the customer data and the cloud token to
   // force the FakeServer to send the full update).
@@ -723,11 +723,11 @@
   autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
   std::vector<CreditCard*> cards = pdm->GetCreditCards();
   ASSERT_EQ(1uL, cards.size());
-  pdm->RecordUseOf(*cards[0]);
+  pdm->RecordUseOf(cards[0]);
   std::vector<AutofillProfile*> profiles = pdm->GetServerProfiles();
   ASSERT_EQ(1uL, profiles.size());
   // TODO(crbug.com/941498): Server profiles are not recorded.
-  pdm->RecordUseOf(*profiles[0]);
+  pdm->RecordUseOf(profiles[0]);
 
   // Update the data (also change the customer data to force the full update as
   // FakeServer computes the hash for progress markers only based on ids). For
diff --git a/chrome/browser/sync/test/integration/two_client_send_tab_to_self_sync_test.cc b/chrome/browser/sync/test/integration/two_client_send_tab_to_self_sync_test.cc
index 919bfe0..a7dc2cd 100644
--- a/chrome/browser/sync/test/integration/two_client_send_tab_to_self_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_send_tab_to_self_sync_test.cc
@@ -298,9 +298,16 @@
 
 // Non-primary accounts don't exist on ChromeOS.
 #if !BUILDFLAG(IS_CHROMEOS_ASH)
+// TODO(crbug.com/1166032): Test times out in component builds.
+#if defined(COMPONENT_BUILD)
+#define MAYBE_SignedInClientCanReceive DISABLED_SignedInClientCanReceive
+#else
+#define MAYBE_SignedInClientCanReceive SignedInClientCanReceive
+#endif
+
 IN_PROC_BROWSER_TEST_F(
     TwoClientSendTabToSelfSyncTestWithSendTabToSelfWhenSignedIn,
-    SignedInClientCanReceive) {
+    MAYBE_SignedInClientCanReceive) {
   ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
 
   // Set up one client syncing and the other signed-in but not syncing.
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
index 8e22eac..0492b39 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
+++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -794,6 +794,9 @@
       <message name="IDS_PRIVACY_SANDBOX_BULLET_TWO" desc="Second bullet point of the Privacy Sandbox description">
         Allow advertisers to study ad campaigns using non-identifiable information.
       </message>
+      <message name="IDS_PRIVACY_SANDBOX_SNACKBAR_MESSAGE" desc="The text displayed in the snackbar, which gives the user an option to navigate to the Privacy Sandbox settings page. 'Privacy sandbox' has TC ID 5753235213964358658.">
+        Explore the Privacy Sandbox
+      </message>
 
       <!-- Secure DNS Settings.  Used by //chrome/browser/privacy. -->
       <message name="IDS_SETTINGS_CUSTOM" desc="Label for a custom option in a dropdown menu.">
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_SNACKBAR_MESSAGE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_SNACKBAR_MESSAGE.png.sha1
new file mode 100644
index 0000000..c29b854
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRIVACY_SANDBOX_SNACKBAR_MESSAGE.png.sha1
@@ -0,0 +1 @@
+24e8a92900ea2105ed92dc6e33104e7c45401f64
\ No newline at end of file
diff --git a/chrome/browser/ui/app_list/app_service/app_service_app_icon_loader.cc b/chrome/browser/ui/app_list/app_service/app_service_app_icon_loader.cc
index 9e3ab1d..f64124d 100644
--- a/chrome/browser/ui/app_list/app_service/app_service_app_icon_loader.cc
+++ b/chrome/browser/ui/app_list/app_service/app_service_app_icon_loader.cc
@@ -32,33 +32,6 @@
 
 }  // namespace
 
-// static
-bool AppServiceAppIconLoader::CanLoadImage(Profile* profile,
-                                           const std::string& id) {
-  const std::string app_id = GetAppId(profile, id);
-
-  // Skip the ARC intent helper, the system Android app that proxies links to
-  // Chrome, which should be hidden.
-  if (app_id == kArcIntentHelperAppId) {
-    return false;
-  }
-
-  if (!apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(profile)) {
-    return false;
-  }
-
-  // Support icon loading for apps registered in AppService or Crostini apps
-  // with the prefix "crostini:".
-  if (apps::AppServiceProxyFactory::GetForProfile(profile)
-              ->AppRegistryCache()
-              .GetAppType(app_id) != apps::mojom::AppType::kUnknown ||
-      crostini::IsUnmatchedCrostiniShelfAppId(app_id)) {
-    return true;
-  }
-
-  return false;
-}
-
 AppServiceAppIconLoader::AppServiceAppIconLoader(
     Profile* profile,
     int resource_size_in_dip,
@@ -72,7 +45,26 @@
 AppServiceAppIconLoader::~AppServiceAppIconLoader() = default;
 
 bool AppServiceAppIconLoader::CanLoadImageForApp(const std::string& id) {
-  return AppServiceAppIconLoader::CanLoadImage(profile(), id);
+  const std::string app_id = GetAppId(profile(), id);
+
+  // Skip the ARC intent helper, the system Android app that proxies links to
+  // Chrome, which should be hidden.
+  if (app_id == kArcIntentHelperAppId) {
+    return false;
+  }
+
+  apps::AppServiceProxy* proxy =
+      apps::AppServiceProxyFactory::GetForProfile(profile());
+
+  // Support icon loading for apps registered in AppService or Crostini apps
+  // with the prefix "crostini:".
+  if (proxy->AppRegistryCache().GetAppType(app_id) !=
+          apps::mojom::AppType::kUnknown ||
+      crostini::IsUnmatchedCrostiniShelfAppId(app_id)) {
+    return true;
+  }
+
+  return false;
 }
 
 void AppServiceAppIconLoader::FetchImage(const std::string& id) {
diff --git a/chrome/browser/ui/app_list/app_service/app_service_app_icon_loader.h b/chrome/browser/ui/app_list/app_service/app_service_app_icon_loader.h
index 9d8f75a..7996b07 100644
--- a/chrome/browser/ui/app_list/app_service/app_service_app_icon_loader.h
+++ b/chrome/browser/ui/app_list/app_service/app_service_app_icon_loader.h
@@ -22,8 +22,6 @@
 class AppServiceAppIconLoader : public AppIconLoader,
                                 private apps::AppRegistryCache::Observer {
  public:
-  static bool CanLoadImage(Profile* profile, const std::string& id);
-
   AppServiceAppIconLoader(Profile* profile,
                           int resource_size_in_dip,
                           AppIconLoaderDelegate* delegate);
diff --git a/chrome/browser/ui/ash/clipboard_history_browsertest.cc b/chrome/browser/ui/ash/clipboard_history_browsertest.cc
index a19005a..a613cd2 100644
--- a/chrome/browser/ui/ash/clipboard_history_browsertest.cc
+++ b/chrome/browser/ui/ash/clipboard_history_browsertest.cc
@@ -806,9 +806,9 @@
            (*data_src->origin() == allowed_origin_);
   }
 
-  bool IsDragDropAllowed(
-      const ui::DataTransferEndpoint* const data_src,
-      const ui::DataTransferEndpoint* const data_dst) override {
+  bool IsDragDropAllowed(const ui::DataTransferEndpoint* const data_src,
+                         const ui::DataTransferEndpoint* const data_dst,
+                         const bool is_drop) override {
     return false;
   }
 
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
index 76e39e6..91dd75d 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -39,7 +39,6 @@
 #include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
 #include "chrome/browser/ui/app_list/app_service/app_service_app_icon_loader.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
-#include "chrome/browser/ui/app_list/icon_standardizer.h"
 #include "chrome/browser/ui/app_list/md_icon_normalizer.h"
 #include "chrome/browser/ui/apps/app_info_dialog.h"
 #include "chrome/browser/ui/ash/chrome_launcher_prefs.h"
@@ -929,10 +928,6 @@
 
 void ChromeLauncherController::OnAppImageUpdated(const std::string& app_id,
                                                  const gfx::ImageSkia& image) {
-  bool is_standard_icon = true;
-  if (!AppServiceAppIconLoader::CanLoadImage(latest_active_profile_, app_id))
-    is_standard_icon = false;
-
   // TODO: need to get this working for shortcuts.
   for (int index = 0; index < model_->item_count(); ++index) {
     ash::ShelfItem item = model_->items()[index];
@@ -941,8 +936,7 @@
         item.id.app_id != app_id) {
       continue;
     }
-    item.image =
-        is_standard_icon ? image : app_list::CreateStandardIconImage(image);
+    item.image = image;
     shelf_spinner_controller_->MaybeApplySpinningEffect(app_id, &item.image);
     model_->Set(index, item);
     // It's possible we're waiting on more than one item, so don't break.
diff --git a/chrome/browser/ui/ash/media_client_impl.cc b/chrome/browser/ui/ash/media_client_impl.cc
index 4386052..d172202a 100644
--- a/chrome/browser/ui/ash/media_client_impl.cc
+++ b/chrome/browser/ui/ash/media_client_impl.cc
@@ -313,8 +313,12 @@
     vm_media_capture_state_ |= MediaCaptureState::kAudio;
 
   media_controller_->NotifyVmMediaNotificationState(
-      manager->IsNotificationActive(DeviceType::kCamera),
-      manager->IsNotificationActive(DeviceType::kMic));
+      manager->IsNotificationActive(
+          chromeos::VmCameraMicManager::kCameraNotification),
+      manager->IsNotificationActive(
+          chromeos::VmCameraMicManager::kMicNotification),
+      manager->IsNotificationActive(
+          chromeos::VmCameraMicManager::kCameraAndMicNotification));
 }
 
 void MediaClientImpl::OnCameraPrivacySwitchStatusChanged(
diff --git a/chrome/browser/ui/ash/media_client_impl_unittest.cc b/chrome/browser/ui/ash/media_client_impl_unittest.cc
index 771dc06..dc86acb 100644
--- a/chrome/browser/ui/ash/media_client_impl_unittest.cc
+++ b/chrome/browser/ui/ash/media_client_impl_unittest.cc
@@ -30,7 +30,9 @@
       const base::flat_map<AccountId, ash::MediaCaptureState>& capture_states)
       override {}
 
-  void NotifyVmMediaNotificationState(bool camera, bool mic) override {}
+  void NotifyVmMediaNotificationState(bool camera,
+                                      bool mic,
+                                      bool camera_and_mic) override {}
 
   bool force_media_client_key_handling() const {
     return force_media_client_key_handling_;
diff --git a/chrome/browser/ui/messages/android/java/src/org/chromium/chrome/browser/ui/messages/snackbar/Snackbar.java b/chrome/browser/ui/messages/android/java/src/org/chromium/chrome/browser/ui/messages/snackbar/Snackbar.java
index 6349c3b..9e1a86e 100644
--- a/chrome/browser/ui/messages/android/java/src/org/chromium/chrome/browser/ui/messages/snackbar/Snackbar.java
+++ b/chrome/browser/ui/messages/android/java/src/org/chromium/chrome/browser/ui/messages/snackbar/Snackbar.java
@@ -90,6 +90,7 @@
     public static final int UMA_CONDITIONAL_TAB_STRIP_DISMISS_UNDO = 35;
     public static final int UMA_PAINT_PREVIEW_UPGRADE_NOTIFICATION = 36;
     public static final int UMA_READING_LIST_BOOKMARK_ADDED = 37;
+    public static final int UMA_PRIVACY_SANDBOX_PAGE_OPEN = 38;
 
     private SnackbarController mController;
     private CharSequence mText;
diff --git a/chrome/browser/ui/search/ntp_user_data_logger.cc b/chrome/browser/ui/search/ntp_user_data_logger.cc
index 4fec69b..10e963f 100644
--- a/chrome/browser/ui/search/ntp_user_data_logger.cc
+++ b/chrome/browser/ui/search/ntp_user_data_logger.cc
@@ -578,11 +578,17 @@
 }
 
 void NTPUserDataLogger::LogModuleLoaded(const std::string& id,
-                                        base::TimeDelta time) {
-  UMA_HISTOGRAM_LOAD_TIME("NewTabPage.Modules.Loaded", time);
-  base::UmaHistogramCustomTimes("NewTabPage.Modules.Loaded." + id, time,
+                                        base::TimeDelta duration,
+                                        base::TimeDelta time_since_navigation) {
+  UMA_HISTOGRAM_LOAD_TIME("NewTabPage.Modules.Loaded", time_since_navigation);
+  base::UmaHistogramCustomTimes("NewTabPage.Modules.Loaded." + id,
+                                time_since_navigation,
                                 base::TimeDelta::FromMilliseconds(1),
                                 base::TimeDelta::FromSeconds(60), 100);
+  UMA_HISTOGRAM_LOAD_TIME("NewTabPage.Modules.LoadDuration", duration);
+  base::UmaHistogramCustomTimes("NewTabPage.Modules.LoadDuration." + id,
+                                duration, base::TimeDelta::FromMilliseconds(1),
+                                base::TimeDelta::FromSeconds(60), 100);
 }
 
 void NTPUserDataLogger::LogModuleUsage(const std::string& id) {
diff --git a/chrome/browser/ui/search/ntp_user_data_logger.h b/chrome/browser/ui/search/ntp_user_data_logger.h
index b98fd5f..db352a6 100644
--- a/chrome/browser/ui/search/ntp_user_data_logger.h
+++ b/chrome/browser/ui/search/ntp_user_data_logger.h
@@ -45,7 +45,9 @@
   void LogModuleImpression(const std::string& id, base::TimeDelta time);
 
   // Logs a module is loaded on the NTP.
-  void LogModuleLoaded(const std::string& id, base::TimeDelta time);
+  void LogModuleLoaded(const std::string& id,
+                       base::TimeDelta duration,
+                       base::TimeDelta time_since_navigation);
 
   // Logs when a user interacts with a module which will result in a navigation.
   void LogModuleUsage(const std::string& id);
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 f109afb..af800f70 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
@@ -400,6 +400,12 @@
   ShowAndVerifyUi();
 }
 
+// crbug.com/1166152
+#if defined(OS_WIN)
+#define MAYBE_InvokeUi_ManyPermissions DISABLED_InvokeUi_ManyPermissions
+#else
+#define MAYBE_InvokeUi_ManyPermissions InvokeUi_ManyPermissions
+#endif
 IN_PROC_BROWSER_TEST_F(ExtensionInstallDialogViewInteractiveBrowserTest,
                        InvokeUi_ManyPermissions) {
   for (int i = 0; i < 20; i++)
diff --git a/chrome/browser/ui/views/hung_renderer_view.cc b/chrome/browser/ui/views/hung_renderer_view.cc
index febf843..4ce7d12 100644
--- a/chrome/browser/ui/views/hung_renderer_view.cc
+++ b/chrome/browser/ui/views/hung_renderer_view.cc
@@ -80,8 +80,8 @@
   DCHECK(!hang_monitor_restarter.is_null());
 
   DCHECK(!render_widget_host_);
-  DCHECK(!process_observation_.IsObserving());
-  DCHECK(!widget_observation_.IsObserving());
+  DCHECK(!process_observer_.IsObservingSources());
+  DCHECK(!widget_observer_.IsObservingSources());
   DCHECK(tab_observers_.empty());
 
   render_widget_host_ = render_widget_host;
@@ -93,8 +93,8 @@
         std::make_unique<WebContentsObserverImpl>(this, hung_contents));
   }
 
-  process_observation_.Observe(render_widget_host_->GetProcess());
-  widget_observation_.Observe(render_widget_host_);
+  process_observer_.Add(render_widget_host_->GetProcess());
+  widget_observer_.Add(render_widget_host_);
 
   // The world is different.
   if (observer_)
@@ -102,8 +102,8 @@
 }
 
 void HungPagesTableModel::Reset() {
-  process_observation_.Reset();
-  widget_observation_.Reset();
+  process_observer_.RemoveAll();
+  widget_observer_.RemoveAll();
   tab_observers_.clear();
   render_widget_host_ = nullptr;
 
@@ -158,8 +158,8 @@
 
 void HungPagesTableModel::RenderWidgetHostDestroyed(
     content::RenderWidgetHost* widget_host) {
-  DCHECK(widget_observation_.IsObservingSource(render_widget_host_));
-  widget_observation_.Reset();
+  DCHECK(widget_observer_.IsObserving(render_widget_host_));
+  widget_observer_.Remove(widget_host);
   render_widget_host_ = nullptr;
 
   // Notify the delegate.
diff --git a/chrome/browser/ui/views/hung_renderer_view.h b/chrome/browser/ui/views/hung_renderer_view.h
index 3665588..1d487ae 100644
--- a/chrome/browser/ui/views/hung_renderer_view.h
+++ b/chrome/browser/ui/views/hung_renderer_view.h
@@ -10,7 +10,7 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
-#include "base/scoped_observation.h"
+#include "base/scoped_observer.h"
 #include "components/favicon/content/content_favicon_driver.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_process_host_observer.h"
@@ -124,13 +124,11 @@
   // some more until the renderer process responds).
   base::RepeatingClosure hang_monitor_restarter_;
 
-  base::ScopedObservation<content::RenderProcessHost,
-                          content::RenderProcessHostObserver>
-      process_observation_{this};
+  ScopedObserver<content::RenderProcessHost, content::RenderProcessHostObserver>
+      process_observer_{this};
 
-  base::ScopedObservation<content::RenderWidgetHost,
-                          content::RenderWidgetHostObserver>
-      widget_observation_{this};
+  ScopedObserver<content::RenderWidgetHost, content::RenderWidgetHostObserver>
+      widget_observer_{this};
 
   DISALLOW_COPY_AND_ASSIGN(HungPagesTableModel);
 };
diff --git a/chrome/browser/ui/views/task_manager_view.cc b/chrome/browser/ui/views/task_manager_view.cc
index 47d7153..84f9e5c 100644
--- a/chrome/browser/ui/views/task_manager_view.cc
+++ b/chrome/browser/ui/views/task_manager_view.cc
@@ -38,7 +38,6 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/public/cpp/shelf_item.h"
 #include "ash/public/cpp/window_properties.h"
-#include "chrome/browser/ui/app_list/icon_standardizer.h"
 #include "chrome/grit/theme_resources.h"
 #include "ui/aura/window.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -172,11 +171,8 @@
 
 gfx::ImageSkia TaskManagerView::GetWindowIcon() {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  // TODO(crbug.com/1162514): Move app_list::CreateStandardIconImage to some
-  // where lower in the stack.
-  return app_list::CreateStandardIconImage(
-      *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
-          IDR_ASH_SHELF_ICON_TASK_MANAGER));
+  return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
+      IDR_ASH_SHELF_ICON_TASK_MANAGER);
 #else
   return views::DialogDelegateView::GetWindowIcon();
 #endif
diff --git a/chrome/browser/ui/webui/chromeos/login/fingerprint_setup_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/fingerprint_setup_screen_handler.cc
index 4b26fd4..806cb06 100644
--- a/chrome/browser/ui/webui/chromeos/login/fingerprint_setup_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/fingerprint_setup_screen_handler.cc
@@ -25,12 +25,8 @@
 
 void FingerprintSetupScreenHandler::DeclareLocalizedValues(
     ::login::LocalizedValuesBuilder* builder) {
-  builder->AddF("setupFingerprintScreenTitle",
-                IDS_OOBE_FINGERPINT_SETUP_SCREEN_TITLE,
-                ui::GetChromeOSDeviceName());
-  builder->AddF("setupFingerprintScreenFooter",
-                IDS_OOBE_FINGERPINT_SETUP_SCREEN_ENROLLMENT_FOOTER,
-                ui::GetChromeOSDeviceName());
+  builder->Add("setupFingerprintScreenTitle",
+               IDS_OOBE_FINGERPINT_SETUP_SCREEN_TITLE);
   builder->Add("skipFingerprintSetup",
                IDS_OOBE_FINGERPINT_SETUP_SCREEN_BUTTON_SKIP);
   builder->Add("fingerprintSetupDone",
@@ -75,7 +71,8 @@
           IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSTRUCTION_LOCATE_SCANNER_KEYBOARD_TOP_RIGHT_ARIA_LABEL;
       break;
   }
-  builder->Add("setupFingerprintScreenDescription", description_id);
+  builder->AddF("setupFingerprintScreenDescription", description_id,
+                ui::GetChromeOSDeviceName());
   builder->Add("setupFingerprintScreenAriaLabel", aria_label_id);
 }
 
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page.mojom b/chrome/browser/ui/webui/new_tab_page/new_tab_page.mojom
index 83178b9..5ba2b97 100644
--- a/chrome/browser/ui/webui/new_tab_page/new_tab_page.mojom
+++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page.mojom
@@ -397,8 +397,10 @@
   // Logs a module impression. Called when a module is loaded and can be seen by
   // the user (scrolled into view).
   OnModuleImpression(string module_id, double time);
-  // Logs when a module is loaded with data.
-  OnModuleLoaded(string module_id, double time);
+  // Logs that a module loaded data for |duration| and finished successfully at
+  // |time|.
+  OnModuleLoaded(string module_id, mojo_base.mojom.TimeDelta duration,
+                 double time);
   // Logs when a user interacts with a module which will result in a navigation.
   OnModuleUsage(string module_id);
   // Logs that the modules have been shown at |time|.
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc
index b0196e9..2e19ae5 100644
--- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc
+++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc
@@ -999,9 +999,11 @@
 }
 
 void NewTabPageHandler::OnModuleLoaded(const std::string& module_id,
+                                       base::TimeDelta duration,
                                        double time) {
   logger_.LogModuleLoaded(
-      module_id, base::Time::FromJsTime(time) - ntp_navigation_start_time_);
+      module_id, base::Time::FromJsTime(time) - ntp_navigation_start_time_,
+      duration);
 }
 
 void NewTabPageHandler::OnModuleUsage(const std::string& module_id) {
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.h b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.h
index f57a202..f18b85a 100644
--- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.h
+++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.h
@@ -139,7 +139,9 @@
       new_tab_page::mojom::VoiceSearchAction action) override;
   void OnVoiceSearchError(new_tab_page::mojom::VoiceSearchError error) override;
   void OnModuleImpression(const std::string& module_id, double time) override;
-  void OnModuleLoaded(const std::string& module_id, double time) override;
+  void OnModuleLoaded(const std::string& module_id,
+                      base::TimeDelta duration,
+                      double time) override;
   void OnModuleUsage(const std::string& module_id) override;
   void OnModulesRendered(double time) override;
   void QueryAutocomplete(const base::string16& input,
diff --git a/chrome/browser/ui/webui/reset_password/reset_password_ui.cc b/chrome/browser/ui/webui/reset_password/reset_password_ui.cc
index 0f67bfa..1f98e4a 100644
--- a/chrome/browser/ui/webui/reset_password/reset_password_ui.cc
+++ b/chrome/browser/ui/webui/reset_password/reset_password_ui.cc
@@ -89,10 +89,13 @@
   if (!nav_entry || !nav_entry->GetHasPostData())
     return PasswordType::PASSWORD_TYPE_UNKNOWN;
   auto& post_data = nav_entry->GetPostData()->elements()->at(0);
-  int post_data_int = -1;
-  if (base::StringToInt(std::string(post_data.bytes(), post_data.length()),
-                        &post_data_int)) {
-    return static_cast<PasswordType>(post_data_int);
+  if (post_data.type() == network::DataElement::Tag::kBytes) {
+    int post_data_int = -1;
+    if (base::StringToInt(
+            post_data.As<network::DataElementBytes>().AsStringPiece(),
+            &post_data_int)) {
+      return static_cast<PasswordType>(post_data_int);
+    }
   }
 
   return PasswordType::PASSWORD_TYPE_UNKNOWN;
diff --git a/chrome/browser/ui/webui/signin/profile_picker_handler.cc b/chrome/browser/ui/webui/signin/profile_picker_handler.cc
index 3f345d0..7a176d5 100644
--- a/chrome/browser/ui/webui/signin/profile_picker_handler.cc
+++ b/chrome/browser/ui/webui/signin/profile_picker_handler.cc
@@ -209,6 +209,10 @@
   // TODO(crbug.com/1115056): Consider renaming this message to
   // 'createLocalProfile' as this is only used for local profiles.
   web_ui()->RegisterMessageCallback(
+      "getAvailableIcons",
+      base::BindRepeating(&ProfilePickerHandler::HandleGetAvailableIcons,
+                          base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
       "createProfile",
       base::BindRepeating(&ProfilePickerHandler::HandleCreateProfile,
                           base::Unretained(this)));
@@ -356,31 +360,33 @@
   ResolveJavascriptCallback(callback_id, std::move(dict));
 }
 
+void ProfilePickerHandler::HandleGetAvailableIcons(
+    const base::ListValue* args) {
+  AllowJavascript();
+  CHECK_EQ(1U, args->GetSize());
+  const base::Value& callback_id = args->GetList()[0];
+  ResolveJavascriptCallback(callback_id,
+                            *profiles::GetCustomProfileAvatarIconsAndLabels());
+}
+
 void ProfilePickerHandler::HandleCreateProfile(const base::ListValue* args) {
-  // profileName, profileColor, avatarUrl, isGeneric, createShortcut
-  CHECK_EQ(5U, args->GetList().size());
+  CHECK_EQ(4U, args->GetList().size());
   base::string16 profile_name =
       base::UTF8ToUTF16(args->GetList()[0].GetString());
   // profileColor is undefined for the default theme.
   base::Optional<SkColor> profile_color;
   if (args->GetList()[1].is_int())
     profile_color = args->GetList()[1].GetInt();
-  std::string avatar_url = args->GetList()[2].GetString();
-  bool is_generic = args->GetList()[3].GetBool();
-  bool create_shortcut = args->GetList()[4].GetBool();
-  DCHECK(base::IsStringASCII(avatar_url));
+  size_t avatar_index = args->GetList()[2].GetInt();
+  bool create_shortcut = args->GetList()[3].GetBool();
   base::TrimWhitespace(profile_name, base::TRIM_ALL, &profile_name);
   CHECK(!profile_name.empty());
-  if (is_generic) {
-    avatar_url = profiles::GetDefaultAvatarIconUrl(
-        profiles::GetPlaceholderAvatarIndex());
-  }
 
 #ifndef NDEBUG
-  size_t icon_index;
-  DCHECK(profiles::IsDefaultAvatarIconUrl(avatar_url, &icon_index));
+  DCHECK(profiles::IsDefaultAvatarIconIndex(avatar_index));
 #endif
 
+  std::string avatar_url = profiles::GetDefaultAvatarIconUrl(avatar_index);
   ProfileMetrics::LogProfileAddNewUser(
       ProfileMetrics::ADD_NEW_PROFILE_PICKER_LOCAL);
   ProfileManager::CreateMultiProfileAsync(
@@ -683,6 +689,8 @@
 }
 
 void ProfilePickerHandler::OnProfileAdded(const base::FilePath& profile_path) {
+  if (profile_path == ProfileManager::GetGuestProfilePath())
+    return;
   size_t number_of_profiles = profiles_order_.size();
   profiles_order_[profile_path] = number_of_profiles;
   PushProfilesList();
@@ -692,6 +700,8 @@
     const base::FilePath& profile_path,
     const base::string16& profile_name) {
   DCHECK(IsJavascriptAllowed());
+  if (profile_path == ProfileManager::GetGuestProfilePath())
+    return;
   size_t index = profiles_order_[profile_path];
   profiles_order_.erase(profile_path);
   for (auto it : profiles_order_) {
diff --git a/chrome/browser/ui/webui/signin/profile_picker_handler.h b/chrome/browser/ui/webui/signin/profile_picker_handler.h
index 1966cb08..b855b86 100644
--- a/chrome/browser/ui/webui/signin/profile_picker_handler.h
+++ b/chrome/browser/ui/webui/signin/profile_picker_handler.h
@@ -47,6 +47,7 @@
   void HandleLoadSignInProfileCreationFlow(const base::ListValue* args);
   void HandleGetNewProfileSuggestedThemeInfo(const base::ListValue* args);
   void HandleGetProfileThemeInfo(const base::ListValue* args);
+  void HandleGetAvailableIcons(const base::ListValue* args);
   void HandleCreateProfile(const base::ListValue* args);
 
   // |args| is unused.
diff --git a/chrome/browser/ui/webui/signin/profile_picker_ui.cc b/chrome/browser/ui/webui/signin/profile_picker_ui.cc
index 16da9bb..10fd195 100644
--- a/chrome/browser/ui/webui/signin/profile_picker_ui.cc
+++ b/chrome/browser/ui/webui/signin/profile_picker_ui.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/policy/browser_signin_policy_handler.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_avatar_icon_util.h"
 #include "chrome/browser/profiles/profile_shortcut_manager.h"
 #include "chrome/browser/signin/signin_util.h"
 #include "chrome/browser/ui/profile_picker.h"
@@ -117,6 +118,11 @@
        IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_SHORTCUT_TEXT},
       {"createProfileConfirm",
        IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_DONE},
+      {"defaultAvatarLabel", IDS_DEFAULT_AVATAR_LABEL_26},
+      {"selectAnAvatarDialogTitle",
+       IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_AVATAR_TEXT},
+      {"selectAvatarDoneButtonLabel",
+       IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_AVATAR_DONE},
 
       // Color picker.
       {"colorPickerLabel", IDS_NTP_CUSTOMIZE_COLOR_PICKER_LABEL},
@@ -144,6 +150,9 @@
   html_source->AddString("minimumPickerSize",
                          base::StringPrintf("%ipx", kMinimumPickerSizePx));
 
+  html_source->AddInteger("placeholderAvatarIndex",
+                          profiles::GetPlaceholderAvatarIndex());
+
   // Add policies.
   html_source->AddBoolean("isBrowserSigninAllowed", IsBrowserSigninAllowed());
   html_source->AddBoolean("isForceSigninEnabled",
@@ -153,7 +162,6 @@
                           IsProfileCreationAllowed());
   html_source->AddBoolean("profileShortcutsEnabled",
                           ProfileShortcutManager::IsFeatureEnabled());
-  // TODO(crbug.com/1063856): Check if |BrowserSignin| device policy exists.
 }
 
 }  // namespace
diff --git a/chrome/browser/web_share_target/target_util_unittest.cc b/chrome/browser/web_share_target/target_util_unittest.cc
index 69431ee..aa7b8ac 100644
--- a/chrome/browser/web_share_target/target_util_unittest.cc
+++ b/chrome/browser/web_share_target/target_util_unittest.cc
@@ -11,18 +11,19 @@
 namespace web_share_target {
 
 std::string convertDataElementToString(const network::DataElement& element) {
-  if (element.type() == network::mojom::DataElementType::kBytes) {
-    return std::string(element.bytes(), element.length());
+  if (element.type() == network::DataElement::Tag::kBytes) {
+    return std::string(element.As<network::DataElementBytes>().AsStringPiece());
   }
-  if (element.type() == network::mojom::DataElementType::kFile) {
-    return std::string(element.path().AsUTF8Unsafe());
+  if (element.type() == network::DataElement::Tag::kFile) {
+    return std::string(
+        element.As<network::DataElementFile>().path().AsUTF8Unsafe());
   }
   return "";
 }
 
 void CheckDataElements(
     const scoped_refptr<network::ResourceRequestBody>& body,
-    const std::vector<network::mojom::DataElementType>& expected_element_types,
+    const std::vector<network::DataElement::Tag>& expected_element_types,
     const std::vector<std::string>& expected_element_values) {
   EXPECT_NE(nullptr, body->elements());
   const std::vector<network::DataElement>& data_elements = *body->elements();
@@ -67,12 +68,10 @@
       ComputeMultipartBody(names, values, is_value_file_uris, filenames, types,
                            boundary);
 
-  std::vector<network::mojom::DataElementType> expected_types = {
-      network::mojom::DataElementType::kBytes,
-      network::mojom::DataElementType::kFile,
-      network::mojom::DataElementType::kBytes,
-      network::mojom::DataElementType::kBytes,
-      network::mojom::DataElementType::kBytes};
+  std::vector<network::DataElement::Tag> expected_types = {
+      network::DataElement::Tag::kBytes, network::DataElement::Tag::kFile,
+      network::DataElement::Tag::kBytes, network::DataElement::Tag::kBytes,
+      network::DataElement::Tag::kBytes};
   std::vector<std::string> expected = {
       "--boundary\r\nContent-Disposition: form-data; name=\"share-file%22\"; "
       "filename=\"filename%0D%0A\"\r\nContent-Type: type\r\n\r\n",
@@ -97,9 +96,8 @@
       ComputeMultipartBody(names, values, is_value_file_uris, filenames, types,
                            boundary);
 
-  std::vector<network::mojom::DataElementType> expected_types = {
-      network::mojom::DataElementType::kBytes,
-      network::mojom::DataElementType::kBytes};
+  std::vector<network::DataElement::Tag> expected_types = {
+      network::DataElement::Tag::kBytes, network::DataElement::Tag::kBytes};
   std::vector<std::string> expected = {
       "--boundary\r\nContent-Disposition: form-data; "
       "name=\"name%22\"\r\nContent-Type: type\r\n\r\nvalue\r\n",
@@ -126,27 +124,24 @@
   scoped_refptr<network::ResourceRequestBody> body = ComputeMultipartBody(
       names, values, is_value_file_uris, filenames, types, boundary);
 
-  std::vector<network::mojom::DataElementType> expected_types = {
+  std::vector<network::DataElement::Tag> expected_types = {
       // item 1
-      network::mojom::DataElementType::kBytes,
+      network::DataElement::Tag::kBytes,
       // item 2
-      network::mojom::DataElementType::kBytes,
-      network::mojom::DataElementType::kFile,
-      network::mojom::DataElementType::kBytes,
+      network::DataElement::Tag::kBytes, network::DataElement::Tag::kFile,
+      network::DataElement::Tag::kBytes,
       // item 3
-      network::mojom::DataElementType::kBytes,
-      network::mojom::DataElementType::kFile,
-      network::mojom::DataElementType::kBytes,
+      network::DataElement::Tag::kBytes, network::DataElement::Tag::kFile,
+      network::DataElement::Tag::kBytes,
       // item 4
-      network::mojom::DataElementType::kBytes,
+      network::DataElement::Tag::kBytes,
       // item 5
-      network::mojom::DataElementType::kBytes,
-      network::mojom::DataElementType::kFile,
-      network::mojom::DataElementType::kBytes,
+      network::DataElement::Tag::kBytes, network::DataElement::Tag::kFile,
+      network::DataElement::Tag::kBytes,
       // item 6
-      network::mojom::DataElementType::kBytes,
+      network::DataElement::Tag::kBytes,
       // ending
-      network::mojom::DataElementType::kBytes};
+      network::DataElement::Tag::kBytes};
   std::vector<std::string> expected = {
       // item 1
       "--boundary\r\nContent-Disposition: form-data; "
@@ -185,9 +180,8 @@
       names, values, is_value_file_uris, filenames, types, boundary);
   EXPECT_NE(nullptr, body->elements());
 
-  std::vector<network::mojom::DataElementType> expected_types = {
-      network::mojom::DataElementType::kBytes,
-      network::mojom::DataElementType::kBytes};
+  std::vector<network::DataElement::Tag> expected_types = {
+      network::DataElement::Tag::kBytes, network::DataElement::Tag::kBytes};
   std::vector<std::string> expected = {
       "--boundary\r\nContent-Disposition: form-data;"
       " name=\"name\"; filename=\"filename\"\r\nContent-Type: type"
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 54b287e..8fdc131 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-master-1610495996-ac73e18e1b2efb1cd1bfbf2a2aaf90e9e3476b5a.profdata
+chrome-linux-master-1610538373-541aee2d8154a147aea334eed2074efc5a2f470f.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index b392018..5edb548 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-master-1610495996-38f3d5c57ab4be3d52eaefe38d45ce16ec0addd8.profdata
+chrome-mac-master-1610538373-c4c83fd08459537f19e890c14c2288baf23d3675.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 4f696ae..7bafa3d 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-master-1610495996-5598384ad8a00037e18a56fd00981ea765e31cd1.profdata
+chrome-win32-master-1610528340-b101588b91e5587ca53d6a4d812cdea4439c3876.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 435afb8..d5eb974 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-master-1610495996-7189a1d14c9908600535ebce9352fe55a59722e6.profdata
+chrome-win64-master-1610528340-1fc68c0c17222e2254fe428312433be61c378c49.profdata
diff --git a/chrome/services/speech/cloud_speech_recognition_client_unittest.cc b/chrome/services/speech/cloud_speech_recognition_client_unittest.cc
index 1264cad..d014aa5 100644
--- a/chrome/services/speech/cloud_speech_recognition_client_unittest.cc
+++ b/chrome/services/speech/cloud_speech_recognition_client_unittest.cc
@@ -184,16 +184,15 @@
           GetUpstreamRequest();
       EXPECT_TRUE(upstream_request);
       EXPECT_TRUE(upstream_request->request.request_body);
-      EXPECT_EQ(1u, upstream_request->request.request_body->elements()->size());
-      EXPECT_EQ(
-          network::mojom::DataElementType::kChunkedDataPipe,
-          (*upstream_request->request.request_body->elements())[0].type());
-      network::TestURLLoaderFactory::PendingRequest* mutable_upstream_request =
-          const_cast<network::TestURLLoaderFactory::PendingRequest*>(
-              upstream_request);
-      chunked_data_pipe_getter_.Bind((*mutable_upstream_request->request
-                                           .request_body->elements_mutable())[0]
-                                         .ReleaseChunkedDataPipeGetter());
+      auto& mutable_elements =
+          *upstream_request->request.request_body->elements_mutable();
+      ASSERT_EQ(1u, mutable_elements.size());
+      ASSERT_EQ(network::DataElement::Tag::kChunkedDataPipe,
+                mutable_elements[0].type());
+      chunked_data_pipe_getter_.Bind(
+          mutable_elements[0]
+              .As<network::DataElementChunkedDataPipe>()
+              .ReleaseChunkedDataPipeGetter());
     }
 
     constexpr size_t kDataPipeCapacity = 256;
diff --git a/chrome/test/data/webui/cr_elements/cr_profile_avatar_selector_tests.js b/chrome/test/data/webui/cr_elements/cr_profile_avatar_selector_tests.js
index 5fe38fb..c75587a 100644
--- a/chrome/test/data/webui/cr_elements/cr_profile_avatar_selector_tests.js
+++ b/chrome/test/data/webui/cr_elements/cr_profile_avatar_selector_tests.js
@@ -20,9 +20,9 @@
     const avatarSelector = /** @type {!CrProfileAvatarSelectorElement} */ (
         document.createElement('cr-profile-avatar-selector'));
     avatarSelector.avatars = [
-      {url: 'chrome://avatar1.png', label: 'avatar1'},
-      {url: 'chrome://avatar2.png', label: 'avatar2'},
-      {url: 'chrome://avatar3.png', label: 'avatar3'}
+      {url: 'chrome://avatar1.png', label: 'avatar1', index: '1'},
+      {url: 'chrome://avatar2.png', label: 'avatar2', index: '2'},
+      {url: 'chrome://avatar3.png', label: 'avatar3', index: '3'}
     ];
     return avatarSelector;
   }
diff --git a/chrome/test/data/webui/new_tab_page/modules/module_descriptor_test.js b/chrome/test/data/webui/new_tab_page/modules/module_descriptor_test.js
index 522288f..c04b871 100644
--- a/chrome/test/data/webui/new_tab_page/modules/module_descriptor_test.js
+++ b/chrome/test/data/webui/new_tab_page/modules/module_descriptor_test.js
@@ -21,8 +21,11 @@
   test('instantiate module with data', async () => {
     // Arrange.
     const element = document.createElement('div');
-    const moduleDescriptor =
-        new ModuleDescriptor('foo', 100, () => Promise.resolve(element));
+    const moduleDescriptor = new ModuleDescriptor('foo', 100, () => {
+      // Move time forward to simulate delay instantiating module.
+      testProxy.setResultFor('now', 128);
+      return Promise.resolve(element);
+    });
     testProxy.setResultFor('now', 123);
 
     // Act.
@@ -30,10 +33,12 @@
 
     // Assert.
     assertEquals(element, moduleDescriptor.element);
-    const [id, now] = await testProxy.handler.whenCalled('onModuleLoaded');
+    const [id, now, delta] =
+        await testProxy.handler.whenCalled('onModuleLoaded');
     assertEquals(1, testProxy.handler.getCallCount('onModuleLoaded'));
     assertEquals('foo', id);
-    assertEquals(123, now);
+    assertEquals(128, now);
+    assertEquals(5000n, delta.microseconds);  // 128ms - 123ms === 5000µs.
   });
 
   test('instantiate module without data', async () => {
diff --git a/chrome/test/data/webui/signin/local_profile_customization_test.js b/chrome/test/data/webui/signin/local_profile_customization_test.js
index e4d34ac..c9bdc2b 100644
--- a/chrome/test/data/webui/signin/local_profile_customization_test.js
+++ b/chrome/test/data/webui/signin/local_profile_customization_test.js
@@ -21,6 +21,8 @@
   /** @type {!TestManageProfilesBrowserProxy} */
   let browserProxy;
 
+  const defaultAvatarIndex = 26;
+
   async function resetCustomizeProfileElement() {
     document.body.innerHTML = '';
     customizeProfileElement = /** @type {!LocalProfileCustomizationElement} */ (
@@ -52,18 +54,16 @@
   /**
    * @param {string} profileName
    * @param {number} profileColor
-   * @param {string} avatarUrl
-   * @param {boolean} isGeneric
+   * @param {number} avatarIndex
    * @param {boolean} createShortcut
    */
   async function verifyCreateProfileCalledWithParams(
-      profileName, profileColor, avatarUrl, isGeneric, createShortcut) {
+      profileName, profileColor, avatarIndex, createShortcut) {
     const args = await browserProxy.whenCalled('createProfile');
     assertEquals(args[0], profileName);
     assertEquals(args[1], profileColor);
-    assertEquals(args[2], avatarUrl);
-    assertEquals(args[3], isGeneric);
-    assertEquals(args[4], createShortcut);
+    assertEquals(args[2], avatarIndex);
+    assertEquals(args[3], createShortcut);
     browserProxy.resetResolver('createProfile');
   }
 
@@ -86,7 +86,7 @@
     assertFalse(customizeProfileElement.$$('#save').disabled);
     customizeProfileElement.$$('#save').click();
     await verifyCreateProfileCalledWithParams(
-        'Work', browserProxy.profileThemeInfo.color, '', true, false);
+        'Work', browserProxy.profileThemeInfo.color, defaultAvatarIndex, false);
   });
 
   test('ThemeSelectionChanges', async function() {
@@ -122,7 +122,8 @@
     customizeProfileElement.$$('#nameInput').value = 'Personal';
     customizeProfileElement.$$('#save').click();
     await verifyCreateProfileCalledWithParams(
-        'Personal', browserProxy.profileThemeInfo.color, '', true, false);
+        'Personal', browserProxy.profileThemeInfo.color, defaultAvatarIndex,
+        false);
   });
 
   test('createShortcut', async function() {
@@ -142,7 +143,8 @@
     customizeProfileElement.$$('#nameInput').value = 'Personal';
     customizeProfileElement.$$('#save').click();
     await verifyCreateProfileCalledWithParams(
-        'Personal', browserProxy.profileThemeInfo.color, '', true, false);
+        'Personal', browserProxy.profileThemeInfo.color, defaultAvatarIndex,
+        false);
     // Profile creation in progress should disable the save button.
     assertTrue(customizeProfileElement.$$('#save').disabled);
     // Fire profile creation finished.
@@ -153,6 +155,7 @@
     assertTrue(createShortcut.checked);
     customizeProfileElement.$$('#save').click();
     await verifyCreateProfileCalledWithParams(
-        'Personal', browserProxy.profileThemeInfo.color, '', true, true);
+        'Personal', browserProxy.profileThemeInfo.color, defaultAvatarIndex,
+        true);
   });
 });
diff --git a/chrome/test/data/webui/signin/test_manage_profiles_browser_proxy.js b/chrome/test/data/webui/signin/test_manage_profiles_browser_proxy.js
index 95e4e6f..2896af2 100644
--- a/chrome/test/data/webui/signin/test_manage_profiles_browser_proxy.js
+++ b/chrome/test/data/webui/signin/test_manage_profiles_browser_proxy.js
@@ -23,6 +23,7 @@
       'createProfile',
       'setProfileName',
       'recordSignInPromoImpression',
+      'getAvailableIcons',
     ]);
 
     /** @type {!AutogeneratedThemeColorInfo} */
@@ -106,11 +107,10 @@
   }
 
   /** @override */
-  createProfile(
-      profileName, profileColor, avatarUrl, isGeneric, createShortcut) {
+  createProfile(profileName, profileColor, avatarIndex, createShortcut) {
     this.methodCalled(
         'createProfile',
-        [profileName, profileColor, avatarUrl, isGeneric, createShortcut]);
+        [profileName, profileColor, avatarIndex, createShortcut]);
   }
 
   /** @override */
@@ -122,4 +122,14 @@
   recordSignInPromoImpression() {
     this.methodCalled('recordSignInPromoImpression');
   }
+
+  /** @override */
+  getAvailableIcons() {
+    this.methodCalled('getAvailableIcons');
+    return Promise.resolve([
+      {url: 'fake-icon-1.png', label: 'fake-icon-1', index: 1, selected: false},
+      {url: 'fake-icon-2.png', label: 'fake-icon-2', index: 2, selected: false},
+      {url: 'fake-icon-3.png', label: 'fake-icon-3', index: 3, selected: false},
+    ]);
+  }
 }
diff --git a/chrome/updater/test/integration_tests.cc b/chrome/updater/test/integration_tests.cc
index 7628a82..ed2aa21 100644
--- a/chrome/updater/test/integration_tests.cc
+++ b/chrome/updater/test/integration_tests.cc
@@ -312,7 +312,14 @@
   Clean();
 }
 
-TEST_F(IntegrationTest, UnregisterUnownedApp) {
+// TODO(https://crbug.com/1166196): Fix flaky timeouts. The timeout is in
+// RunWake(0).
+#if defined(OS_MAC)
+#define MAYBE_UnregisterUnownedApp DISABLED_UnregisterUnownedApp
+#else
+#define MAYBE_UnregisterUnownedApp UnregisterUnownedApp
+#endif
+TEST_F(IntegrationTest, MAYBE_UnregisterUnownedApp) {
   RegisterTestApp();
   ExpectInstalled();
   ExpectActiveVersion(UPDATER_VERSION_STRING);
diff --git a/chromeos/services/assistant/chromium_http_connection.cc b/chromeos/services/assistant/chromium_http_connection.cc
index 2f002fd5..7602bcc 100644
--- a/chromeos/services/assistant/chromium_http_connection.cc
+++ b/chromeos/services/assistant/chromium_http_connection.cc
@@ -163,7 +163,8 @@
     receiver_set_.Add(this, data_remote.InitWithNewPipeAndPassReceiver());
     resource_request->request_body = new network::ResourceRequestBody();
     resource_request->request_body->SetToChunkedDataPipe(
-        std::move(data_remote));
+        std::move(data_remote),
+        network::ResourceRequestBody::ReadOnlyOnce(false));
   }
 
   url_loader_ = network::SimpleURLLoader::Create(std::move(resource_request),
diff --git a/components/autofill/core/browser/autofill_download_manager_unittest.cc b/components/autofill/core/browser/autofill_download_manager_unittest.cc
index f939418..47fde35 100644
--- a/components/autofill/core/browser/autofill_download_manager_unittest.cc
+++ b/components/autofill/core/browser/autofill_download_manager_unittest.cc
@@ -87,10 +87,11 @@
     const std::vector<network::DataElement>* data_elements) {
   std::string result;
   for (const network::DataElement& e : *data_elements) {
-    DCHECK_EQ(e.type(), network::mojom::DataElementType::kBytes);
+    DCHECK_EQ(e.type(), network::DataElement::Tag::kBytes);
     // Provide the length of the bytes explicitly, not to rely on the null
     // termination.
-    result.append(e.bytes(), base::checked_cast<size_t>(e.length()));
+    const auto piece = e.As<network::DataElementBytes>().AsStringPiece();
+    result.append(piece.data(), piece.size());
   }
   return result;
 }
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc
index 020107d..b240931 100644
--- a/components/autofill/core/browser/autofill_manager.cc
+++ b/components/autofill/core/browser/autofill_manager.cc
@@ -413,23 +413,25 @@
 
 AutofillManager::FillingContext::FillingContext(
     const AutofillField& field,
-    const AutofillProfile* optional_profile,
-    const CreditCard* optional_credit_card,
+    absl::variant<const AutofillProfile*, const CreditCard*>
+        profile_or_credit_card,
     const base::string16* optional_cvc)
-    : profile(optional_profile ? base::make_optional(*optional_profile)
-                               : base::nullopt),
-      credit_card(optional_credit_card
-                      ? base::make_optional(std::make_pair(
-                            *optional_credit_card,
-                            optional_cvc ? *optional_cvc : base::string16()))
-                      : base::nullopt),
-      filled_field_renderer_id(field.unique_renderer_id),
+    : filled_field_renderer_id(field.unique_renderer_id),
       filled_field_signature(field.GetFieldSignature()),
       filled_field_unique_name(field.unique_name()),
       original_fill_time(AutofillTickClock::NowTicks()) {
-  DCHECK(optional_profile || optional_credit_card);
-  DCHECK(optional_credit_card || !optional_cvc);
-  DCHECK(profile || credit_card);
+  DCHECK(absl::holds_alternative<const CreditCard*>(profile_or_credit_card) ||
+         !optional_cvc);
+
+  if (absl::holds_alternative<const AutofillProfile*>(profile_or_credit_card)) {
+    profile_or_credit_card_with_cvc =
+        *absl::get<const AutofillProfile*>(profile_or_credit_card);
+  } else if (absl::holds_alternative<const CreditCard*>(
+                 profile_or_credit_card)) {
+    profile_or_credit_card_with_cvc =
+        std::make_pair(*absl::get<const CreditCard*>(profile_or_credit_card),
+                       optional_cvc ? *optional_cvc : base::string16());
+  }
 }
 
 AutofillManager::FillingContext::~FillingContext() = default;
@@ -1071,9 +1073,8 @@
         credit_card_, *form_structure, *autofill_field, sync_state_);
   }
 
-  FillOrPreviewDataModelForm(action, query_id, form, field, /*profile=*/nullptr,
-                             &credit_card_, /*cvc=*/nullptr, form_structure,
-                             autofill_field);
+  FillOrPreviewDataModelForm(action, query_id, form, field, &credit_card_,
+                             /*cvc=*/nullptr, form_structure, autofill_field);
 }
 
 void AutofillManager::FillOrPreviewProfileForm(
@@ -1092,7 +1093,6 @@
   }
 
   FillOrPreviewDataModelForm(action, query_id, form, field, &profile,
-                             /*credit_card=*/nullptr,
                              /*cvc=*/nullptr, form_structure, autofill_field);
 }
 
@@ -1135,8 +1135,8 @@
     return;
 
   FillOrPreviewDataModelForm(AutofillDriver::FORM_DATA_ACTION_FILL, query_id,
-                             form, field, /*profile=*/nullptr, &credit_card,
-                             &cvc, form_structure, autofill_field);
+                             form, field, &credit_card, &cvc, form_structure,
+                             autofill_field);
 }
 
 void AutofillManager::FillProfileForm(const autofill::AutofillProfile& profile,
@@ -1630,25 +1630,19 @@
     int query_id,
     const FormData& form,
     const FormFieldData& field,
-    const AutofillProfile* optional_profile,
-    const CreditCard* optional_credit_card,
+    absl::variant<const AutofillProfile*, const CreditCard*>
+        profile_or_credit_card,
     const base::string16* optional_cvc,
     FormStructure* form_structure,
     AutofillField* autofill_field,
     bool is_refill) {
-  DCHECK(optional_profile || optional_credit_card);
-  DCHECK(optional_credit_card || !optional_cvc);
+  bool is_credit_card =
+      absl::holds_alternative<const CreditCard*>(profile_or_credit_card);
+
+  DCHECK(is_credit_card || !optional_cvc);
   DCHECK(form_structure);
   DCHECK(autofill_field);
 
-  const AutofillDataModel& data_model = [&]() -> const AutofillDataModel& {
-    if (optional_profile)
-      return *optional_profile;
-    else
-      return *optional_credit_card;
-  }();
-  bool is_credit_card = !!optional_credit_card;
-
   LogBuffer buffer;
   buffer << "is credit card section: " << is_credit_card << Br{};
   buffer << "is refill: " << is_refill << Br{};
@@ -1661,9 +1655,10 @@
   DCHECK_EQ(form_structure->field_count(), form.fields.size());
 
   if (action == AutofillDriver::FORM_DATA_ACTION_FILL && !is_refill) {
-    SetFillingContext(*form_structure, std::make_unique<FillingContext>(
-                                           *autofill_field, optional_profile,
-                                           optional_credit_card, optional_cvc));
+    SetFillingContext(
+        *form_structure,
+        std::make_unique<FillingContext>(*autofill_field,
+                                         profile_or_credit_card, optional_cvc));
   }
 
   // Only record the types that are filled for an eventual refill if all the
@@ -1761,8 +1756,8 @@
 
     // Don't fill expired cards expiration date.
     if (data_util::IsCreditCardExpirationType(field_type) &&
-        (!optional_credit_card ||
-         optional_credit_card->IsExpired(AutofillClock::Now()))) {
+        (is_credit_card && absl::get<const CreditCard*>(profile_or_credit_card)
+                               ->IsExpired(AutofillClock::Now()))) {
       buffer << Tr{} << field_number
              << "Skipped: don't fill expiration date of expired cards";
       continue;
@@ -1795,9 +1790,9 @@
     const base::string16 kEmptyCvc{};
     std::string failure_to_fill;  // Reason for failing to fill.
 
-    // Fill the non-empty value from |data_model| into the result vector, which
-    // will be sent to the renderer.
-    FillFieldWithValue(cached_field, data_model, &result.fields[i],
+    // Fill the non-empty value from |profile_or_credit_card| into the result
+    // vector, which will be sent to the renderer.
+    FillFieldWithValue(cached_field, profile_or_credit_card, &result.fields[i],
                        should_notify, optional_cvc ? *optional_cvc : kEmptyCvc,
                        data_util::DetermineGroups(*form_structure),
                        &failure_to_fill);
@@ -1822,9 +1817,9 @@
   if (autofilled_form_signatures_.size() > kMaxRecentFormSignaturesToRemember)
     autofilled_form_signatures_.pop_back();
 
-  // Note that this may invalidate |data_model|.
+  // Note that this may invalidate |profile_or_credit_card|.
   if (action == AutofillDriver::FORM_DATA_ACTION_FILL && !is_refill)
-    personal_data_->RecordUseOf(data_model);
+    personal_data_->RecordUseOf(profile_or_credit_card);
 
   if (log_manager_) {
     log_manager_->Log() << LoggingScope::kFilling
@@ -2309,15 +2304,17 @@
   }
 }
 
-void AutofillManager::FillFieldWithValue(AutofillField* autofill_field,
-                                         const AutofillDataModel& data_model,
-                                         FormFieldData* field_data,
-                                         bool should_notify,
-                                         const base::string16& cvc,
-                                         uint32_t profile_form_bitmask,
-                                         std::string* failure_to_fill) {
-  if (field_filler_.FillFormField(*autofill_field, data_model, field_data, cvc,
-                                  failure_to_fill)) {
+void AutofillManager::FillFieldWithValue(
+    AutofillField* autofill_field,
+    absl::variant<const AutofillProfile*, const CreditCard*>
+        profile_or_credit_card,
+    FormFieldData* field_data,
+    bool should_notify,
+    const base::string16& cvc,
+    uint32_t profile_form_bitmask,
+    std::string* failure_to_fill) {
+  if (field_filler_.FillFormField(*autofill_field, profile_or_credit_card,
+                                  field_data, cvc, failure_to_fill)) {
     if (failure_to_fill)
       *failure_to_fill = "Decided to fill";
     // Mark the cached field as autofilled, so that we can detect when a
@@ -2333,10 +2330,14 @@
         client_->GetSecurityLevelForUmaHistograms(), profile_form_bitmask);
 
     if (should_notify) {
+      DCHECK(absl::holds_alternative<const AutofillProfile*>(
+          profile_or_credit_card));
+      const AutofillProfile* profile =
+          absl::get<const AutofillProfile*>(profile_or_credit_card);
       client_->DidFillOrPreviewField(
-          /*value=*/data_model.GetInfo(autofill_field->Type(), app_locale_),
-          /*profile_full_name=*/data_model.GetInfo(AutofillType(NAME_FULL),
-                                                   app_locale_));
+          /*value=*/profile->GetInfo(autofill_field->Type(), app_locale_),
+          /*profile_full_name=*/profile->GetInfo(AutofillType(NAME_FULL),
+                                                 app_locale_));
     }
   }
 }
@@ -2463,22 +2464,28 @@
     return;
 
   FormFieldData field = *autofill_field;
-  if (filling_context->credit_card) {
+  if (absl::holds_alternative<std::pair<CreditCard, base::string16>>(
+          filling_context->profile_or_credit_card_with_cvc)) {
     FillOrPreviewDataModelForm(
         AutofillDriver::RendererFormDataAction::FORM_DATA_ACTION_FILL,
         /*query_id=*/-1, form, field,
-        /*profile=*/nullptr, &filling_context->credit_card.value().first,
-        &filling_context->credit_card.value().second, form_structure,
-        autofill_field,
+        &absl::get<std::pair<CreditCard, base::string16>>(
+             filling_context->profile_or_credit_card_with_cvc)
+             .first,
+        &absl::get<std::pair<CreditCard, base::string16>>(
+             filling_context->profile_or_credit_card_with_cvc)
+             .second,
+        form_structure, autofill_field,
         /*is_refill=*/true);
   }
-  if (filling_context->profile) {
+  if (absl::holds_alternative<AutofillProfile>(
+          filling_context->profile_or_credit_card_with_cvc)) {
     FillOrPreviewDataModelForm(
         AutofillDriver::RendererFormDataAction::FORM_DATA_ACTION_FILL,
-        /*query_id=*/-1, form, field, &filling_context->profile.value(),
-        /*credic_card=*/nullptr, /*cvc=*/nullptr, form_structure,
-        autofill_field,
-        /*is_refill=*/true);
+        /*query_id=*/-1, form, field,
+        &absl::get<AutofillProfile>(
+            filling_context->profile_or_credit_card_with_cvc),
+        /*cvc=*/nullptr, form_structure, autofill_field, /*is_refill=*/true);
   }
 }
 
diff --git a/components/autofill/core/browser/autofill_manager.h b/components/autofill/core/browser/autofill_manager.h
index 9d6c4b1..5f9a358 100644
--- a/components/autofill/core/browser/autofill_manager.h
+++ b/components/autofill/core/browser/autofill_manager.h
@@ -40,6 +40,7 @@
 #include "components/autofill/core/browser/ui/popup_types.h"
 #include "components/autofill/core/common/form_data.h"
 #include "components/autofill/core/common/signatures.h"
+#include "third_party/abseil-cpp/absl/types/variant.h"
 
 namespace gfx {
 class RectF;
@@ -47,7 +48,6 @@
 
 namespace autofill {
 
-class AutofillDataModel;
 class AutofillField;
 class AutofillClient;
 class AutofillManagerTestDelegate;
@@ -365,11 +365,13 @@
 
   // Keeps track of the filling context for a form, used to make refill attemps.
   struct FillingContext {
-    // |optional_profile| or |optional_credit_card| must be non-null.
-    // If |optional_credit_card| is non-null, |optional_cvc| may be non-null.
+    // |profile_or_credit_card| contains either AutofillProfile or CreditCard
+    // and must be non-null.
+    // If |profile_or_credit_card| contains a CreditCard, |optional_cvc| may be
+    // non-null.
     FillingContext(const AutofillField& field,
-                   const AutofillProfile* optional_profile,
-                   const CreditCard* optional_credit_card,
+                   absl::variant<const AutofillProfile*, const CreditCard*>
+                       profile_or_credit_card,
                    const base::string16* optional_cvc);
     ~FillingContext();
 
@@ -378,8 +380,8 @@
     // The profile or credit card that was used for the initial fill.
     // The std::string associated with the credit card is the CVC, which may be
     // empty.
-    const base::Optional<AutofillProfile> profile;
-    const base::Optional<std::pair<CreditCard, base::string16>> credit_card;
+    absl::variant<AutofillProfile, std::pair<CreditCard, base::string16>>
+        profile_or_credit_card_with_cvc;
     // Possible identifiers of the field that was focused when the form was
     // initially filled. A refill shall be triggered from the same field.
     // TODO(crbug/896689): Remove |filled_field_unique_name|.
@@ -463,16 +465,17 @@
                                 const AutofillProfile& profile);
 
   // Fills or previews |data_model| in the |form|.
-  void FillOrPreviewDataModelForm(AutofillDriver::RendererFormDataAction action,
-                                  int query_id,
-                                  const FormData& form,
-                                  const FormFieldData& field,
-                                  const AutofillProfile* optional_profile,
-                                  const CreditCard* optional_credit_card,
-                                  const base::string16* optional_cvc,
-                                  FormStructure* form_structure,
-                                  AutofillField* autofill_field,
-                                  bool is_refill = false);
+  void FillOrPreviewDataModelForm(
+      AutofillDriver::RendererFormDataAction action,
+      int query_id,
+      const FormData& form,
+      const FormFieldData& field,
+      absl::variant<const AutofillProfile*, const CreditCard*>
+          profile_or_credit_card,
+      const base::string16* optional_cvc,
+      FormStructure* form_structure,
+      AutofillField* autofill_field,
+      bool is_refill = false);
 
   // Creates a FormStructure using the FormData received from the renderer. Will
   // return an empty scoped_ptr if the data should not be processed for upload
@@ -547,13 +550,15 @@
       size_t current_index,
       const ServerFieldTypeSet& upload_types);
 
-  void FillFieldWithValue(AutofillField* autofill_field,
-                          const AutofillDataModel& data_model,
-                          FormFieldData* field_data,
-                          bool should_notify,
-                          const base::string16& cvc,
-                          uint32_t profile_form_bitmask,
-                          std::string* failure_to_fill);
+  void FillFieldWithValue(
+      AutofillField* autofill_field,
+      absl::variant<const AutofillProfile*, const CreditCard*>
+          profile_or_credit_card,
+      FormFieldData* field_data,
+      bool should_notify,
+      const base::string16& cvc,
+      uint32_t profile_form_bitmask,
+      std::string* failure_to_fill);
 
   // TODO(crbug/896689): Remove code duplication once experiment is finished.
   void SetFillingContext(const FormStructure& form,
diff --git a/components/autofill/core/browser/data_model/autofill_structured_address_component.h b/components/autofill/core/browser/data_model/autofill_structured_address_component.h
index 2284008..b4a4f81 100644
--- a/components/autofill/core/browser/data_model/autofill_structured_address_component.h
+++ b/components/autofill/core/browser/data_model/autofill_structured_address_component.h
@@ -67,8 +67,7 @@
   kUseNewerIfDifferent = 1 << 5,
   // If the newer component contains one token more, apply a recursive strategy
   // to merge the tokens.
-  kRecursivelyMergeSingleTokenSubset =
-      1 << 6 | kRecursivelyMergeTokenEquivalentValues,
+  kRecursivelyMergeSingleTokenSubset = 1 << 6,
   // If one is a substring use the most recent one.
   kUseMostRecentSubstring = 1 << 7,
   // Merge the child nodes and reformat the node from its children after merge.
diff --git a/components/autofill/core/browser/field_filler.cc b/components/autofill/core/browser/field_filler.cc
index 849661ab..add65ac 100644
--- a/components/autofill/core/browser/field_filler.cc
+++ b/components/autofill/core/browser/field_filler.cc
@@ -19,8 +19,6 @@
 #include "components/autofill/core/browser/autofill_field.h"
 #include "components/autofill/core/browser/autofill_type.h"
 #include "components/autofill/core/browser/data_model/autofill_data_model.h"
-#include "components/autofill/core/browser/data_model/autofill_profile.h"
-#include "components/autofill/core/browser/data_model/credit_card.h"
 #include "components/autofill/core/browser/data_model/data_model_utils.h"
 #include "components/autofill/core/browser/data_model/phone_number.h"
 #include "components/autofill/core/browser/field_types.h"
@@ -540,9 +538,10 @@
 // found, falls back to alternate filling strategies based on the |type|.
 bool FillSelectControl(const AutofillType& type,
                        const base::string16& value,
-                       FormFieldData* field,
-                       const AutofillDataModel& data_model,
+                       absl::variant<const AutofillProfile*, const CreditCard*>
+                           profile_or_credit_card,
                        const std::string& app_locale,
+                       FormFieldData* field,
                        AddressNormalizer* address_normalizer,
                        std::string* failure_to_fill) {
   DCHECK_EQ("select-one", field->form_control_type);
@@ -571,9 +570,10 @@
 
   // If that fails, try specific fallbacks based on the field type.
   if (storable_type == ADDRESS_HOME_STATE) {
-    // Safe to cast the data model to AutofillProfile here.
+    DCHECK(absl::holds_alternative<const AutofillProfile*>(
+        profile_or_credit_card));
     const std::string country_code = data_util::GetCountryCodeWithFallback(
-        static_cast<const AutofillProfile&>(data_model), app_locale);
+        *absl::get<const AutofillProfile*>(profile_or_credit_card), app_locale);
     return FillStateSelectControl(value, field, country_code,
                                   address_normalizer, failure_to_fill);
   }
@@ -813,12 +813,20 @@
 
 FieldFiller::~FieldFiller() {}
 
-bool FieldFiller::FillFormField(const AutofillField& field,
-                                const AutofillDataModel& data_model,
-                                FormFieldData* field_data,
-                                const base::string16& cvc,
-                                std::string* failure_to_fill) {
+bool FieldFiller::FillFormField(
+    const AutofillField& field,
+    absl::variant<const AutofillProfile*, const CreditCard*>
+        profile_or_credit_card,
+    FormFieldData* field_data,
+    const base::string16& cvc,
+    std::string* failure_to_fill) {
   const AutofillType type = field.Type();
+  const AutofillDataModel& data_model = [&]() -> const AutofillDataModel& {
+    if (absl::holds_alternative<const AutofillProfile*>(profile_or_credit_card))
+      return *absl::get<const AutofillProfile*>(profile_or_credit_card);
+    else
+      return *absl::get<const CreditCard*>(profile_or_credit_card);
+  }();
 
   if (data_model.ShouldSkipFillingOrSuggesting(type.GetStorableType())) {
     if (failure_to_fill)
@@ -851,19 +859,21 @@
     return true;
   }
   if (field_data->form_control_type == "select-one") {
-    return FillSelectControl(type, value, field_data, data_model, app_locale_,
-                             address_normalizer_, failure_to_fill);
+    return FillSelectControl(type, value, profile_or_credit_card, app_locale_,
+                             field_data, address_normalizer_, failure_to_fill);
   }
   if (field_data->form_control_type == "month") {
-    // Safe to cast to CreditCard here because month control type only applying
-    // to credit card expirations.
-    FillMonthControl(static_cast<const CreditCard&>(data_model), field_data);
+    DCHECK(absl::holds_alternative<const CreditCard*>(profile_or_credit_card));
+    FillMonthControl(*absl::get<const CreditCard*>(profile_or_credit_card),
+                     field_data);
     return true;
   }
   if (type.GetStorableType() == ADDRESS_HOME_STREET_ADDRESS) {
-    // Safe to cast to AutofillProfile here because of the address |type|.
-    const std::string profile_language_code =
-        static_cast<const AutofillProfile&>(data_model).language_code();
+    DCHECK(absl::holds_alternative<const AutofillProfile*>(
+        profile_or_credit_card));
+    const std::string& profile_language_code =
+        absl::get<const AutofillProfile*>(profile_or_credit_card)
+            ->language_code();
     FillStreetAddress(value, profile_language_code, field_data);
     return true;
   }
@@ -872,9 +882,11 @@
     return true;
   }
   if (type.GetStorableType() == ADDRESS_HOME_STATE) {
-    // TODO(crbug.com/1147883): Static casts are unsafe
-    const std::string country_code = data_util::GetCountryCodeWithFallback(
-        static_cast<const AutofillProfile&>(data_model), app_locale_);
+    DCHECK(absl::holds_alternative<const AutofillProfile*>(
+        profile_or_credit_card));
+    const std::string& country_code = data_util::GetCountryCodeWithFallback(
+        *absl::get<const AutofillProfile*>(profile_or_credit_card),
+        app_locale_);
     return FillStateText(value, country_code, field_data, failure_to_fill);
   }
   if (field_data->form_control_type == "text" &&
diff --git a/components/autofill/core/browser/field_filler.h b/components/autofill/core/browser/field_filler.h
index 85ddb2b..d549587 100644
--- a/components/autofill/core/browser/field_filler.h
+++ b/components/autofill/core/browser/field_filler.h
@@ -9,12 +9,14 @@
 
 #include "base/macros.h"
 #include "base/strings/string16.h"
+#include "components/autofill/core/browser/data_model/autofill_profile.h"
+#include "components/autofill/core/browser/data_model/credit_card.h"
 #include "components/autofill/core/common/form_field_data.h"
+#include "third_party/abseil-cpp/absl/types/variant.h"
 
 namespace autofill {
 
 class AddressNormalizer;
-class AutofillDataModel;
 class AutofillField;
 
 // Helper class to put user content in fields, to eventually send to the
@@ -25,14 +27,14 @@
               AddressNormalizer* address_normalizer);
   ~FieldFiller();
 
-  // Set |field_data|'s value to the right value in |data_model|. Uses |field|
-  // to determine which field type should be filled, and |app_locale_| as hint
-  // when filling exceptional cases like phone number values. Returns |true| if
-  // the field has been filled, false otherwise. |cvc| is not stored in the
-  // data model and may be needed at fill time. If |failure_to_fill| is not
-  // null, errors are reported to that string.
+  // Set |field_data|'s value to the right value in |profile_or_credit_card|.
+  // Uses |field| to determine which field type should be filled, and
+  // |app_locale_| as hint when filling exceptional cases like phone number
+  // values. Returns |true| if the field has been filled, false otherwise. If
+  // |failure_to_fill| is not null, errors are reported to that string.
   bool FillFormField(const AutofillField& field,
-                     const AutofillDataModel& data_model,
+                     absl::variant<const AutofillProfile*, const CreditCard*>
+                         profile_or_credit_card,
                      FormFieldData* field_data,
                      const base::string16& cvc,
                      std::string* failure_to_fill = nullptr);
diff --git a/components/autofill/core/browser/field_filler_unittest.cc b/components/autofill/core/browser/field_filler_unittest.cc
index 3f3c16c..3959b74 100644
--- a/components/autofill/core/browser/field_filler_unittest.cc
+++ b/components/autofill/core/browser/field_filler_unittest.cc
@@ -101,13 +101,13 @@
   // Try a single-digit month.
   CreditCard card = test::GetCreditCard();
   card.SetExpirationMonth(3);
-  filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
   GetIndexOfValue(field.option_values, field.value, &content_index);
   EXPECT_EQ(ASCIIToUTF16("Mar"), field.option_contents[content_index]);
 
   // Try a two-digit month.
   card.SetExpirationMonth(11);
-  filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
   GetIndexOfValue(field.option_values, field.value, &content_index);
   EXPECT_EQ(ASCIIToUTF16("Nov"), field.option_contents[content_index]);
 }
@@ -126,11 +126,11 @@
   field_city.set_heuristic_type(ADDRESS_HOME_CITY);
 
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field_state, profile, &field_state,
+  filler.FillFormField(field_state, &profile, &field_state,
                        /*cvc=*/base::string16());
   EXPECT_EQ(state, field_state.value);
 
-  filler.FillFormField(field_city, profile, &field_city,
+  filler.FillFormField(field_city, &profile, &field_city,
                        /*cvc=*/base::string16());
   EXPECT_EQ(city, field_city.value);
 }
@@ -366,7 +366,7 @@
   // Non credit card related field.
   address()->SetRawInfo(NAME_FIRST, ASCIIToUTF16("Test"));
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, *address(), &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, address(), &field, /*cvc=*/base::string16());
 
   // Verify that the field is filled in all circumstances.
   EXPECT_EQ(ASCIIToUTF16("Test"), field.value);
@@ -382,7 +382,7 @@
   // Credit card related field.
   credit_card()->SetNumber(ASCIIToUTF16("4111111111111111"));
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, *credit_card(), &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, credit_card(), &field, /*cvc=*/base::string16());
 
   // Verify that the field is filled.
   EXPECT_EQ(ASCIIToUTF16("4111111111111111"), field.value);
@@ -400,7 +400,7 @@
   // Credit card related field.
   credit_card()->SetNumber(ASCIIToUTF16("0123456789999999"));
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, *credit_card(), &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, credit_card(), &field, /*cvc=*/base::string16());
 
   // Verify that the field is filled with the fourth digit of the credit card
   // number.
@@ -419,7 +419,7 @@
   // Credit card related field.
   credit_card()->SetNumber(ASCIIToUTF16("0123456789999999"));
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, *credit_card(), &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, credit_card(), &field, /*cvc=*/base::string16());
 
   // Verify that the field is filled with the full credit card number.
   EXPECT_EQ(ASCIIToUTF16("0123456789999999"), field.value);
@@ -437,7 +437,7 @@
   // Credit card related field.
   credit_card()->SetNumber(ASCIIToUTF16("0123456789999999"));
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, *credit_card(), &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, credit_card(), &field, /*cvc=*/base::string16());
 
   // Verify that the field is filled with the third digit of the credit card
   // number.
@@ -453,7 +453,7 @@
   // Credit card related field.
   credit_card()->SetNumber(ASCIIToUTF16("4111111111111111"));
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, *credit_card(), &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, credit_card(), &field, /*cvc=*/base::string16());
 
   // Verify that the field is filled with only the first digit of the credit
   // card number.
@@ -525,13 +525,13 @@
 
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
   // State is filled, because it's an address field.
-  filler.FillFormField(field_state, profile, &field_state,
+  filler.FillFormField(field_state, &profile, &field_state,
                        /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16("CA"), field_state.value);
 
   // Email is not filled, because it's not an address field, and it doesn't
   // depend on the country.
-  filler.FillFormField(field_email, profile, &field_email,
+  filler.FillFormField(field_email, &profile, &field_email,
                        /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16(""), field_email.value);
 }
@@ -557,7 +557,7 @@
   AutofillProfile address;
   address.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("+15145554578"));
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16(test_case.expected_value), field.value);
 }
 
@@ -607,7 +607,7 @@
   CreditCard card = test::GetCreditCard();
   card.SetExpirationDateFromString(ASCIIToUTF16("12/2023"));
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16(test_case.expected_value), field.value);
 }
 
@@ -670,7 +670,7 @@
   card.SetExpirationDateFromString(ASCIIToUTF16("03/2022"));
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
   bool response =
-      filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+      filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16(test_case.expected_value), field.value);
   EXPECT_EQ(response, test_case.expected_response);
 }
@@ -760,7 +760,7 @@
 
   address()->SetRawInfo(NAME_FIRST, ASCIIToUTF16("Meenie"));
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, *address(), &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, address(), &field, /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16("Meenie"), field.value);
 }
 
@@ -782,7 +782,7 @@
 
   address()->SetRawInfo(NAME_FIRST, ASCIIToUTF16("Miney"));
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, *address(), &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, address(), &field, /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16("2"), field.value);  // Corresponds to "Miney".
 }
 
@@ -836,7 +836,7 @@
   AutofillProfile address = test::GetFullProfile();
   address.SetRawInfo(ADDRESS_HOME_STATE, UTF8ToUTF16(test_case.input_value));
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
   // nullptr means we expect them not to match without normalization.
   if (test_case.expected_value_without_normalization != nullptr) {
     EXPECT_EQ(UTF8ToUTF16(test_case.expected_value_without_normalization),
@@ -849,7 +849,7 @@
                               UTF8ToUTF16(test_case.input_value));
   // Fill a first time without loading the rules for the region.
   FieldFiller canadian_filler(/*app_locale=*/"en-US", normalizer());
-  canadian_filler.FillFormField(field, canadian_address, &field,
+  canadian_filler.FillFormField(field, &canadian_address, &field,
                                 /*cvc=*/base::string16());
   // If the expectation with normalization is nullptr, this means that the same
   // result than without a normalizer is expected.
@@ -864,7 +864,7 @@
 
     // Load the rules and try again.
     normalizer()->LoadRulesForRegion("CA");
-    canadian_filler.FillFormField(field, canadian_address, &field,
+    canadian_filler.FillFormField(field, &canadian_address, &field,
                                   /*cvc=*/base::string16());
     EXPECT_EQ(UTF8ToUTF16(test_case.expected_value_with_normalization),
               field.value);
@@ -933,7 +933,7 @@
   AutofillProfile address = test::GetFullProfile();
   address.SetRawInfo(ADDRESS_HOME_COUNTRY, UTF8ToUTF16("CA"));
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
   EXPECT_EQ(UTF8ToUTF16("Canada"), field.value);
 }
 
@@ -1059,7 +1059,7 @@
   CreditCard card = test::GetCreditCard();
   card.SetExpirationMonth(4);
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16("Apr"), field.value);
 }
 
@@ -1075,7 +1075,7 @@
   CreditCard card = test::GetCreditCard();
   card.SetExpirationMonth(4);
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16("April"), field.value);
 }
 
@@ -1092,7 +1092,7 @@
   CreditCard card = test::GetCreditCard();
   card.SetExpirationMonth(4);
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16("April (04)"), field.value);
 }
 
@@ -1119,10 +1119,10 @@
   CreditCard card = test::GetCreditCard();
   card.SetExpirationMonth(8);
   FieldFiller filler(/*app_locale=*/"fr-FR", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
   EXPECT_EQ(UTF8ToUTF16("08 - AOÛT"), field.value);
   card.SetExpirationMonth(12);
-  filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
   EXPECT_EQ(UTF8ToUTF16("12 - DECEMBRE"), field.value);
 }
 
@@ -1136,15 +1136,15 @@
   CreditCard card = test::GetCreditCard();
   card.SetExpirationMonth(2);
   FieldFiller filler(/*app_locale=*/"fr-FR", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
   EXPECT_EQ(UTF8ToUTF16("FÉVR."), field.value);
 
   card.SetExpirationMonth(1);
-  filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
   EXPECT_EQ(UTF8ToUTF16("JANV"), field.value);
 
   card.SetExpirationMonth(12);
-  filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
   EXPECT_EQ(UTF8ToUTF16("décembre"), field.value);
 }
 
@@ -1160,7 +1160,7 @@
   CreditCard card = test::GetCreditCard();
   card.SetExpirationMonth(4);
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16("4"), field.value);
 }
 
@@ -1174,7 +1174,7 @@
   CreditCard card = test::GetCreditCard();
   card.SetExpirationYear(2017);
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16("17"), field.value);
 }
 
@@ -1189,22 +1189,22 @@
 
   // Normal case:
   card.SetNumber(ASCIIToUTF16("4111111111111111"));  // Visa number.
-  filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16("Visa"), field.value);
 
   // Filling should be able to handle intervening whitespace:
   card.SetNumber(ASCIIToUTF16("5555555555554444"));  // MC number.
-  filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16("Mastercard"), field.value);
 
   // American Express is sometimes abbreviated as AmEx:
   card.SetNumber(ASCIIToUTF16("378282246310005"));  // Amex number.
-  filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16("AmEx"), field.value);
 
   // Case insensitivity:
   card.SetNumber(ASCIIToUTF16("6011111111111117"));  // Discover number.
-  filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16("discover"), field.value);
 }
 
@@ -1217,12 +1217,12 @@
   // Try a month with two digits.
   CreditCard card = test::GetCreditCard();
   card.SetExpirationDateFromString(ASCIIToUTF16("12/2017"));
-  filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16("2017-12"), field.value);
 
   // Try a month with a leading zero.
   card.SetExpirationDateFromString(ASCIIToUTF16("03/2019"));
-  filler.FillFormField(field, card, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &card, &field, /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16("2019-03"), field.value);
 }
 
@@ -1236,7 +1236,7 @@
       "123 Fake St.\n"
       "Apt. 42");
   address()->SetInfo(AutofillType(ADDRESS_HOME_STREET_ADDRESS), value, "en-US");
-  filler.FillFormField(field, *address(), &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, address(), &field, /*cvc=*/base::string16());
   EXPECT_EQ(value, field.value);
 
   base::string16 ja_value = UTF8ToUTF16(
@@ -1245,7 +1245,7 @@
   address()->SetInfo(AutofillType(ADDRESS_HOME_STREET_ADDRESS), ja_value,
                      "ja-JP");
   address()->set_language_code("ja-JP");
-  filler.FillFormField(field, *address(), &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, address(), &field, /*cvc=*/base::string16());
   EXPECT_EQ(ja_value, field.value);
 }
 
@@ -1259,7 +1259,7 @@
       "123 Fake St.\n"
       "Apt. 42");
   address()->SetInfo(AutofillType(ADDRESS_HOME_STREET_ADDRESS), value, "en-US");
-  filler.FillFormField(field, *address(), &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, address(), &field, /*cvc=*/base::string16());
   EXPECT_EQ(UTF8ToUTF16("123 Fake St., Apt. 42"), field.value);
 
   base::string16 ja_value = UTF8ToUTF16(
@@ -1268,7 +1268,7 @@
   address()->SetInfo(AutofillType(ADDRESS_HOME_STREET_ADDRESS), ja_value,
                      "ja-JP");
   address()->set_language_code("ja-JP");
-  filler.FillFormField(field, *address(), &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, address(), &field, /*cvc=*/base::string16());
   EXPECT_EQ(UTF8ToUTF16("桜丘町26-1セルリアンタワー6階"), field.value);
 }
 
@@ -1279,7 +1279,7 @@
 
   credit_card()->SetNumber(ASCIIToUTF16("41111111111111111"));
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(cc_number_full, *credit_card(), &cc_number_full,
+  filler.FillFormField(cc_number_full, credit_card(), &cc_number_full,
                        /*cvc=*/base::string16());
 
   // Verify that full card-number shall get filled properly.
@@ -1307,7 +1307,7 @@
 
     // Fill with a card-number; should fill just the card_number_part.
     credit_card()->SetNumber(ASCIIToUTF16(test.card_number_));
-    filler.FillFormField(cc_number_part, *credit_card(), &cc_number_part,
+    filler.FillFormField(cc_number_part, credit_card(), &cc_number_part,
                          /*cvc=*/base::string16());
 
     // Verify for expected results.
@@ -1321,7 +1321,7 @@
   cc_number_full.set_heuristic_type(CREDIT_CARD_NUMBER);
 
   credit_card()->SetNumber(ASCIIToUTF16(test.card_number_));
-  filler.FillFormField(cc_number_full, *credit_card(), &cc_number_full,
+  filler.FillFormField(cc_number_full, credit_card(), &cc_number_full,
                        /*cvc=*/base::string16());
 
   // Verify for expected results.
@@ -1350,7 +1350,7 @@
 
     // Fill with a card-number; should fill just the card_number_part.
     credit_card()->SetNumber(ASCIIToUTF16(test.card_number_));
-    filler.FillFormField(cc_number_part, *credit_card(), &cc_number_part,
+    filler.FillFormField(cc_number_part, credit_card(), &cc_number_part,
                          /*cvc=*/base::string16());
 
     // Verify for expected results.
@@ -1364,7 +1364,7 @@
   AutofillField cc_number_full;
   cc_number_full.set_heuristic_type(CREDIT_CARD_NUMBER);
   credit_card()->SetNumber(ASCIIToUTF16(test.card_number_));
-  filler.FillFormField(cc_number_full, *credit_card(), &cc_number_full,
+  filler.FillFormField(cc_number_full, credit_card(), &cc_number_full,
                        /*cvc=*/base::string16());
 
   // Verify for expected results.
@@ -1439,7 +1439,7 @@
   AutofillProfile address = test::GetFullProfile();
   address.SetRawInfo(ADDRESS_HOME_STATE, UTF8ToUTF16(test_case.value_to_fill));
   bool has_filled =
-      filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+      filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
 
   EXPECT_EQ(test_case.should_fill, has_filled);
   EXPECT_EQ(ASCIIToUTF16(test_case.expected_value), field.value);
@@ -1493,7 +1493,7 @@
   AutofillProfile address;
   address.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("+15145554578"));
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16("1"), field.value);
 }
 
@@ -1514,7 +1514,7 @@
   AutofillProfile address;
   address.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("+918890888888"));
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16("+91"), field.value);
 }
 
@@ -1535,7 +1535,7 @@
   AutofillProfile address;
   address.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("+918890888888"));
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16("0091"), field.value);
 }
 
@@ -1556,7 +1556,7 @@
   AutofillProfile address;
   address.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("+49151669087345"));
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16("+49 (Germany)"), field.value);
 }
 
@@ -1578,7 +1578,7 @@
   AutofillProfile address;
   address.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("+49151669087345"));
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16("(00 49) Germany"), field.value);
 }
 
@@ -1601,7 +1601,7 @@
   AutofillProfile address;
   address.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("+49151669087345"));
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16("(0049) Germany"), field.value);
 }
 
@@ -1623,7 +1623,7 @@
   address.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("DE"));
 
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16("BY"), field.value);
 }
 
@@ -1646,7 +1646,7 @@
   address.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("DE"));
 
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16("Bayern"), field.value);
 }
 
@@ -1669,7 +1669,7 @@
   address.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("DE"));
 
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16("Bavaria Has Munich"), field.value);
 }
 
@@ -1692,7 +1692,7 @@
   address.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("DE"));
 
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16("BY"), field.value);
 }
 
@@ -1715,7 +1715,7 @@
   address.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("DE"));
 
   FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
-  filler.FillFormField(field, address, &field, /*cvc=*/base::string16());
+  filler.FillFormField(field, &address, &field, /*cvc=*/base::string16());
   EXPECT_EQ(ASCIIToUTF16("Bavari"), field.value);
 }
 
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc
index c95b048..301ed1a 100644
--- a/components/autofill/core/browser/personal_data_manager.cc
+++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -601,46 +601,58 @@
     observer.OnInsufficientFormData();
 }
 
-void PersonalDataManager::RecordUseOf(const AutofillDataModel& data_model) {
+void PersonalDataManager::RecordUseOf(
+    absl::variant<const AutofillProfile*, const CreditCard*>
+        profile_or_credit_card) {
   if (is_off_the_record_)
     return;
 
-  CreditCard* credit_card = GetCreditCardByGUID(data_model.guid());
-  if (credit_card) {
-    credit_card->RecordAndLogUse();
+  if (absl::holds_alternative<const CreditCard*>(profile_or_credit_card)) {
+    CreditCard* credit_card = GetCreditCardByGUID(
+        absl::get<const CreditCard*>(profile_or_credit_card)->guid());
 
-    if (credit_card->record_type() == CreditCard::LOCAL_CARD) {
-      // Fail silently if there's no local database, because we need to support
-      // this for tests.
-      if (database_helper_->GetLocalDatabase()) {
-        database_helper_->GetLocalDatabase()->UpdateCreditCard(*credit_card);
+    if (credit_card) {
+      credit_card->RecordAndLogUse();
+
+      if (credit_card->record_type() == CreditCard::LOCAL_CARD) {
+        // Fail silently if there's no local database, because we need to
+        // support this for tests.
+        if (database_helper_->GetLocalDatabase()) {
+          database_helper_->GetLocalDatabase()->UpdateCreditCard(*credit_card);
+        }
+      } else {
+        DCHECK(database_helper_->GetServerDatabase())
+            << "Recording use of server card without server storage.";
+        database_helper_->GetServerDatabase()->UpdateServerCardMetadata(
+            *credit_card);
       }
-    } else {
-      DCHECK(database_helper_->GetServerDatabase())
-          << "Recording use of server card without server storage.";
-      database_helper_->GetServerDatabase()->UpdateServerCardMetadata(
-          *credit_card);
-    }
 
-    Refresh();
-    return;
+      Refresh();
+      return;
+    }
   }
 
-  AutofillProfile* profile = GetProfileByGUID(data_model.guid());
-  if (profile) {
-    profile->RecordAndLogUse();
+  if (absl::holds_alternative<const AutofillProfile*>(profile_or_credit_card)) {
+    // TODO(crbug.com/941498): Server profiles are not recorded therefore
+    // GetProfileByGUID returns null for them.
+    AutofillProfile* profile = GetProfileByGUID(
+        absl::get<const AutofillProfile*>(profile_or_credit_card)->guid());
 
-    switch (profile->record_type()) {
-      case AutofillProfile::LOCAL_PROFILE:
-        UpdateProfileInDB(*profile, /*enforced=*/true);
-        break;
-      case AutofillProfile::SERVER_PROFILE:
-        DCHECK(database_helper_->GetServerDatabase())
-            << "Recording use of server address without server storage.";
-        database_helper_->GetServerDatabase()->UpdateServerAddressMetadata(
-            *profile);
-        Refresh();
-        break;
+    if (profile) {
+      profile->RecordAndLogUse();
+
+      switch (profile->record_type()) {
+        case AutofillProfile::LOCAL_PROFILE:
+          UpdateProfileInDB(*profile, /*enforced=*/true);
+          break;
+        case AutofillProfile::SERVER_PROFILE:
+          DCHECK(database_helper_->GetServerDatabase())
+              << "Recording use of server address without server storage.";
+          database_helper_->GetServerDatabase()->UpdateServerAddressMetadata(
+              *profile);
+          Refresh();
+          break;
+      }
     }
   }
 }
diff --git a/components/autofill/core/browser/personal_data_manager.h b/components/autofill/core/browser/personal_data_manager.h
index 7f14296..e98c992 100644
--- a/components/autofill/core/browser/personal_data_manager.h
+++ b/components/autofill/core/browser/personal_data_manager.h
@@ -145,9 +145,11 @@
   // imported from a form.
   void MarkObserversInsufficientFormDataForImport();
 
-  // Called to indicate |data_model| was used (to fill in a form). Updates
-  // the database accordingly. Can invalidate |data_model|.
-  virtual void RecordUseOf(const AutofillDataModel& data_model);
+  // Called to indicate |profile_or_credit_card| was used (to fill in a form).
+  // Updates the database accordingly.
+  virtual void RecordUseOf(
+      absl::variant<const AutofillProfile*, const CreditCard*>
+          profile_or_credit_card);
 
   // Saves |imported_profile| to the WebDB if it exists. Returns the guid of
   // the new or updated profile, or the empty string if no profile was saved.
diff --git a/components/autofill/core/browser/personal_data_manager_unittest.cc b/components/autofill/core/browser/personal_data_manager_unittest.cc
index d19607c9..670736b 100644
--- a/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -3970,7 +3970,7 @@
   EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
       .WillOnce(QuitMessageLoop(&profile_run_loop));
   EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1);
-  personal_data_->RecordUseOf(profile);
+  personal_data_->RecordUseOf(&profile);
   profile_run_loop.Run();
 
   added_profile = personal_data_->GetProfileByGUID(profile.guid());
@@ -3985,7 +3985,7 @@
   EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
       .WillOnce(QuitMessageLoop(&credit_card_run_loop));
   EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1);
-  personal_data_->RecordUseOf(credit_card);
+  personal_data_->RecordUseOf(&credit_card);
   credit_card_run_loop.Run();
 
   added_profile = personal_data_->GetProfileByGUID(profile.guid());
diff --git a/components/autofill/core/browser/test_personal_data_manager.cc b/components/autofill/core/browser/test_personal_data_manager.cc
index 3380a826..d0ed404 100644
--- a/components/autofill/core/browser/test_personal_data_manager.cc
+++ b/components/autofill/core/browser/test_personal_data_manager.cc
@@ -23,14 +23,24 @@
   return sync_and_signin_state_;
 }
 
-void TestPersonalDataManager::RecordUseOf(const AutofillDataModel& data_model) {
-  CreditCard* credit_card = GetCreditCardWithGUID(data_model.guid().c_str());
-  if (credit_card)
-    credit_card->RecordAndLogUse();
+void TestPersonalDataManager::RecordUseOf(
+    absl::variant<const AutofillProfile*, const CreditCard*>
+        profile_or_credit_card) {
+  if (absl::holds_alternative<const CreditCard*>(profile_or_credit_card)) {
+    CreditCard* credit_card = GetCreditCardByGUID(
+        absl::get<const CreditCard*>(profile_or_credit_card)->guid());
 
-  AutofillProfile* profile = GetProfileWithGUID(data_model.guid().c_str());
-  if (profile)
-    profile->RecordAndLogUse();
+    if (credit_card)
+      credit_card->RecordAndLogUse();
+  }
+
+  if (absl::holds_alternative<const AutofillProfile*>(profile_or_credit_card)) {
+    AutofillProfile* profile = GetProfileByGUID(
+        absl::get<const AutofillProfile*>(profile_or_credit_card)->guid());
+
+    if (profile)
+      profile->RecordAndLogUse();
+  }
 }
 
 std::string TestPersonalDataManager::SaveImportedProfile(
diff --git a/components/autofill/core/browser/test_personal_data_manager.h b/components/autofill/core/browser/test_personal_data_manager.h
index 0f5d004..eaf5473 100644
--- a/components/autofill/core/browser/test_personal_data_manager.h
+++ b/components/autofill/core/browser/test_personal_data_manager.h
@@ -32,7 +32,8 @@
   // or to make things easier in general to toggle.
   void OnSyncServiceInitialized(syncer::SyncService* sync_service) override;
   AutofillSyncSigninState GetSyncSigninState() const override;
-  void RecordUseOf(const AutofillDataModel& data_model) override;
+  void RecordUseOf(absl::variant<const AutofillProfile*, const CreditCard*>
+                       profile_or_credit_card) override;
   std::string SaveImportedProfile(
       const AutofillProfile& imported_profile) override;
   std::string SaveImportedCreditCard(
diff --git a/components/autofill_assistant/browser/actions/action_delegate.h b/components/autofill_assistant/browser/actions/action_delegate.h
index a7bc8ddbf..acb25cc1 100644
--- a/components/autofill_assistant/browser/actions/action_delegate.h
+++ b/components/autofill_assistant/browser/actions/action_delegate.h
@@ -445,6 +445,14 @@
   virtual void SetOverlayBehavior(
       ConfigureUiStateProto::OverlayBehavior overlay_behavior) = 0;
 
+  // Maybe shows a warning letting the user know that the website is unusually
+  // slow, depending on the current settings.
+  virtual void MaybeShowSlowWebsiteWarning() = 0;
+
+  // Maybe shows a warning letting the user know that a slow connection was
+  // detected, depending on the current settings.
+  virtual void MaybeShowSlowConnectionWarning() = 0;
+
   virtual base::WeakPtr<ActionDelegate> GetWeakPtr() const = 0;
 
  protected:
diff --git a/components/autofill_assistant/browser/actions/mock_action_delegate.h b/components/autofill_assistant/browser/actions/mock_action_delegate.h
index c35b389..05990f9 100644
--- a/components/autofill_assistant/browser/actions/mock_action_delegate.h
+++ b/components/autofill_assistant/browser/actions/mock_action_delegate.h
@@ -323,6 +323,9 @@
   MOCK_METHOD1(SetOverlayBehavior,
                void(ConfigureUiStateProto::OverlayBehavior));
 
+  MOCK_METHOD0(MaybeShowSlowWebsiteWarning, void());
+  MOCK_METHOD0(MaybeShowSlowConnectionWarning, void());
+
   base::WeakPtr<ActionDelegate> GetWeakPtr() const override {
     return weak_ptr_factory_.GetWeakPtr();
   }
diff --git a/components/autofill_assistant/browser/client_settings.cc b/components/autofill_assistant/browser/client_settings.cc
index 620586a..812e8b2 100644
--- a/components/autofill_assistant/browser/client_settings.cc
+++ b/components/autofill_assistant/browser/client_settings.cc
@@ -105,7 +105,39 @@
       back_button_settings.reset();
     }
   }
-
+  if (proto.has_slow_warning_settings()) {
+    if (proto.slow_warning_settings().has_enable_slow_connection_warnings()) {
+      enable_slow_connection_warnings =
+          proto.slow_warning_settings().enable_slow_connection_warnings();
+    }
+    if (proto.slow_warning_settings().has_enable_slow_website_warnings()) {
+      enable_slow_website_warnings =
+          proto.slow_warning_settings().enable_slow_website_warnings();
+    }
+    if (proto.slow_warning_settings().has_show_only_once()) {
+      only_show_warning_once = proto.slow_warning_settings().show_only_once();
+    }
+    if (proto.slow_warning_settings().has_warning_delay_ms()) {
+      timeout_warning_delay = base::TimeDelta::FromMilliseconds(
+          proto.slow_warning_settings().warning_delay_ms());
+    }
+    if (proto.slow_warning_settings().has_slow_roundtrip_threshold_ms()) {
+      slow_roundtrip_threshold = base::TimeDelta::FromMilliseconds(
+          proto.slow_warning_settings().slow_roundtrip_threshold_ms());
+    }
+    if (proto.slow_warning_settings().has_max_consecutive_slow_roundtrips()) {
+      max_consecutive_slow_roundtrips =
+          proto.slow_warning_settings().max_consecutive_slow_roundtrips();
+    }
+    if (proto.slow_warning_settings().has_slow_connection_message()) {
+      slow_connection_message =
+          proto.slow_warning_settings().slow_connection_message();
+    }
+    if (proto.slow_warning_settings().has_slow_website_message()) {
+      slow_website_message =
+          proto.slow_warning_settings().slow_website_message();
+    }
+  }
   // Test only settings.
   if (proto.has_integration_test_settings()) {
     integration_test_settings = proto.integration_test_settings();
diff --git a/components/autofill_assistant/browser/client_settings.h b/components/autofill_assistant/browser/client_settings.h
index 25d50c9..f754ea0 100644
--- a/components/autofill_assistant/browser/client_settings.h
+++ b/components/autofill_assistant/browser/client_settings.h
@@ -9,6 +9,7 @@
 #include "base/optional.h"
 #include "base/time/time.h"
 #include "components/autofill_assistant/browser/service.pb.h"
+#include "components/strings/grit/components_strings.h"
 
 namespace autofill_assistant {
 
@@ -89,6 +90,17 @@
   // Snackbar.
   base::Optional<ClientSettingsProto::BackButtonSettings> back_button_settings;
 
+  bool enable_slow_connection_warnings = false;
+  bool enable_slow_website_warnings = false;
+  bool only_show_warning_once = false;
+  base::TimeDelta timeout_warning_delay =
+      base::TimeDelta::FromMilliseconds(1000);
+  int max_consecutive_slow_roundtrips = 3;
+  base::TimeDelta slow_roundtrip_threshold =
+      base::TimeDelta::FromMilliseconds(500);
+  std::string slow_connection_message = "";
+  std::string slow_website_message = "";
+
  private:
   DISALLOW_COPY_AND_ASSIGN(ClientSettings);
 };
diff --git a/components/autofill_assistant/browser/controller.cc b/components/autofill_assistant/browser/controller.cc
index d54e5c6..492ea9f 100644
--- a/components/autofill_assistant/browser/controller.cc
+++ b/components/autofill_assistant/browser/controller.cc
@@ -508,6 +508,11 @@
   browse_mode_invisible_ = invisible;
 }
 
+bool Controller::ShouldShowWarning() {
+  return state_ == AutofillAssistantState::RUNNING ||
+         state_ == AutofillAssistantState::PROMPT;
+}
+
 void Controller::AddNavigationListener(
     ScriptExecutorDelegate::NavigationListener* listener) {
   navigation_listeners_.AddObserver(listener);
diff --git a/components/autofill_assistant/browser/controller.h b/components/autofill_assistant/browser/controller.h
index 219c2ec..a01e3c8 100644
--- a/components/autofill_assistant/browser/controller.h
+++ b/components/autofill_assistant/browser/controller.h
@@ -154,6 +154,7 @@
           view_inflation_finished_callback) override;
   void ClearGenericUi() override;
   void SetBrowseModeInvisible(bool invisible) override;
+  bool ShouldShowWarning() override;
 
   // Show the UI if it's not already shown. This is only meaningful while in
   // states where showing the UI is optional, such as RUNNING, in tracking mode.
diff --git a/components/autofill_assistant/browser/fake_script_executor_delegate.cc b/components/autofill_assistant/browser/fake_script_executor_delegate.cc
index 5ae3812..1416ff3 100644
--- a/components/autofill_assistant/browser/fake_script_executor_delegate.cc
+++ b/components/autofill_assistant/browser/fake_script_executor_delegate.cc
@@ -86,11 +86,11 @@
 }
 
 void FakeScriptExecutorDelegate::SetBubbleMessage(const std::string& message) {
-  status_message_ = message;
+  bubble_message_ = message;
 }
 
 std::string FakeScriptExecutorDelegate::GetBubbleMessage() const {
-  return status_message_;
+  return bubble_message_;
 }
 
 void FakeScriptExecutorDelegate::SetDetails(std::unique_ptr<Details> details,
@@ -264,4 +264,8 @@
 
 void FakeScriptExecutorDelegate::SetBrowseModeInvisible(bool invisible) {}
 
+bool FakeScriptExecutorDelegate::ShouldShowWarning() {
+  return true;
+}
+
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/fake_script_executor_delegate.h b/components/autofill_assistant/browser/fake_script_executor_delegate.h
index a5a4409..70b17df 100644
--- a/components/autofill_assistant/browser/fake_script_executor_delegate.h
+++ b/components/autofill_assistant/browser/fake_script_executor_delegate.h
@@ -101,6 +101,8 @@
       ConfigureUiStateProto::OverlayBehavior overlay_behavior) override;
   void SetBrowseModeInvisible(bool invisible) override;
 
+  bool ShouldShowWarning() override;
+
   ClientSettings* GetMutableSettings() { return &client_settings_; }
 
   void SetCurrentURL(const GURL& url) { current_url_ = url; }
@@ -120,10 +122,10 @@
   }
 
   void SetUserModel(UserModel* user_model) { user_model_ = user_model; }
-
   std::vector<AutofillAssistantState> GetStateHistory() {
     return state_history_;
   }
+
   AutofillAssistantState GetState() const {
     return state_history_.empty() ? AutofillAssistantState::INACTIVE
                                   : state_history_.back();
@@ -161,6 +163,7 @@
   std::unique_ptr<TriggerContext> trigger_context_;
   std::vector<AutofillAssistantState> state_history_;
   std::string status_message_;
+  std::string bubble_message_;
   std::vector<Details> details_;
   std::unique_ptr<InfoBox> info_box_;
   std::unique_ptr<std::vector<UserAction>> user_actions_;
diff --git a/components/autofill_assistant/browser/script_executor.cc b/components/autofill_assistant/browser/script_executor.cc
index daf2f2a..4689c86 100644
--- a/components/autofill_assistant/browser/script_executor.cc
+++ b/components/autofill_assistant/browser/script_executor.cc
@@ -296,6 +296,9 @@
                           weak_ptr_factory_.GetWeakPtr(), selector),
       base::BindOnce(&ScriptExecutor::OnShortWaitForElement,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+  current_action_data_.wait_for_dom->SetTimeoutWarningCallback(
+      base::BindOnce(&ScriptExecutor::MaybeShowSlowWebsiteWarning,
+                     weak_ptr_factory_.GetWeakPtr()));
   current_action_data_.wait_for_dom->Run();
 }
 
@@ -310,6 +313,9 @@
       this, delegate_, max_wait_time, allow_interrupt, check_elements,
       base::BindOnce(&ScriptExecutor::OnWaitForElementVisibleWithInterrupts,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+  current_action_data_.wait_for_dom->SetTimeoutWarningCallback(base::BindOnce(
+      &ScriptExecutor::SetBubbleMessage, weak_ptr_factory_.GetWeakPtr(),
+      delegate_->GetSettings().slow_website_message));
   current_action_data_.wait_for_dom->Run();
 }
 
@@ -829,6 +835,32 @@
   delegate_->SetOverlayBehavior(overlay_behavior);
 }
 
+void ScriptExecutor::MaybeShowSlowWebsiteWarning() {
+  MaybeShowSlowWarning(delegate_->GetSettings().slow_website_message,
+                       delegate_->GetSettings().enable_slow_website_warnings);
+}
+
+void ScriptExecutor::MaybeShowSlowConnectionWarning() {
+  MaybeShowSlowWarning(
+      delegate_->GetSettings().slow_connection_message,
+      delegate_->GetSettings().enable_slow_connection_warnings);
+}
+
+void ScriptExecutor::MaybeShowSlowWarning(const std::string& message,
+                                          bool enabled) {
+  if (message.empty() || !enabled || !delegate_->ShouldShowWarning()) {
+    return;
+  }
+
+  if (delegate_->GetSettings().only_show_warning_once &&
+      warning_callout_already_shown_) {
+    return;
+  }
+
+  warning_callout_already_shown_ = true;
+  SetBubbleMessage(message);
+}
+
 base::WeakPtr<ActionDelegate> ScriptExecutor::GetWeakPtr() const {
   return weak_ptr_factory_.GetWeakPtr();
 }
@@ -838,8 +870,10 @@
                                   const std::string& response) {
   VLOG(2) << __func__ << " http-status=" << http_status;
   batch_start_time_ = base::TimeTicks::Now();
+  const base::TimeDelta& roundtrip_duration = batch_start_time_ - start_time;
+  // Doesn't trigger when the script is completed.
   roundtrip_timing_stats_.set_roundtrip_time_ms(
-      (batch_start_time_ - start_time).InMilliseconds());
+      roundtrip_duration.InMilliseconds());
   bool success =
       http_status == net::HTTP_OK && ProcessNextActionResponse(response);
   if (should_stop_script_) {
@@ -857,6 +891,16 @@
   }
 
   if (!actions_.empty()) {
+    if (roundtrip_duration >
+        delegate_->GetSettings().slow_roundtrip_threshold) {
+      consecutive_slow_roundtrip_counter_++;
+      if (consecutive_slow_roundtrip_counter_ >=
+          delegate_->GetSettings().max_consecutive_slow_roundtrips) {
+        MaybeShowSlowConnectionWarning();
+      }
+    } else {
+      consecutive_slow_roundtrip_counter_ = 0;
+    }
     ProcessNextAction();
     return;
   }
@@ -1077,6 +1121,8 @@
       allow_interrupt_(allow_interrupt),
       check_elements_(std::move(check_elements)),
       callback_(std::move(callback)),
+      timeout_warning_period_(
+          main_script->delegate_->GetSettings().timeout_warning_delay),
       retry_timer_(main_script->delegate_->GetSettings()
                        .periodic_element_check_interval) {}
 
@@ -1090,6 +1136,11 @@
   Start();
 }
 
+void ScriptExecutor::WaitForDomOperation::SetTimeoutWarningCallback(
+    base::OnceCallback<void()> timeout_warning) {
+  timeout_warning_callback_ = std::move(timeout_warning);
+}
+
 void ScriptExecutor::WaitForDomOperation::Start() {
   retry_timer_.Start(
       max_wait_time_,
@@ -1137,8 +1188,19 @@
   main_script_->ReportScriptsUpdateToListener(std::move(scripts));
 }
 
+void ScriptExecutor::WaitForDomOperation::TimeoutWarning() {
+  if (timeout_warning_callback_) {
+    std::move(timeout_warning_callback_).Run();
+  }
+}
+
 void ScriptExecutor::WaitForDomOperation::RunChecks(
     base::OnceCallback<void(const ClientStatus&)> report_attempt_result) {
+  warning_timer_ = std::make_unique<base::OneShotTimer>();
+  warning_timer_->Start(
+      FROM_HERE, timeout_warning_period_,
+      base::BindOnce(&ScriptExecutor::WaitForDomOperation::TimeoutWarning,
+                     weak_ptr_factory_.GetWeakPtr()));
   wait_time_total_ =
       (wait_time_stopwatch_.TotalElapsed() < retry_timer_.period())
           // It's the first run of the checks, set the total time waited to 0.
@@ -1196,6 +1258,7 @@
 
 void ScriptExecutor::WaitForDomOperation::OnAllChecksDone(
     base::OnceCallback<void(const ClientStatus&)> report_attempt_result) {
+  warning_timer_->Stop();
   if (runnable_interrupts_.empty()) {
     // Since no interrupts fired, allow previously-run interrupts to be run
     // again in the next round. This is meant to give elements one round to
diff --git a/components/autofill_assistant/browser/script_executor.h b/components/autofill_assistant/browser/script_executor.h
index 79bd45c..0ded07b 100644
--- a/components/autofill_assistant/browser/script_executor.h
+++ b/components/autofill_assistant/browser/script_executor.h
@@ -273,6 +273,8 @@
   void ClearGenericUi() override;
   void SetOverlayBehavior(
       ConfigureUiStateProto::OverlayBehavior overlay_behavior) override;
+  void MaybeShowSlowWebsiteWarning() override;
+  void MaybeShowSlowConnectionWarning() override;
   base::WeakPtr<ActionDelegate> GetWeakPtr() const override;
 
  private:
@@ -304,6 +306,7 @@
 
     void Run();
     void Terminate();
+    void SetTimeoutWarningCallback(base::OnceCallback<void()> timeout_warning);
 
    private:
     void Start();
@@ -342,6 +345,8 @@
     // the original area.
     void RestorePreInterruptScroll();
 
+    void TimeoutWarning();
+
     ScriptExecutor* main_script_;
     ScriptExecutorDelegate* delegate_;
     const base::TimeDelta max_wait_time_;
@@ -350,6 +355,9 @@
                                  base::OnceCallback<void(const ClientStatus&)>)>
         check_elements_;
     WaitForDomOperation::Callback callback_;
+    base::OnceCallback<void()> timeout_warning_callback_;
+    std::unique_ptr<base::OneShotTimer> warning_timer_;
+    base::TimeDelta timeout_warning_period_;
 
     std::unique_ptr<BatchElementChecker> batch_element_checker_;
 
@@ -449,6 +457,10 @@
   // that they do not overwrite the paused state.
   bool ShouldInterruptOnPause(const ActionProto& proto);
 
+  // Maybe shows the message specified in a callout, depending on the current
+  // state and client settings.
+  void MaybeShowSlowWarning(const std::string& message, bool enabled);
+
   const std::string script_path_;
   std::unique_ptr<TriggerContext> additional_context_;
   std::string last_global_payload_;
@@ -525,6 +537,9 @@
   base::TimeTicks batch_start_time_;
   RoundtripTimingStats roundtrip_timing_stats_;
 
+  bool warning_callout_already_shown_ = false;
+  int consecutive_slow_roundtrip_counter_ = 0;
+
   base::WeakPtrFactory<ScriptExecutor> weak_ptr_factory_{this};
   DISALLOW_COPY_AND_ASSIGN(ScriptExecutor);
 };
diff --git a/components/autofill_assistant/browser/script_executor_delegate.h b/components/autofill_assistant/browser/script_executor_delegate.h
index 78dc335..33e71c2 100644
--- a/components/autofill_assistant/browser/script_executor_delegate.h
+++ b/components/autofill_assistant/browser/script_executor_delegate.h
@@ -192,6 +192,10 @@
   // calling |EnterState(BROWSE)| to take effect.
   virtual void SetBrowseModeInvisible(bool invisible) = 0;
 
+  // Whether the slow connection or website warning should be shown. Depends on
+  // the state at the moment of the invocation.
+  virtual bool ShouldShowWarning() = 0;
+
  protected:
   virtual ~ScriptExecutorDelegate() {}
 };
diff --git a/components/autofill_assistant/browser/script_executor_unittest.cc b/components/autofill_assistant/browser/script_executor_unittest.cc
index 7a86d49..80cdb61 100644
--- a/components/autofill_assistant/browser/script_executor_unittest.cc
+++ b/components/autofill_assistant/browser/script_executor_unittest.cc
@@ -264,6 +264,88 @@
   EXPECT_EQ(1u, processed_actions2_capture.size());
 }
 
+ACTION_P2(Delay, env, delay) {
+  env->FastForwardBy(base::TimeDelta::FromMilliseconds(delay));
+}
+
+TEST_F(ScriptExecutorTest, ShowsSlowConnectionWarning) {
+  ClientSettings* client_settings = delegate_.GetMutableSettings();
+  client_settings->slow_connection_message = "slow";
+  client_settings->enable_slow_connection_warnings = true;
+  client_settings->max_consecutive_slow_roundtrips = 2;
+  ActionsResponseProto initial_actions_response;
+  initial_actions_response.add_actions()->mutable_tell()->set_message("1");
+  EXPECT_CALL(mock_service_, OnGetActions(StrEq(kScriptPath), _, _, _, _, _))
+      .WillOnce(DoAll(Delay(&task_environment_, 600),
+                      RunOnceCallback<5>(net::HTTP_OK,
+                                         Serialize(initial_actions_response))));
+
+  ActionsResponseProto next_actions_response;
+  next_actions_response.add_actions()->mutable_tell()->set_message("2");
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+      .WillOnce(DoAll(Delay(&task_environment_, 600),
+                      RunOnceCallback<5>(net::HTTP_OK,
+                                         Serialize(initial_actions_response))))
+      .WillOnce(RunOnceCallback<5>(net::HTTP_OK, ""));
+  EXPECT_CALL(executor_callback_,
+              Run(Field(&ScriptExecutor::Result::success, true)));
+  executor_->Run(&user_data_, executor_callback_.Get());
+
+  EXPECT_EQ(delegate_.GetBubbleMessage(), "slow");
+}
+
+TEST_F(ScriptExecutorTest, SlowConnectionWarningNotShowingIfNotConsecutive) {
+  ClientSettings* client_settings = delegate_.GetMutableSettings();
+  client_settings->slow_connection_message = "slow";
+  client_settings->enable_slow_connection_warnings = true;
+  client_settings->max_consecutive_slow_roundtrips = 2;
+  ActionsResponseProto initial_actions_response;
+  initial_actions_response.add_actions()->mutable_tell()->set_message("1");
+  EXPECT_CALL(mock_service_, OnGetActions(StrEq(kScriptPath), _, _, _, _, _))
+      .WillOnce(DoAll(Delay(&task_environment_, 600),
+                      RunOnceCallback<5>(net::HTTP_OK,
+                                         Serialize(initial_actions_response))));
+
+  ActionsResponseProto next_actions_response;
+  next_actions_response.add_actions()->mutable_tell()->set_message("2");
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+      .WillOnce(DoAll(RunOnceCallback<5>(net::HTTP_OK,
+                                         Serialize(initial_actions_response))))
+      .WillOnce(DoAll(Delay(&task_environment_, 600),
+                      RunOnceCallback<5>(net::HTTP_OK,
+                                         Serialize(initial_actions_response))))
+      .WillOnce(RunOnceCallback<5>(net::HTTP_OK, ""));
+  EXPECT_CALL(executor_callback_,
+              Run(Field(&ScriptExecutor::Result::success, true)));
+  executor_->Run(&user_data_, executor_callback_.Get());
+
+  EXPECT_NE(delegate_.GetBubbleMessage(), "slow");
+}
+
+TEST_F(ScriptExecutorTest, SlowConnectionWarningNotShowingIfOnCompleted) {
+  ClientSettings* client_settings = delegate_.GetMutableSettings();
+  client_settings->slow_connection_message = "slow";
+  client_settings->enable_slow_connection_warnings = true;
+  client_settings->max_consecutive_slow_roundtrips = 2;
+  ActionsResponseProto initial_actions_response;
+  initial_actions_response.add_actions()->mutable_tell()->set_message("1");
+  EXPECT_CALL(mock_service_, OnGetActions(StrEq(kScriptPath), _, _, _, _, _))
+      .WillOnce(DoAll(Delay(&task_environment_, 600),
+                      RunOnceCallback<5>(net::HTTP_OK,
+                                         Serialize(initial_actions_response))));
+
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+      .WillOnce(
+          RunOnceCallback<5>(net::HTTP_OK, Serialize(initial_actions_response)))
+      .WillOnce(DoAll(Delay(&task_environment_, 600),
+                      RunOnceCallback<5>(net::HTTP_OK, "")));
+  EXPECT_CALL(executor_callback_,
+              Run(Field(&ScriptExecutor::Result::success, true)));
+  executor_->Run(&user_data_, executor_callback_.Get());
+
+  EXPECT_NE(delegate_.GetBubbleMessage(), "slow");
+}
+
 TEST_F(ScriptExecutorTest, UnsupportedAction) {
   ActionsResponseProto actions_response;
   actions_response.add_actions();  // action definition missing
@@ -539,6 +621,27 @@
   EXPECT_EQ(ACTION_APPLIED, processed_actions_capture[0].status());
 }
 
+TEST_F(ScriptExecutorTest, WaitForDomSlowWarning) {
+  ClientSettings* client_settings = delegate_.GetMutableSettings();
+  client_settings->slow_website_message = "slow";
+  client_settings->enable_slow_website_warnings = true;
+  ActionsResponseProto actions_response;
+  auto* wait_for_dom = actions_response.add_actions()->mutable_wait_for_dom();
+  *wait_for_dom->mutable_wait_condition()->mutable_match() =
+      ToSelectorProto("element");
+
+  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+      .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
+
+  // First check does not find the element, wait for dom waits 1s, then the
+  // element is found, and the action succeeds.
+  EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"element"}), _))
+      .WillOnce(Delay(&task_environment_, 2000));
+  executor_->Run(&user_data_, executor_callback_.Get());
+
+  EXPECT_EQ(delegate_.GetBubbleMessage(), "slow");
+}
+
 TEST_F(ScriptExecutorTest, RunInterrupt) {
   // All elements exist, so first the interrupt should be run, then the element
   // should be reported as found.
@@ -1636,10 +1739,6 @@
   EXPECT_EQ(AutofillAssistantState::PROMPT, delegate_.GetState());
 }
 
-ACTION_P2(Delay, env, delay) {
-  env->FastForwardBy(base::TimeDelta::FromMilliseconds(delay));
-}
-
 TEST_F(ScriptExecutorTest, RoundtripTimingStats) {
   ActionsResponseProto actions_response;
   ActionProto* action = actions_response.add_actions();
diff --git a/components/autofill_assistant/browser/script_tracker_unittest.cc b/components/autofill_assistant/browser/script_tracker_unittest.cc
index fc358c5..a1918fe 100644
--- a/components/autofill_assistant/browser/script_tracker_unittest.cc
+++ b/components/autofill_assistant/browser/script_tracker_unittest.cc
@@ -8,6 +8,7 @@
 
 #include "base/test/gmock_callback_support.h"
 #include "base/test/mock_callback.h"
+#include "base/test/task_environment.h"
 #include "components/autofill_assistant/browser/fake_script_executor_delegate.h"
 #include "components/autofill_assistant/browser/protocol_utils.h"
 #include "components/autofill_assistant/browser/script_executor_delegate.h"
@@ -126,6 +127,10 @@
     return output;
   }
 
+  // task_environment_ must be first to guarantee other field
+  // creation run in that environment.
+  base::test::TaskEnvironment task_environment_;
+
   GURL url_;
   NiceMock<MockService> mock_service_;
   NiceMock<MockWebController> mock_web_controller_;
diff --git a/components/autofill_assistant/browser/service.proto b/components/autofill_assistant/browser/service.proto
index 0748f4c..3fc8a73 100644
--- a/components/autofill_assistant/browser/service.proto
+++ b/components/autofill_assistant/browser/service.proto
@@ -155,6 +155,7 @@
   optional ClientDimensionProto text_size = 7;
 }
 
+// Next ID: 22
 message ClientSettingsProto {
   message IntegrationTestSettings {
     // Disables animations for the poodle and the progress bar.
@@ -231,6 +232,32 @@
   }
   optional BackButtonSettings back_button_settings = 19;
 
+  // Settings to define the behavior for showing warnings about slow connection
+  // and/or websites to users.
+  message SlowWarningSettings {
+    // Whether to show warnings related to a slow connection to the user.
+    optional bool enable_slow_connection_warnings = 1;
+    // Whether to show warnings related to a slow website to the user.
+    optional bool enable_slow_website_warnings = 2;
+    // If true, the slow connection or website warning will be only shown once.
+    optional bool show_only_once = 3;
+    // Defines the maximum wait on a dom find element operation before showing
+    // the slow website warning.
+    optional int32 warning_delay_ms = 4;
+    // Defines the threshold above which a roundtrip is considered too slow.
+    optional int32 slow_roundtrip_threshold_ms = 5;
+    // Defines the number of consecutive slow roundtrips allowed before showing
+    // the slow connection warning.
+    optional int32 max_consecutive_slow_roundtrips = 6;
+    // The message to show as a warning to inform the user of a slow connection.
+    // If this is not set, no warning will be shown in case of slow connection.
+    optional string slow_connection_message = 7;
+    // The message to show as a warning to inform the user of a slow website.
+    // If this is not set, no warning will be shown in case of a slow website.
+    optional string slow_website_message = 8;
+  }
+  optional SlowWarningSettings slow_warning_settings = 21;
+
   reserved 8 to 11;
 }
 
diff --git a/components/browser_sync/active_devices_provider_impl.cc b/components/browser_sync/active_devices_provider_impl.cc
index ec07f79..94aedba 100644
--- a/components/browser_sync/active_devices_provider_impl.cc
+++ b/components/browser_sync/active_devices_provider_impl.cc
@@ -8,22 +8,12 @@
 
 #include "base/feature_list.h"
 #include "base/metrics/field_trial_params.h"
+#include "base/stl_util.h"
 #include "components/browser_sync/active_devices_provider_impl.h"
+#include "components/browser_sync/browser_sync_switches.h"
 
 namespace browser_sync {
 
-// Enables filtering out inactive devices which haven't sent DeviceInfo update
-// recently (depending on the device's pulse_interval and an additional margin).
-const base::Feature kSyncFilterOutInactiveDevicesForSingleClient{
-    "SyncFilterOutInactiveDevicesForSingleClient",
-    base::FEATURE_ENABLED_BY_DEFAULT};
-
-// An additional threshold to consider devices as active. It extends device's
-// pulse interval to mitigate possible latency after DeviceInfo commit.
-const base::FeatureParam<base::TimeDelta> kSyncActiveDeviceMargin{
-    &kSyncFilterOutInactiveDevicesForSingleClient, "SyncActiveDeviceMargin",
-    base::TimeDelta::FromMinutes(30)};
-
 ActiveDevicesProviderImpl::ActiveDevicesProviderImpl(
     syncer::DeviceInfoTracker* device_info_tracker,
     base::Clock* clock)
@@ -40,25 +30,43 @@
 
 size_t ActiveDevicesProviderImpl::CountActiveDevicesIfAvailable() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  std::vector<std::unique_ptr<syncer::DeviceInfo>> all_devices =
-      device_info_tracker_->GetAllDeviceInfo();
+
+  return GetActiveDevices().size();
+}
+
+std::vector<std::string>
+ActiveDevicesProviderImpl::CollectFCMRegistrationTokensForInvalidations(
+    const std::string& local_cache_guid) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  std::vector<std::string> fcm_registration_tokens;
   if (!base::FeatureList::IsEnabled(
-          kSyncFilterOutInactiveDevicesForSingleClient)) {
-    return all_devices.size();
+          switches::kSyncUseFCMRegistrationTokensList)) {
+    return fcm_registration_tokens;
   }
 
-  size_t active_devices = 0;
-  for (const auto& device : all_devices) {
-    const base::Time expected_expiration_time =
-        device->last_updated_timestamp() + device->pulse_interval() +
-        kSyncActiveDeviceMargin.Get();
-    // If the device's expiration time hasn't been reached, then it is
-    // considered active device.
-    if (expected_expiration_time > clock_->Now()) {
-      active_devices++;
+  for (const std::unique_ptr<syncer::DeviceInfo>& device : GetActiveDevices()) {
+    if (!local_cache_guid.empty() && device->guid() == local_cache_guid) {
+      continue;
     }
+    if (device->fcm_registration_token().empty()) {
+      continue;
+    }
+
+    fcm_registration_tokens.push_back(device->fcm_registration_token());
   }
-  return active_devices;
+
+  // Do not send tokens if the list of active devices is huge. This is similar
+  // to the case when the client doesn't know about other devices, so return an
+  // empty list. Otherwise the client would return only a part of all active
+  // clients and other clients might miss an invalidation.
+  if (fcm_registration_tokens.size() >
+      static_cast<size_t>(
+          switches::kSyncFCMRegistrationTokensListMaxSize.Get())) {
+    return std::vector<std::string>();
+  }
+
+  return fcm_registration_tokens;
 }
 
 void ActiveDevicesProviderImpl::SetActiveDevicesChangedCallback(
@@ -77,4 +85,26 @@
   }
 }
 
+std::vector<std::unique_ptr<syncer::DeviceInfo>>
+ActiveDevicesProviderImpl::GetActiveDevices() const {
+  std::vector<std::unique_ptr<syncer::DeviceInfo>> all_devices =
+      device_info_tracker_->GetAllDeviceInfo();
+  if (!base::FeatureList::IsEnabled(
+          switches::kSyncFilterOutInactiveDevicesForSingleClient)) {
+    return all_devices;
+  }
+
+  base::EraseIf(
+      all_devices, [this](const std::unique_ptr<syncer::DeviceInfo>& device) {
+        const base::Time expected_expiration_time =
+            device->last_updated_timestamp() + device->pulse_interval() +
+            switches::kSyncActiveDeviceMargin.Get();
+        // If the device's expiration time hasn't been reached, then
+        // it is considered active device.
+        return expected_expiration_time <= clock_->Now();
+      });
+
+  return all_devices;
+}
+
 }  // namespace browser_sync
diff --git a/components/browser_sync/active_devices_provider_impl.h b/components/browser_sync/active_devices_provider_impl.h
index d0bbed0..5bca0e5 100644
--- a/components/browser_sync/active_devices_provider_impl.h
+++ b/components/browser_sync/active_devices_provider_impl.h
@@ -5,6 +5,10 @@
 #ifndef COMPONENTS_BROWSER_SYNC_ACTIVE_DEVICES_PROVIDER_IMPL_H_
 #define COMPONENTS_BROWSER_SYNC_ACTIVE_DEVICES_PROVIDER_IMPL_H_
 
+#include <memory>
+#include <string>
+#include <vector>
+
 #include "base/sequence_checker.h"
 #include "base/time/default_clock.h"
 #include "components/sync/driver/active_devices_provider.h"
@@ -26,6 +30,9 @@
   // syncer::ActiveDevicesProvider implementation.
   size_t CountActiveDevicesIfAvailable() override;
 
+  std::vector<std::string> CollectFCMRegistrationTokensForInvalidations(
+      const std::string& local_cache_guid) override;
+
   void SetActiveDevicesChangedCallback(
       ActiveDevicesChangedCallback callback) override;
 
@@ -33,6 +40,8 @@
   void OnDeviceInfoChange() override;
 
  private:
+  std::vector<std::unique_ptr<syncer::DeviceInfo>> GetActiveDevices() const;
+
   syncer::DeviceInfoTracker* const device_info_tracker_;
   const base::Clock* const clock_;
   ActiveDevicesChangedCallback callback_;
diff --git a/components/browser_sync/active_devices_provider_impl_unittest.cc b/components/browser_sync/active_devices_provider_impl_unittest.cc
index f9dbaa1..5ab9233c 100644
--- a/components/browser_sync/active_devices_provider_impl_unittest.cc
+++ b/components/browser_sync/active_devices_provider_impl_unittest.cc
@@ -9,15 +9,19 @@
 #include <vector>
 
 #include "base/guid.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/test/mock_callback.h"
 #include "base/test/simple_test_clock.h"
 #include "base/time/time.h"
+#include "components/browser_sync/browser_sync_switches.h"
 #include "components/sync_device_info/device_info_util.h"
 #include "components/sync_device_info/fake_device_info_tracker.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using syncer::DeviceInfo;
 using syncer::FakeDeviceInfoTracker;
+using testing::IsEmpty;
+using testing::UnorderedElementsAre;
 
 namespace browser_sync {
 namespace {
@@ -26,15 +30,15 @@
 
 std::unique_ptr<DeviceInfo> CreateFakeDeviceInfo(
     const std::string& name,
+    const std::string& fcm_registration_token,
     base::Time last_updated_timestamp) {
   return std::make_unique<syncer::DeviceInfo>(
-      base::GenerateGUID(), name, "chrome_version", "user_agent",
-      sync_pb::SyncEnums::TYPE_UNSET, "device_id", "manufacturer_name",
-      "model_name", last_updated_timestamp,
+      base::GUID::GenerateRandomV4().AsLowercaseString(), name,
+      "chrome_version", "user_agent", sync_pb::SyncEnums::TYPE_UNSET,
+      "device_id", "manufacturer_name", "model_name", last_updated_timestamp,
       base::TimeDelta::FromMinutes(kPulseIntervalMinutes),
       /*send_tab_to_self_receiving_enabled=*/false,
-      /*sharing_info=*/base::nullopt,
-      /*fcm_registration_token=*/std::string(),
+      /*sharing_info=*/base::nullopt, fcm_registration_token,
       /*interested_data_types=*/syncer::ModelTypeSet());
 }
 
@@ -45,8 +49,11 @@
 
   ~ActiveDevicesProviderImplTest() override = default;
 
-  void AddDevice(const std::string& name, base::Time last_updated_timestamp) {
-    device_list_.push_back(CreateFakeDeviceInfo(name, last_updated_timestamp));
+  void AddDevice(const std::string& name,
+                 const std::string& fcm_registration_token,
+                 base::Time last_updated_timestamp) {
+    device_list_.push_back(CreateFakeDeviceInfo(name, fcm_registration_token,
+                                                last_updated_timestamp));
     fake_device_info_tracker_.Add(device_list_.back().get());
   }
 
@@ -58,16 +65,19 @@
 };
 
 TEST_F(ActiveDevicesProviderImplTest, ShouldFilterInactiveDevices) {
-  AddDevice("device_recent", clock_.Now() - base::TimeDelta::FromMinutes(1));
+  AddDevice("device_recent", /*fcm_registration_token=*/"",
+            clock_.Now() - base::TimeDelta::FromMinutes(1));
 
   // Should be considered as active device due to margin even though the device
   // is outside the pulse interval.
   AddDevice(
       "device_pulse_interval",
+      /*fcm_registration_token=*/"",
       clock_.Now() - base::TimeDelta::FromMinutes(kPulseIntervalMinutes + 1));
 
   // Very old device.
-  AddDevice("device_inactive", clock_.Now() - base::TimeDelta::FromDays(100));
+  AddDevice("device_inactive", /*fcm_registration_token=*/"",
+            clock_.Now() - base::TimeDelta::FromDays(100));
 
   EXPECT_EQ(2u, active_devices_provider_.CountActiveDevicesIfAvailable());
 }
@@ -87,5 +97,44 @@
       base::RepeatingClosure());
 }
 
+TEST_F(ActiveDevicesProviderImplTest, ShouldReturnActiveFCMRegistrationTokens) {
+  AddDevice("device_1", "fcm_token_1",
+            clock_.Now() - base::TimeDelta::FromMinutes(1));
+  AddDevice("device_2", "fcm_token_2",
+            clock_.Now() - base::TimeDelta::FromMinutes(1));
+  AddDevice("device_inactive", "fcm_token_3",
+            clock_.Now() - base::TimeDelta::FromDays(100));
+
+  ASSERT_EQ(3u, device_list_.size());
+
+  EXPECT_THAT(
+      active_devices_provider_.CollectFCMRegistrationTokensForInvalidations(
+          "other_guid"),
+      UnorderedElementsAre(device_list_[0]->fcm_registration_token(),
+                           device_list_[1]->fcm_registration_token()));
+  EXPECT_THAT(
+      active_devices_provider_.CollectFCMRegistrationTokensForInvalidations(
+          device_list_[0]->guid()),
+      UnorderedElementsAre(device_list_[1]->fcm_registration_token()));
+}
+
+TEST_F(ActiveDevicesProviderImplTest, ShouldReturnEmptyListWhenTooManyDevices) {
+  // Create many devices to exceed the limit of the list.
+  const size_t kActiveDevicesNumber =
+      switches::kSyncFCMRegistrationTokensListMaxSize.Get() + 1;
+
+  for (size_t i = 0; i < kActiveDevicesNumber; ++i) {
+    const std::string device_name = "device_" + base::NumberToString(i);
+    const std::string fcm_token = "fcm_token_" + device_name;
+    AddDevice(device_name, fcm_token,
+              clock_.Now() - base::TimeDelta::FromMinutes(1));
+  }
+
+  EXPECT_THAT(
+      active_devices_provider_.CollectFCMRegistrationTokensForInvalidations(
+          "guid"),
+      IsEmpty());
+}
+
 }  // namespace
 }  // namespace browser_sync
diff --git a/components/browser_sync/browser_sync_switches.cc b/components/browser_sync/browser_sync_switches.cc
index e327d97..4ba5ded 100644
--- a/components/browser_sync/browser_sync_switches.cc
+++ b/components/browser_sync/browser_sync_switches.cc
@@ -26,4 +26,27 @@
     "SyncUseSessionsUnregisterDelay", base::FEATURE_DISABLED_BY_DEFAULT};
 #endif  // defined(OS_ANDROID)
 
+// Enables filtering out inactive devices which haven't sent DeviceInfo update
+// recently (depending on the device's pulse_interval and an additional margin).
+const base::Feature kSyncFilterOutInactiveDevicesForSingleClient{
+    "SyncFilterOutInactiveDevicesForSingleClient",
+    base::FEATURE_ENABLED_BY_DEFAULT};
+
+// An additional threshold to consider devices as active. It extends device's
+// pulse interval to mitigate possible latency after DeviceInfo commit.
+const base::FeatureParam<base::TimeDelta> kSyncActiveDeviceMargin{
+    &kSyncFilterOutInactiveDevicesForSingleClient, "SyncActiveDeviceMargin",
+    base::TimeDelta::FromMinutes(30)};
+
+// Enables providing the list of FCM registration tokens in the commit request.
+const base::Feature kSyncUseFCMRegistrationTokensList{
+    "SyncUseFCMRegistrationTokensList", base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Max size of FCM registration tokens list. If the number of active devices
+// having FCM registration tokens is higher, then the resulting list will be
+// empty meaning unknown FCM registration tokens.
+const base::FeatureParam<int> kSyncFCMRegistrationTokensListMaxSize{
+    &kSyncUseFCMRegistrationTokensList, "SyncFCMRegistrationTokensListMaxSize",
+    5};
+
 }  // namespace switches
diff --git a/components/browser_sync/browser_sync_switches.h b/components/browser_sync/browser_sync_switches.h
index 21e7612..32345cd 100644
--- a/components/browser_sync/browser_sync_switches.h
+++ b/components/browser_sync/browser_sync_switches.h
@@ -18,6 +18,11 @@
 extern const base::Feature kSyncUseSessionsUnregisterDelay;
 #endif
 
+extern const base::Feature kSyncFilterOutInactiveDevicesForSingleClient;
+extern const base::FeatureParam<base::TimeDelta> kSyncActiveDeviceMargin;
+extern const base::Feature kSyncUseFCMRegistrationTokensList;
+extern const base::FeatureParam<int> kSyncFCMRegistrationTokensListMaxSize;
+
 }  // namespace switches
 
 #endif  // COMPONENTS_BROWSER_SYNC_BROWSER_SYNC_SWITCHES_H_
diff --git a/components/browser_ui/photo_picker/android/BUILD.gn b/components/browser_ui/photo_picker/android/BUILD.gn
index ed902f8..c402ff6 100644
--- a/components/browser_ui/photo_picker/android/BUILD.gn
+++ b/components/browser_ui/photo_picker/android/BUILD.gn
@@ -5,7 +5,11 @@
 import("//build/config/android/rules.gni")
 
 source_set("android") {
-  sources = [ "photo_picker_sandbox_bridge.cc" ]
+  sources = [
+    "features.cc",
+    "features.h",
+    "photo_picker_sandbox_bridge.cc",
+  ]
   deps = [
     ":photo_picker_jni_headers",
     "//base",
diff --git a/components/browser_ui/photo_picker/android/features.cc b/components/browser_ui/photo_picker/android/features.cc
new file mode 100644
index 0000000..a517698
--- /dev/null
+++ b/components/browser_ui/photo_picker/android/features.cc
@@ -0,0 +1,14 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/browser_ui/photo_picker/android/features.h"
+
+namespace photo_picker {
+namespace features {
+
+const base::Feature kPhotoPickerVideoSupport{"PhotoPickerVideoSupport",
+                                             base::FEATURE_DISABLED_BY_DEFAULT};
+
+}  // namespace features
+}  // namespace photo_picker
diff --git a/components/browser_ui/photo_picker/android/features.h b/components/browser_ui/photo_picker/android/features.h
new file mode 100644
index 0000000..1834686
--- /dev/null
+++ b/components/browser_ui/photo_picker/android/features.h
@@ -0,0 +1,18 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_BROWSER_UI_PHOTO_PICKER_ANDROID_FEATURES_H_
+#define COMPONENTS_BROWSER_UI_PHOTO_PICKER_ANDROID_FEATURES_H_
+
+#include "base/feature_list.h"
+
+namespace photo_picker {
+namespace features {
+
+extern const base::Feature kPhotoPickerVideoSupport;
+
+}  // namespace features
+}  // namespace photo_picker
+
+#endif  // COMPONENTS_BROWSER_UI_PHOTO_PICKER_ANDROID_FEATURES_H_
diff --git a/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/DecoderServiceHost.java b/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/DecoderServiceHost.java
index cacc7ff..ca09cee 100644
--- a/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/DecoderServiceHost.java
+++ b/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/DecoderServiceHost.java
@@ -49,6 +49,9 @@
     // A tag for logging error messages.
     private static final String TAG = "ImageDecoderHost";
 
+    // The current context.
+    private final Context mContext;
+
     // A content resolver for providing file descriptors for the images.
     private ContentResolver mContentResolver;
 
@@ -76,9 +79,18 @@
     // The number of io failures during video decoding, per batch.
     private int mFailedVideoDecodesUnknown;
 
+    // Whether animated thumbnails should be generated for video clips.
+    private final boolean mAnimatedThumbnailsSupported;
+
     // A worker task for asynchronously handling video decode requests.
     private DecodeVideoTask mWorkerTask;
 
+    // The current processing request.
+    private DecoderServiceParams mProcessingRequest;
+
+    // The callbacks used to notify the clients when the service is ready.
+    private final List<DecoderStatusCallback> mCallbacks = new ArrayList<DecoderStatusCallback>();
+
     // Keeps track of the last decoding ordinal issued.
     static int sLastDecodingOrdinal = 0;
 
@@ -215,20 +227,17 @@
     PriorityQueue<DecoderServiceParams> mPendingRequests =
             new PriorityQueue<>(/*initialCapacity=*/1, mRequestComparator);
 
-    // The current processing request.
-    private DecoderServiceParams mProcessingRequest;
-
-    // The callbacks used to notify the clients when the service is ready.
-    private final List<DecoderStatusCallback> mCallbacks = new ArrayList<DecoderStatusCallback>();
-
-    private final Context mContext;
-
     /**
      * The DecoderServiceHost constructor.
      * @param callback The callback to use when communicating back to the client.
+     * @param context The current context.
+     * @param animatedThumbnailsSupported Whether animated thumbnails should be generated for video
+     *         clips.
      */
-    public DecoderServiceHost(DecoderStatusCallback callback, Context context) {
+    public DecoderServiceHost(
+            DecoderStatusCallback callback, Context context, boolean animatedThumbnailsSupported) {
         mCallbacks.add(callback);
+        mAnimatedThumbnailsSupported = animatedThumbnailsSupported;
         if (sStatusCallbackForTesting != null) {
             mCallbacks.add(sStatusCallbackForTesting);
         }
@@ -273,7 +282,7 @@
         DecoderServiceParams params = new DecoderServiceParams(
                 uri, width, fullWidth, fileType, /*firstFrame=*/true, callback);
         mPendingRequests.add(params);
-        if (params.mFileType == PickerBitmap.TileTypes.VIDEO) {
+        if (params.mFileType == PickerBitmap.TileTypes.VIDEO && mAnimatedThumbnailsSupported) {
             // Decoding requests for videos are requests for first frames only. Add another
             // low-priority request for decoding the rest of the frames.
             DecoderServiceParams lowPriorityRequest =
diff --git a/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/DecoderServiceHostTest.java b/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/DecoderServiceHostTest.java
index d2380a0..92d3688 100644
--- a/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/DecoderServiceHostTest.java
+++ b/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/DecoderServiceHostTest.java
@@ -47,6 +47,9 @@
     // A callback that fires when the decoder is ready.
     public final CallbackHelper mOnDecoderReadyCallback = new CallbackHelper();
 
+    // A callback that fires when the decoder is idle.
+    public final CallbackHelper mOnDecoderIdleCallback = new CallbackHelper();
+
     // A callback that fires when something is finished decoding in the dialog.
     public final CallbackHelper mOnDecodedCallback = new CallbackHelper();
 
@@ -77,7 +80,9 @@
     }
 
     @Override
-    public void decoderIdle() {}
+    public void decoderIdle() {
+        mOnDecoderIdleCallback.notifyCalled();
+    }
 
     // DecoderServiceHost.ImagesDecodedCallback:
 
@@ -100,6 +105,11 @@
                 callCount, 1, WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
     }
 
+    private void waitForDecoderIdle(int lastCount) throws Exception {
+        mOnDecoderIdleCallback.waitForCallback(
+                lastCount, 1, WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+    }
+
     private void waitForThumbnailDecode() throws Exception {
         int callCount = mOnDecodedCallback.getCallCount();
         mOnDecodedCallback.waitForCallback(callCount, 1, WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
@@ -133,7 +143,8 @@
         lowerPri = new DecoderServiceHost.DecoderServiceParams(uri, width, fullWidth,
                 PickerBitmap.TileTypes.VIDEO,
                 /* firstFrame= */ true, callback);
-        DecoderServiceHost host = new DecoderServiceHost(this, mContext);
+        DecoderServiceHost host =
+                new DecoderServiceHost(this, mContext, /* animatedThumbnailsSupported = */ true);
         Assert.assertTrue("Still images have priority over requests for initial video frame",
                 host.mRequestComparator.compare(higherPri, lowerPri) < 0);
 
@@ -191,7 +202,8 @@
     @Test
     @LargeTest
     public void testDecodingOrder() throws Throwable {
-        DecoderServiceHost host = new DecoderServiceHost(this, mContext);
+        DecoderServiceHost host =
+                new DecoderServiceHost(this, mContext, /* animatedThumbnailsSupported = */ true);
         host.bind(mContext);
         waitForDecoder();
 
@@ -254,8 +266,70 @@
 
     @Test
     @LargeTest
+    public void testDecodingOrderNoAnimationSupported() throws Throwable {
+        DecoderServiceHost host =
+                new DecoderServiceHost(this, mContext, /* animatedThumbnailsSupported = */ false);
+        host.bind(mContext);
+        waitForDecoder();
+
+        String video1 = "noogler.mp4";
+        String video2 = "noogler2.mp4";
+        String jpg1 = "blue100x100.jpg";
+        File file1 = new File(UrlUtils.getIsolatedTestFilePath(TEST_FILE_PATH + video1));
+        File file2 = new File(UrlUtils.getIsolatedTestFilePath(TEST_FILE_PATH + video2));
+        File file3 = new File(UrlUtils.getIsolatedTestFilePath(TEST_FILE_PATH + jpg1));
+
+        decodeImage(host, Uri.fromFile(file1), PickerBitmap.TileTypes.VIDEO, 10,
+                /*fullWidth=*/false, this);
+        decodeImage(host, Uri.fromFile(file2), PickerBitmap.TileTypes.VIDEO, 10,
+                /*fullWidth=*/false, this);
+        decodeImage(host, Uri.fromFile(file3), PickerBitmap.TileTypes.PICTURE, 10,
+                /*fullWidth=*/false, this);
+
+        int idleCallCount = mOnDecoderIdleCallback.getCallCount();
+
+        // First decoding result should be first frame of video 1. Even though still images take
+        // priority over video decoding, video 1 will be the only item in the queue when the first
+        // decoding request is kicked off (as a result of calling decodeImage).
+        waitForThumbnailDecode();
+        Assert.assertTrue(mLastDecodedPath.contains(video1));
+        Assert.assertEquals(true, mLastIsVideo);
+        Assert.assertEquals("0:00", mLastVideoDuration);
+        Assert.assertEquals(1, mLastFrameCount);
+
+        // When the decoder is finished with the first frame of video 1, there will be two new
+        // requests available for processing. Video2 was added first, but that will be skipped in
+        // favor of the still image, so the jpg is expected to be decoded next.
+        waitForThumbnailDecode();
+        Assert.assertTrue(mLastDecodedPath.contains(jpg1));
+        Assert.assertEquals(false, mLastIsVideo);
+        Assert.assertEquals(null, mLastVideoDuration);
+        Assert.assertEquals(1, mLastFrameCount);
+
+        // Third and last decoding result is first frame of video 2.
+        waitForThumbnailDecode();
+        Assert.assertTrue(mLastDecodedPath.contains(video2));
+        Assert.assertEquals(true, mLastIsVideo);
+        Assert.assertEquals("0:00", mLastVideoDuration);
+        Assert.assertEquals(1, mLastFrameCount);
+
+        // Make sure nothing else is returned (no animations should be supported).
+        waitForDecoderIdle(idleCallCount);
+
+        // Everything should be as we left it.
+        Assert.assertTrue(mLastDecodedPath.contains(video2));
+        Assert.assertEquals(true, mLastIsVideo);
+        Assert.assertEquals("0:00", mLastVideoDuration);
+        Assert.assertEquals(1, mLastFrameCount);
+
+        host.unbind(mContext);
+    }
+
+    @Test
+    @LargeTest
     public void testDecodingSizes() throws Throwable {
-        DecoderServiceHost host = new DecoderServiceHost(this, mContext);
+        DecoderServiceHost host =
+                new DecoderServiceHost(this, mContext, /* animatedThumbnailsSupported = */ true);
         host.bind(mContext);
         waitForDecoder();
 
@@ -334,7 +408,8 @@
     @Test
     @LargeTest
     public void testCancelation() throws Throwable {
-        DecoderServiceHost host = new DecoderServiceHost(this, mContext);
+        DecoderServiceHost host =
+                new DecoderServiceHost(this, mContext, /* animatedThumbnailsSupported = */ true);
         host.bind(mContext);
         waitForDecoder();
 
@@ -370,7 +445,8 @@
     @Test
     @LargeTest
     public void testNoConnectionFailureMode() throws Throwable {
-        DecoderServiceHost host = new DecoderServiceHost(this, mContext);
+        DecoderServiceHost host =
+                new DecoderServiceHost(this, mContext, /* animatedThumbnailsSupported = */ true);
 
         // Try decoding without a connection to the decoder.
         String green = "green100x100.jpg";
@@ -384,7 +460,8 @@
     @Test
     @LargeTest
     public void testFileNotFoundFailureMode() throws Throwable {
-        DecoderServiceHost host = new DecoderServiceHost(this, mContext);
+        DecoderServiceHost host =
+                new DecoderServiceHost(this, mContext, /* animatedThumbnailsSupported = */ true);
         host.bind(mContext);
         waitForDecoder();
 
diff --git a/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/PhotoPickerDialog.java b/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/PhotoPickerDialog.java
index 544c6ff..7854543 100644
--- a/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/PhotoPickerDialog.java
+++ b/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/PhotoPickerDialog.java
@@ -84,18 +84,21 @@
      * @param listener The listener object that gets notified when an action is taken.
      * @param multiSelectionAllowed Whether the photo picker should allow multiple items to be
      *                              selected.
+     * @param animatedThumbnailsSupported Whether animated thumbnails should be generated for video
+     *         clips.
      * @param mimeTypes A list of mime types to show in the dialog.
      */
     public PhotoPickerDialog(WindowAndroid windowAndroid, ContentResolver contentResolver,
-            PhotoPickerListener listener, boolean multiSelectionAllowed, List<String> mimeTypes) {
+            PhotoPickerListener listener, boolean multiSelectionAllowed,
+            boolean animatedThumbnailsSupported, List<String> mimeTypes) {
         super(windowAndroid.getContext().get(), R.style.Theme_Chromium_Fullscreen);
 
         mWindowAndroid = windowAndroid;
         mListenerWrapper = new PhotoPickerListenerWrapper(listener);
 
         // Initialize the main content view.
-        mCategoryView =
-                new PickerCategoryView(windowAndroid, contentResolver, multiSelectionAllowed, this);
+        mCategoryView = new PickerCategoryView(windowAndroid, contentResolver,
+                multiSelectionAllowed, animatedThumbnailsSupported, this);
         mCategoryView.initialize(this, mListenerWrapper, mimeTypes);
         setView(mCategoryView);
     }
diff --git a/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/PhotoPickerDialogTest.java b/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/PhotoPickerDialogTest.java
index 3fdb2c58..c69215b 100644
--- a/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/PhotoPickerDialogTest.java
+++ b/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/PhotoPickerDialogTest.java
@@ -272,9 +272,9 @@
                 TestThreadUtils.runOnUiThreadBlocking(new Callable<PhotoPickerDialog>() {
                     @Override
                     public PhotoPickerDialog call() {
-                        final PhotoPickerDialog dialog =
-                                new PhotoPickerDialog(mWindowAndroid, contentResolver,
-                                        PhotoPickerDialogTest.this, multiselect, mimeTypes);
+                        final PhotoPickerDialog dialog = new PhotoPickerDialog(mWindowAndroid,
+                                contentResolver, PhotoPickerDialogTest.this, multiselect,
+                                /* animatedThumbnailsSupported = */ true, mimeTypes);
                         dialog.show();
                         return dialog;
                     }
diff --git a/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/PickerCategoryView.java b/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/PickerCategoryView.java
index 9b0074f..8afb200 100644
--- a/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/PickerCategoryView.java
+++ b/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/PickerCategoryView.java
@@ -192,17 +192,20 @@
      *         selection.
      * @param contentResolver The ContentResolver to use to retrieve image metadata from disk.
      * @param multiSelectionAllowed Whether to allow the user to select more than one image.
+     * @param animatedThumbnailsSupported Whether animated thumbnails should be generated for video
+     *         clips.
      */
     @SuppressWarnings("unchecked") // mSelectableListLayout
     public PickerCategoryView(WindowAndroid windowAndroid, ContentResolver contentResolver,
-            boolean multiSelectionAllowed, PhotoPickerToolbar.PhotoPickerToolbarDelegate delegate) {
+            boolean multiSelectionAllowed, boolean animatedThumbnailsSupported,
+            PhotoPickerToolbar.PhotoPickerToolbarDelegate delegate) {
         super(windowAndroid.getContext().get());
         mWindowAndroid = windowAndroid;
         Context context = mWindowAndroid.getContext().get();
         mContentResolver = contentResolver;
         mMultiSelectionAllowed = multiSelectionAllowed;
 
-        mDecoderServiceHost = new DecoderServiceHost(this, context);
+        mDecoderServiceHost = new DecoderServiceHost(this, context, animatedThumbnailsSupported);
         mDecoderServiceHost.bind(context);
 
         mSelectionDelegate = new SelectionDelegate<PickerBitmap>();
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleCategorySettings.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleCategorySettings.java
index 517861e..68ba45b1 100644
--- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleCategorySettings.java
+++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleCategorySettings.java
@@ -490,6 +490,13 @@
                 return;
         }
 
+        getSiteSettingsDelegate().dismissPrivacySandboxSnackbar();
+
+        // Display the Privacy Sandbox snackbar whenever third-party/all cookies are blocked.
+        if (mode == CookieControlsMode.BLOCK_THIRD_PARTY) {
+            getSiteSettingsDelegate().maybeDisplayPrivacySandboxSnackbar();
+        }
+
         WebsitePreferenceBridge.setCategoryEnabled(
                 getSiteSettingsDelegate().getBrowserContextHandle(), ContentSettingsType.COOKIES,
                 allowCookies);
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsDelegate.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsDelegate.java
index 931f996..d3ee6e05 100644
--- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsDelegate.java
+++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsDelegate.java
@@ -112,4 +112,15 @@
      * @return The set of all origins whose notification permissions are delegated to another app.
      */
     Set<String> getAllDelegatedNotificationOrigins();
+
+    /**
+     * Displays a snackbar, informing the user about the Privacy Sandbox settings page, when the
+     * corresponding flag is enabled.
+     */
+    void maybeDisplayPrivacySandboxSnackbar();
+
+    /**
+     * Dismisses the Privacy Sandbox snackbar, if active.
+     */
+    void dismissPrivacySandboxSnackbar();
 }
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsPreferenceFragment.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsPreferenceFragment.java
index 9643ece..0d816be 100644
--- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsPreferenceFragment.java
+++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsPreferenceFragment.java
@@ -25,7 +25,7 @@
     /**
      * @return the SiteSettingsDelegate instance to use when rendering the Site Settings UI.
      */
-    protected SiteSettingsDelegate getSiteSettingsDelegate() {
+    public SiteSettingsDelegate getSiteSettingsDelegate() {
         assert mSiteSettingsDelegate != null : "SiteSettingsDelegate not set";
         return mSiteSettingsDelegate;
     }
diff --git a/components/feed/core/v2/feed_network_impl_unittest.cc b/components/feed/core/v2/feed_network_impl_unittest.cc
index dfafe06..3f8c6a0 100644
--- a/components/feed/core/v2/feed_network_impl_unittest.cc
+++ b/components/feed/core/v2/feed_network_impl_unittest.cc
@@ -476,7 +476,9 @@
   auto* elements = resource_request.request_body->elements();
   ASSERT_TRUE(elements);
   ASSERT_EQ(1UL, elements->size());
-  std::string sent_body((*elements)[0].bytes(), (*elements)[0].length());
+  ASSERT_EQ(network::DataElement::Tag::kBytes, elements->at(0).type());
+  std::string sent_body(
+      elements->at(0).As<network::DataElementBytes>().AsStringPiece());
   std::string sent_body_uncompressed;
   ASSERT_TRUE(compression::GzipUncompress(sent_body, &sent_body_uncompressed));
   std::string expected_body;
diff --git a/components/optimization_guide/core/hints_fetcher_unittest.cc b/components/optimization_guide/core/hints_fetcher_unittest.cc
index a6882bc..bf009ad64 100644
--- a/components/optimization_guide/core/hints_fetcher_unittest.cc
+++ b/components/optimization_guide/core/hints_fetcher_unittest.cc
@@ -139,7 +139,12 @@
       EXPECT_EQ(pending_request.request.request_body->elements()->size(), 1u);
       auto& element =
           pending_request.request.request_body->elements_mutable()->front();
-      last_request_body_ = std::string(element.bytes(), element.length());
+      if (element.type() != network::DataElement::Tag::kBytes) {
+        ADD_FAILURE() << "network::DataElement type mismatch";
+        return;
+      }
+      last_request_body_ =
+          std::string(element.As<network::DataElementBytes>().AsStringPiece());
     }
   }
 
diff --git a/components/password_manager/core/browser/password_store_signin_notifier_impl.cc b/components/password_manager/core/browser/password_store_signin_notifier_impl.cc
index b22f058..8777fb1 100644
--- a/components/password_manager/core/browser/password_store_signin_notifier_impl.cc
+++ b/components/password_manager/core/browser/password_store_signin_notifier_impl.cc
@@ -48,9 +48,13 @@
 }
 
 // IdentityManager::Observer implementation.
-void PasswordStoreSigninNotifierImpl::OnPrimaryAccountCleared(
-    const CoreAccountInfo& account_info) {
-  NotifySignedOut(account_info.email, /* primary_account= */ true);
+void PasswordStoreSigninNotifierImpl::OnPrimaryAccountChanged(
+    const signin::PrimaryAccountChangeEvent& event) {
+  if (event.GetEventTypeFor(signin::ConsentLevel::kSync) ==
+      signin::PrimaryAccountChangeEvent::Type::kCleared) {
+    NotifySignedOut(event.GetPreviousState().primary_account.email,
+                    /* primary_account= */ true);
+  }
 }
 
 // IdentityManager::Observer implementation.
diff --git a/components/password_manager/core/browser/password_store_signin_notifier_impl.h b/components/password_manager/core/browser/password_store_signin_notifier_impl.h
index 172fa3d..32e9ad2 100644
--- a/components/password_manager/core/browser/password_store_signin_notifier_impl.h
+++ b/components/password_manager/core/browser/password_store_signin_notifier_impl.h
@@ -32,7 +32,8 @@
   void UnsubscribeFromSigninEvents() override;
 
   // IdentityManager::Observer implementations.
-  void OnPrimaryAccountCleared(const CoreAccountInfo& account_info) override;
+  void OnPrimaryAccountChanged(
+      const signin::PrimaryAccountChangeEvent& event) override;
   void OnExtendedAccountInfoRemoved(const AccountInfo& info) override;
 
  private:
diff --git a/components/password_manager/core/browser/sync/password_model_type_controller.cc b/components/password_manager/core/browser/sync/password_model_type_controller.cc
index a8e00c03..cf3ff87 100644
--- a/components/password_manager/core/browser/sync/password_model_type_controller.cc
+++ b/components/password_manager/core/browser/sync/password_model_type_controller.cc
@@ -183,15 +183,18 @@
   features_util::ClearAccountStorageSettingsForAllUsers(pref_service_);
 }
 
-void PasswordModelTypeController::OnPrimaryAccountCleared(
-    const CoreAccountInfo& previous_primary_account_info) {
-  // Note: OnPrimaryAccountCleared() basically means that the consent for
-  // Sync-the-feature was revoked. In this case, also clear any possible
-  // matching opt-in for the account-scoped storage, since it'd probably be
-  // surprising to the user if their account passwords still remained after
-  // disabling Sync.
-  features_util::OptOutOfAccountStorageAndClearSettingsForAccount(
-      pref_service_, previous_primary_account_info.gaia);
+void PasswordModelTypeController::OnPrimaryAccountChanged(
+    const signin::PrimaryAccountChangeEvent& event) {
+  if (event.GetEventTypeFor(signin::ConsentLevel::kSync) ==
+      signin::PrimaryAccountChangeEvent::Type::kCleared) {
+    // Note: kCleared event for ConsentLevel::kSync basically means that the
+    // consent for Sync-the-feature was revoked. In this case, also clear any
+    // possible matching opt-in for the account-scoped storage, since it'd
+    // probably be surprising to the user if their account passwords still
+    // remained after disabling Sync.
+    features_util::OptOutOfAccountStorageAndClearSettingsForAccount(
+        pref_service_, event.GetPreviousState().primary_account.gaia);
+  }
 }
 
 void PasswordModelTypeController::OnOptInStateMaybeChanged() {
diff --git a/components/password_manager/core/browser/sync/password_model_type_controller.h b/components/password_manager/core/browser/sync/password_model_type_controller.h
index bc5362b..4ed2ce8 100644
--- a/components/password_manager/core/browser/sync/password_model_type_controller.h
+++ b/components/password_manager/core/browser/sync/password_model_type_controller.h
@@ -59,8 +59,8 @@
       const signin::AccountsInCookieJarInfo& accounts_in_cookie_jar_info,
       const GoogleServiceAuthError& error) override;
   void OnAccountsCookieDeletedByUserAction() override;
-  void OnPrimaryAccountCleared(
-      const CoreAccountInfo& previous_primary_account_info) override;
+  void OnPrimaryAccountChanged(
+      const signin::PrimaryAccountChangeEvent& event) override;
 
  private:
   void OnOptInStateMaybeChanged();
diff --git a/components/payments/content/autofill_payment_app.cc b/components/payments/content/autofill_payment_app.cc
index d4c6f50..2274cc1 100644
--- a/components/payments/content/autofill_payment_app.cc
+++ b/components/payments/content/autofill_payment_app.cc
@@ -119,7 +119,7 @@
 void AutofillPaymentApp::RecordUse() {
   // Record the use of the credit card.
   payment_request_delegate_->GetPersonalDataManager()->RecordUseOf(
-      credit_card_);
+      &credit_card_);
 }
 
 bool AutofillPaymentApp::NeedsInstallation() const {
diff --git a/components/payments/content/payment_request_state.cc b/components/payments/content/payment_request_state.cc
index 392609c..842c530 100644
--- a/components/payments/content/payment_request_state.cc
+++ b/components/payments/content/payment_request_state.cc
@@ -405,7 +405,7 @@
 void PaymentRequestState::RecordUseStats() {
   if (ShouldShowShippingSection()) {
     DCHECK(selected_shipping_profile_);
-    personal_data_manager_->RecordUseOf(*selected_shipping_profile_);
+    personal_data_manager_->RecordUseOf(selected_shipping_profile_);
   }
 
   if (ShouldShowContactSection()) {
@@ -415,7 +415,7 @@
     // should only be updated once.
     if (!ShouldShowShippingSection() || (selected_shipping_profile_->guid() !=
                                          selected_contact_profile_->guid())) {
-      personal_data_manager_->RecordUseOf(*selected_contact_profile_);
+      personal_data_manager_->RecordUseOf(selected_contact_profile_);
     }
   }
 
diff --git a/components/safe_search_api/DIR_METADATA b/components/safe_search_api/DIR_METADATA
index 9db75de..df2cd975 100644
--- a/components/safe_search_api/DIR_METADATA
+++ b/components/safe_search_api/DIR_METADATA
@@ -1,3 +1,3 @@
 monorail {
-  component: "FamilyLink"
+  component: "FamilyExperiences"
 }
diff --git a/components/services/storage/public/mojom/BUILD.gn b/components/services/storage/public/mojom/BUILD.gn
index 305f12c..7cb4ffc 100644
--- a/components/services/storage/public/mojom/BUILD.gn
+++ b/components/services/storage/public/mojom/BUILD.gn
@@ -7,6 +7,7 @@
 mojom("mojom") {
   sources = [
     "blob_storage_context.mojom",
+    "cache_storage_control.mojom",
     "file_system_access_context.mojom",
     "indexed_db_control.mojom",
     "indexed_db_control_test.mojom",
diff --git a/components/services/storage/public/mojom/cache_storage_control.mojom b/components/services/storage/public/mojom/cache_storage_control.mojom
new file mode 100644
index 0000000..3bec5b0
--- /dev/null
+++ b/components/services/storage/public/mojom/cache_storage_control.mojom
@@ -0,0 +1,35 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module storage.mojom;
+
+import "services/network/public/mojom/cross_origin_embedder_policy.mojom";
+import "third_party/blink/public/mojom/cache_storage/cache_storage.mojom";
+import "url/mojom/origin.mojom";
+
+enum CacheStorageOwner {
+  // Caches that can be accessed by the JS CacheStorage API (developer facing).
+  kCacheAPI,
+
+  // Private cache to store background fetch downloads.
+  kBackgroundFetch,
+};
+
+// Controls the state of CacheStorage within a partition. This is a privileged
+// interface and must not be brokered to untrusted clients.
+//
+// Currently this is consumed and implemented in the browser process, but the
+// implementation will eventually live in the storage service which may run
+// out-of-process.
+interface CacheStorageControl {
+  // Binds a CacheStorage receiver to the CacheStorageControl to access
+  // the cache storage for a particular origin and owner.
+  AddReceiver(
+      network.mojom.CrossOriginEmbedderPolicy policy,
+      pending_remote<network.mojom.CrossOriginEmbedderPolicyReporter>?
+          coep_reporter,
+      url.mojom.Origin origin,
+      CacheStorageOwner owner,
+      pending_receiver<blink.mojom.CacheStorage> receiver);
+};
diff --git a/components/signin/core/browser/chrome_connected_header_helper.cc b/components/signin/core/browser/chrome_connected_header_helper.cc
index 6ea1976..4dde387 100644
--- a/components/signin/core/browser/chrome_connected_header_helper.cc
+++ b/components/signin/core/browser/chrome_connected_header_helper.cc
@@ -58,6 +58,8 @@
 
 }  // namespace
 
+const char kChromeConnectedCookieName[] = "CHROME_CONNECTED";
+
 ChromeConnectedHeaderHelper::ChromeConnectedHeaderHelper(
     AccountConsistencyMethod account_consistency)
     : account_consistency_(account_consistency) {}
diff --git a/components/signin/core/browser/chrome_connected_header_helper.h b/components/signin/core/browser/chrome_connected_header_helper.h
index cf37ab1e..c17dc78 100644
--- a/components/signin/core/browser/chrome_connected_header_helper.h
+++ b/components/signin/core/browser/chrome_connected_header_helper.h
@@ -15,6 +15,12 @@
 
 namespace signin {
 
+// Name of the cookie used by Chrome sign-in to inform GAIA that an
+// authenticating user is already signed in to Chrome. Because it is not
+// possible to intercept headers from iOS WKWebView, Chrome requires this cookie
+// to communicate its signed-in state with GAIA.
+extern const char kChromeConnectedCookieName[];
+
 // SigninHeaderHelper implementation managing the "X-Chrome-Connected" header.
 class ChromeConnectedHeaderHelper : public SigninHeaderHelper {
  public:
diff --git a/components/signin/ios/browser/DEPS b/components/signin/ios/browser/DEPS
index 4f8bc28..5edadf85 100644
--- a/components/signin/ios/browser/DEPS
+++ b/components/signin/ios/browser/DEPS
@@ -9,10 +9,12 @@
 specific_include_rules = {
     "account_consistency_service.mm": [
       "+components/signin/core/browser/account_reconcilor.h",
+      "+components/signin/core/browser/chrome_connected_header_helper.h",
       "+components/signin/core/browser/signin_header_helper.h",
     ],
     "account_consistency_service_unittest.mm": [
       "+components/signin/core/browser/account_reconcilor.h",
       "+components/signin/core/browser/account_reconcilor_delegate.h",
+      "+components/signin/core/browser/chrome_connected_header_helper.h",
     ],
 }
diff --git a/components/signin/ios/browser/account_consistency_service.h b/components/signin/ios/browser/account_consistency_service.h
index 3b0ceef..d9e2406 100644
--- a/components/signin/ios/browser/account_consistency_service.h
+++ b/components/signin/ios/browser/account_consistency_service.h
@@ -39,11 +39,6 @@
 class AccountConsistencyService : public KeyedService,
                                   public signin::IdentityManager::Observer {
  public:
-  // Name of the cookie that is managed by AccountConsistencyService and is used
-  // to inform Google web properties that the browser is connected and that
-  // Google authentication cookies are managed by |AccountReconcilor|).
-  static const char kChromeConnectedCookieName[];
-
   AccountConsistencyService(
       web::BrowserState* browser_state,
       AccountReconcilor* account_reconcilor,
diff --git a/components/signin/ios/browser/account_consistency_service.mm b/components/signin/ios/browser/account_consistency_service.mm
index 7b1b98e..496fcad6 100644
--- a/components/signin/ios/browser/account_consistency_service.mm
+++ b/components/signin/ios/browser/account_consistency_service.mm
@@ -17,6 +17,7 @@
 #include "components/content_settings/core/browser/cookie_settings.h"
 #include "components/google/core/common/google_util.h"
 #include "components/signin/core/browser/account_reconcilor.h"
+#include "components/signin/core/browser/chrome_connected_header_helper.h"
 #include "components/signin/core/browser/signin_header_helper.h"
 #include "components/signin/ios/browser/features.h"
 #include "components/signin/public/base/account_consistency_method.h"
@@ -355,9 +356,6 @@
   account_consistency_service_->RemoveWebStateHandler(web_state());
 }
 
-const char AccountConsistencyService::kChromeConnectedCookieName[] =
-    "CHROME_CONNECTED";
-
 AccountConsistencyService::AccountConsistencyService(
     web::BrowserState* browser_state,
     AccountReconcilor* account_reconcilor,
@@ -458,7 +456,7 @@
 
   network::mojom::CookieDeletionFilterPtr filter =
       network::mojom::CookieDeletionFilter::New();
-  filter->cookie_name = kChromeConnectedCookieName;
+  filter->cookie_name = signin::kChromeConnectedCookieName;
 
   ++active_cookie_manager_requests_for_testing_;
   cookie_manager->DeleteCookies(
@@ -503,7 +501,7 @@
   std::unique_ptr<net::CanonicalCookie> cookie =
       net::CanonicalCookie::CreateSanitizedCookie(
           url,
-          /*name=*/kChromeConnectedCookieName, cookie_value,
+          /*name=*/signin::kChromeConnectedCookieName, cookie_value,
           /*domain=*/domain,
           /*path=*/std::string(),
           /*creation_time=*/base::Time::Now(),
diff --git a/components/signin/ios/browser/account_consistency_service_unittest.mm b/components/signin/ios/browser/account_consistency_service_unittest.mm
index 385562e..0bff9d4a 100644
--- a/components/signin/ios/browser/account_consistency_service_unittest.mm
+++ b/components/signin/ios/browser/account_consistency_service_unittest.mm
@@ -21,6 +21,7 @@
 #include "components/prefs/pref_service.h"
 #include "components/signin/core/browser/account_reconcilor.h"
 #include "components/signin/core/browser/account_reconcilor_delegate.h"
+#include "components/signin/core/browser/chrome_connected_header_helper.h"
 #include "components/signin/ios/browser/features.h"
 #import "components/signin/ios/browser/manage_accounts_delegate.h"
 #include "components/signin/public/base/list_accounts_test_utils.h"
@@ -196,24 +197,21 @@
 
   // Cookie verification APIs.
   void CheckDomainHasChromeConnectedCookie(const std::string& domain) {
-    EXPECT_TRUE(
-        ContainsCookie(GetCookiesInCookieJar(),
-                       AccountConsistencyService::kChromeConnectedCookieName,
-                       GetCookieDomain(domain)));
+    EXPECT_TRUE(ContainsCookie(GetCookiesInCookieJar(),
+                               signin::kChromeConnectedCookieName,
+                               GetCookieDomain(domain)));
   }
 
   void CheckNoChromeConnectedCookieForDomain(const std::string& domain) {
-    EXPECT_FALSE(
-        ContainsCookie(GetCookiesInCookieJar(),
-                       AccountConsistencyService::kChromeConnectedCookieName,
-                       GetCookieDomain(domain)));
+    EXPECT_FALSE(ContainsCookie(GetCookiesInCookieJar(),
+                                signin::kChromeConnectedCookieName,
+                                GetCookieDomain(domain)));
   }
 
   void CheckNoChromeConnectedCookies() {
-    EXPECT_FALSE(
-        ContainsCookie(GetCookiesInCookieJar(),
-                       AccountConsistencyService::kChromeConnectedCookieName,
-                       /*domain=*/std::string()));
+    EXPECT_FALSE(ContainsCookie(GetCookiesInCookieJar(),
+                                signin::kChromeConnectedCookieName,
+                                /*domain=*/std::string()));
   }
 
   // Verifies the time that the Gaia cookie was last updated for google.com.
diff --git a/components/signin/public/identity_manager/identity_manager.cc b/components/signin/public/identity_manager/identity_manager.cc
index 0f64d03..97b10b9 100644
--- a/components/signin/public/identity_manager/identity_manager.cc
+++ b/components/signin/public/identity_manager/identity_manager.cc
@@ -490,14 +490,6 @@
     case PrimaryAccountChangeEvent::Type::kNone:
       break;
   }
-  switch (event_details.GetEventTypeFor(ConsentLevel::kNotRequired)) {
-    case PrimaryAccountChangeEvent::Type::kSet:
-    case PrimaryAccountChangeEvent::Type::kCleared:
-      FireUnconsentedPrimaryAccountChanged(event_details);
-      break;
-    case PrimaryAccountChangeEvent::Type::kNone:
-      break;
-  }
 
   for (auto& observer : observer_list_)
     observer.OnPrimaryAccountChanged(event_details);
@@ -528,15 +520,6 @@
   }
 }
 
-void IdentityManager::FireUnconsentedPrimaryAccountChanged(
-    const PrimaryAccountChangeEvent& event_details) {
-  const CoreAccountInfo& account_info =
-      event_details.GetCurrentState().primary_account;
-  for (auto& observer : observer_list_) {
-    observer.OnUnconsentedPrimaryAccountChanged(account_info);
-  }
-}
-
 void IdentityManager::FirePrimaryAccountCleared(
     const PrimaryAccountChangeEvent& event_details) {
   const CoreAccountInfo& account_info =
diff --git a/components/signin/public/identity_manager/identity_manager.h b/components/signin/public/identity_manager/identity_manager.h
index 57317ff..37bec4f 100644
--- a/components/signin/public/identity_manager/identity_manager.h
+++ b/components/signin/public/identity_manager/identity_manager.h
@@ -101,22 +101,6 @@
     // General observers should use |OnPrimaryAccountChanged|.
     virtual void AfterSyncPrimaryAccountCleared() {}
 
-    // When the unconsented primary account (see ./README.md) of the user
-    // changes, this callback gets called with the new account as
-    // |unconsented_primary_account_info|. If after the change, there is no
-    // unconsented primary account, |unconsented_primary_account_info| is empty.
-    // This does not get called when the unconsented account becomes consented
-    // (as the same account was unconsented before so there is no change). In
-    // all other changes (the unconsented primary account gets added, changed or
-    // removed), this notification is called only once. Note: we do not use the
-    // {Set, Cleared} notifications like for the primary account above because
-    // the identity manager does not have clear guarantees that that account
-    // cannot change in one atomic operation (without getting cleared in the
-    // mean-time).
-    // DEPRECATED: Use OnPrimaryAccountChanged() instead.
-    virtual void OnUnconsentedPrimaryAccountChanged(
-        const CoreAccountInfo& unconsented_primary_account_info) {}
-
     // Called when a new refresh token is associated with |account_info|.
     // NOTE: On a signin event, the ordering of this callback wrt the
     // OnPrimaryAccountSet() callback is undefined. If you as a client are
@@ -679,8 +663,6 @@
   // Fire the deprecated observer methods for settings and clearing the primary
   // account.
   void FirePrimaryAccountSet(const PrimaryAccountChangeEvent& event_details);
-  void FireUnconsentedPrimaryAccountChanged(
-      const PrimaryAccountChangeEvent& event_details);
   void FirePrimaryAccountCleared(
       const PrimaryAccountChangeEvent& event_details);
 
diff --git a/components/signin/public/identity_manager/identity_manager_unittest.cc b/components/signin/public/identity_manager/identity_manager_unittest.cc
index 2170b44..a50b822 100644
--- a/components/signin/public/identity_manager/identity_manager_unittest.cc
+++ b/components/signin/public/identity_manager/identity_manager_unittest.cc
@@ -561,22 +561,23 @@
   ClearPrimaryAccount(identity_manager());
 
   SetPrimaryAccount(identity_manager(), kTestEmail);
+  auto event = identity_manager_observer()->GetPrimaryAccountChangedEvent();
+  EXPECT_EQ(PrimaryAccountChangeEvent::Type::kSet,
+            event.GetEventTypeFor(ConsentLevel::kSync));
+  EXPECT_EQ(PrimaryAccountChangeEvent::Type::kSet,
+            event.GetEventTypeFor(ConsentLevel::kNotRequired));
 
   CoreAccountInfo primary_account_from_set_callback =
-      identity_manager_observer()->PrimaryAccountFromSetCallback();
+      event.GetCurrentState().primary_account;
   EXPECT_EQ(kTestGaiaId, primary_account_from_set_callback.gaia);
   EXPECT_EQ(kTestEmail, primary_account_from_set_callback.email);
 
-  // Primary account is by definition also unconsented primary account.
-  EXPECT_EQ(
-      primary_account_from_set_callback,
-      identity_manager_observer()->UnconsentedPrimaryAccountFromCallback());
-
   CoreAccountInfo primary_account_info =
       identity_manager()->GetPrimaryAccountInfo();
   EXPECT_EQ(kTestGaiaId, primary_account_info.gaia);
   EXPECT_EQ(kTestEmail, primary_account_info.email);
 
+  // Primary account is by definition also unconsented primary account.
   EXPECT_EQ(primary_account_info, identity_manager()->GetPrimaryAccountInfo(
                                       ConsentLevel::kNotRequired));
 
@@ -599,15 +600,20 @@
   // Sign the user out and check that the IdentityManager responds
   // appropriately.
   ClearPrimaryAccount(identity_manager());
+  auto event = identity_manager_observer()->GetPrimaryAccountChangedEvent();
+  EXPECT_EQ(PrimaryAccountChangeEvent::Type::kCleared,
+            event.GetEventTypeFor(ConsentLevel::kSync));
+  EXPECT_EQ(PrimaryAccountChangeEvent::Type::kCleared,
+            event.GetEventTypeFor(ConsentLevel::kNotRequired));
 
   CoreAccountInfo primary_account_from_cleared_callback =
-      identity_manager_observer()->PrimaryAccountFromClearedCallback();
+      event.GetPreviousState().primary_account;
   EXPECT_EQ(kTestGaiaId, primary_account_from_cleared_callback.gaia);
   EXPECT_EQ(kTestEmail, primary_account_from_cleared_callback.email);
 
   // After the sign-out, there is no unconsented primary account.
-  EXPECT_TRUE(identity_manager_observer()
-                  ->UnconsentedPrimaryAccountFromCallback()
+  EXPECT_TRUE(identity_manager()
+                  ->GetPrimaryAccountInfo(ConsentLevel::kNotRequired)
                   .IsEmpty());
 
   CoreAccountInfo primary_account_info =
@@ -675,8 +681,9 @@
   EXPECT_FALSE(
       identity_manager()->HasPrimaryAccount(ConsentLevel::kNotRequired));
   EXPECT_FALSE(identity_manager_observer()
-                   ->PrimaryAccountFromClearedCallback()
-                   .IsEmpty());
+                   ->GetPrimaryAccountChangedEvent()
+                   .GetPreviousState()
+                   .primary_account.IsEmpty());
 #endif
 }
 
diff --git a/components/signin/public/identity_manager/identity_test_utils.cc b/components/signin/public/identity_manager/identity_test_utils.cc
index 588ff69..9820d33a 100644
--- a/components/signin/public/identity_manager/identity_test_utils.cc
+++ b/components/signin/public/identity_manager/identity_test_utils.cc
@@ -198,7 +198,14 @@
   DCHECK(identity_manager->GetPrimaryAccountMutator());
   base::RunLoop run_loop;
   TestIdentityManagerObserver signout_observer(identity_manager);
-  signout_observer.SetOnPrimaryAccountClearedCallback(run_loop.QuitClosure());
+  signout_observer.SetOnPrimaryAccountChangedCallback(base::BindOnce(
+      [](base::RunLoop* run_loop, PrimaryAccountChangeEvent event) {
+        if (event.GetEventTypeFor(ConsentLevel::kSync) ==
+            PrimaryAccountChangeEvent::Type::kCleared) {
+          run_loop->Quit();
+        }
+      },
+      &run_loop));
   identity_manager->GetPrimaryAccountMutator()->RevokeSyncConsent(
       signin_metrics::SIGNOUT_TEST,
       signin_metrics::SignoutDelete::IGNORE_METRIC);
@@ -220,7 +227,14 @@
       identity_manager->HasPrimaryAccount(ConsentLevel::kSync);
   base::RunLoop run_loop;
   TestIdentityManagerObserver signout_observer(identity_manager);
-  signout_observer.SetOnPrimaryAccountClearedCallback(run_loop.QuitClosure());
+  signout_observer.SetOnPrimaryAccountChangedCallback(base::BindOnce(
+      [](base::RunLoop* run_loop, PrimaryAccountChangeEvent event) {
+        if (event.GetEventTypeFor(ConsentLevel::kNotRequired) ==
+            PrimaryAccountChangeEvent::Type::kCleared) {
+          run_loop->Quit();
+        }
+      },
+      &run_loop));
   identity_manager->GetPrimaryAccountMutator()->ClearPrimaryAccount(
       signin_metrics::SIGNOUT_TEST,
       signin_metrics::SignoutDelete::IGNORE_METRIC);
diff --git a/components/signin/public/identity_manager/test_identity_manager_observer.cc b/components/signin/public/identity_manager/test_identity_manager_observer.cc
index 6fcdd672..cd0087f 100644
--- a/components/signin/public/identity_manager/test_identity_manager_observer.cc
+++ b/components/signin/public/identity_manager/test_identity_manager_observer.cc
@@ -20,34 +20,14 @@
   identity_manager_->RemoveObserver(this);
 }
 
-void TestIdentityManagerObserver::SetOnPrimaryAccountSetCallback(
-    base::OnceClosure callback) {
-  on_primary_account_set_callback_ = std::move(callback);
+void TestIdentityManagerObserver::SetOnPrimaryAccountChangedCallback(
+    PrimaryAccountChangedCallback callback) {
+  on_primary_account_changed_callback_ = std::move(callback);
 }
 
-const CoreAccountInfo&
-TestIdentityManagerObserver::PrimaryAccountFromSetCallback() {
-  return primary_account_from_set_callback_;
-}
-
-void TestIdentityManagerObserver::SetOnPrimaryAccountClearedCallback(
-    base::OnceClosure callback) {
-  on_primary_account_cleared_callback_ = std::move(callback);
-}
-
-const CoreAccountInfo&
-TestIdentityManagerObserver::PrimaryAccountFromClearedCallback() {
-  return primary_account_from_cleared_callback_;
-}
-
-void TestIdentityManagerObserver::SetOnUnconsentedPrimaryAccountChangedCallback(
-    base::OnceClosure callback) {
-  on_unconsented_primary_account_callback_ = std::move(callback);
-}
-
-const CoreAccountInfo&
-TestIdentityManagerObserver::UnconsentedPrimaryAccountFromCallback() {
-  return unconsented_primary_account_from_callback_;
+const PrimaryAccountChangeEvent&
+TestIdentityManagerObserver::GetPrimaryAccountChangedEvent() {
+  return on_primary_account_changed_event_;
 }
 
 void TestIdentityManagerObserver::SetOnRefreshTokenUpdatedCallback(
@@ -135,36 +115,9 @@
 // IdentityManager::Observer:
 void TestIdentityManagerObserver::OnPrimaryAccountChanged(
     const PrimaryAccountChangeEvent& event) {
-  // TODO(https://crbug.com/1158855): Refactor this test observer to
-  // have a single on_primary_account_changed_callback_  and a single
-  // on_primary_account_changed_event_.
-  switch (event.GetEventTypeFor(ConsentLevel::kNotRequired)) {
-    case PrimaryAccountChangeEvent::Type::kSet:
-    case PrimaryAccountChangeEvent::Type::kCleared:
-      unconsented_primary_account_from_callback_ =
-          event.GetCurrentState().primary_account;
-      if (on_unconsented_primary_account_callback_)
-        std::move(on_unconsented_primary_account_callback_).Run();
-      break;
-    case PrimaryAccountChangeEvent::Type::kNone:
-      break;
-  }
-  switch (event.GetEventTypeFor(ConsentLevel::kSync)) {
-    case PrimaryAccountChangeEvent::Type::kSet:
-      primary_account_from_set_callback_ =
-          event.GetCurrentState().primary_account;
-      if (on_primary_account_set_callback_)
-        std::move(on_primary_account_set_callback_).Run();
-      break;
-    case PrimaryAccountChangeEvent::Type::kCleared:
-      primary_account_from_cleared_callback_ =
-          event.GetPreviousState().primary_account;
-      if (on_primary_account_cleared_callback_)
-        std::move(on_primary_account_cleared_callback_).Run();
-      break;
-    case PrimaryAccountChangeEvent::Type::kNone:
-      break;
-  }
+  on_primary_account_changed_event_ = event;
+  if (on_primary_account_changed_callback_)
+    std::move(on_primary_account_changed_callback_).Run(event);
 }
 
 void TestIdentityManagerObserver::OnRefreshTokenUpdatedForAccount(
diff --git a/components/signin/public/identity_manager/test_identity_manager_observer.h b/components/signin/public/identity_manager/test_identity_manager_observer.h
index 91479fe..59064de 100644
--- a/components/signin/public/identity_manager/test_identity_manager_observer.h
+++ b/components/signin/public/identity_manager/test_identity_manager_observer.h
@@ -20,18 +20,15 @@
 // the potential results and/or errors returned after such events have occurred.
 class TestIdentityManagerObserver : IdentityManager::Observer {
  public:
+  using PrimaryAccountChangedCallback =
+      base::OnceCallback<void(PrimaryAccountChangeEvent)>;
+
   explicit TestIdentityManagerObserver(IdentityManager* identity_manager);
   ~TestIdentityManagerObserver() override;
 
-  void SetOnPrimaryAccountSetCallback(base::OnceClosure callback);
-  const CoreAccountInfo& PrimaryAccountFromSetCallback();
-
-  void SetOnPrimaryAccountClearedCallback(base::OnceClosure callback);
-  const CoreAccountInfo& PrimaryAccountFromClearedCallback();
-
-  void SetOnUnconsentedPrimaryAccountChangedCallback(
-      base::OnceClosure callback);
-  const CoreAccountInfo& UnconsentedPrimaryAccountFromCallback();
+  void SetOnPrimaryAccountChangedCallback(
+      PrimaryAccountChangedCallback callback);
+  const PrimaryAccountChangeEvent& GetPrimaryAccountChangedEvent();
 
   void SetOnRefreshTokenUpdatedCallback(base::OnceClosure callback);
   const CoreAccountInfo& AccountFromRefreshTokenUpdatedCallback();
@@ -88,14 +85,8 @@
 
   IdentityManager* identity_manager_;
 
-  base::OnceClosure on_primary_account_set_callback_;
-  CoreAccountInfo primary_account_from_set_callback_;
-
-  base::OnceClosure on_primary_account_cleared_callback_;
-  CoreAccountInfo primary_account_from_cleared_callback_;
-
-  base::OnceClosure on_unconsented_primary_account_callback_;
-  CoreAccountInfo unconsented_primary_account_from_callback_;
+  PrimaryAccountChangedCallback on_primary_account_changed_callback_;
+  PrimaryAccountChangeEvent on_primary_account_changed_event_;
 
   base::OnceClosure on_refresh_token_updated_callback_;
   CoreAccountInfo account_from_refresh_token_updated_callback_;
diff --git a/components/speech/upstream_loader.cc b/components/speech/upstream_loader.cc
index 9a88c14..0f00733 100644
--- a/components/speech/upstream_loader.cc
+++ b/components/speech/upstream_loader.cc
@@ -19,8 +19,11 @@
   // Attach a chunked upload body.
   mojo::PendingRemote<network::mojom::ChunkedDataPipeGetter> data_remote;
   receiver_set_.Add(this, data_remote.InitWithNewPipeAndPassReceiver());
-  resource_request->request_body = new network::ResourceRequestBody();
-  resource_request->request_body->SetToChunkedDataPipe(std::move(data_remote));
+  resource_request->request_body =
+      base::MakeRefCounted<network::ResourceRequestBody>();
+  resource_request->request_body->SetToChunkedDataPipe(
+      std::move(data_remote),
+      network::ResourceRequestBody::ReadOnlyOnce(false));
   simple_url_loader_ = network::SimpleURLLoader::Create(
       std::move(resource_request), upstream_traffic_annotation);
   simple_url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
diff --git a/components/subresource_filter/core/browser/subresource_filter_features.h b/components/subresource_filter/core/browser/subresource_filter_features.h
index 61a9f5ef..9cb949a 100644
--- a/components/subresource_filter/core/browser/subresource_filter_features.h
+++ b/components/subresource_filter/core/browser/subresource_filter_features.h
@@ -180,7 +180,7 @@
 
 // Feature and variation parameter definitions -------------------------------
 
-// The master toggle to enable/disable the Safe Browsing Subresource Filter.
+// The primary toggle to enable/disable the Safe Browsing Subresource Filter.
 extern const base::Feature kSafeBrowsingSubresourceFilter;
 
 // Enables the blocking of ads on sites that are abusive.
diff --git a/components/subresource_filter/core/common/indexed_ruleset.cc b/components/subresource_filter/core/common/indexed_ruleset.cc
index c30209b..2a2efee9 100644
--- a/components/subresource_filter/core/common/indexed_ruleset.cc
+++ b/components/subresource_filter/core/common/indexed_ruleset.cc
@@ -74,7 +74,7 @@
   if (!offset.o)
     return false;
 
-  if (rule.semantics() == proto::RULE_SEMANTICS_BLACKLIST) {
+  if (rule.semantics() == proto::RULE_SEMANTICS_BLOCKLIST) {
     blocklist_.IndexUrlRule(offset);
   } else {
     const auto* flat_rule = flatbuffers::GetTemporaryPointer(builder_, offset);
@@ -150,7 +150,7 @@
   if (!rule)
     return LoadPolicy::ALLOW;
 
-  return rule->options() & url_pattern_index::flat::OptionFlag_IS_WHITELIST
+  return rule->options() & url_pattern_index::flat::OptionFlag_IS_ALLOWLIST
              ? LoadPolicy::EXPLICITLY_ALLOW
              : LoadPolicy::DISALLOW;
 }
diff --git a/components/subresource_filter/core/common/indexed_ruleset_unittest.cc b/components/subresource_filter/core/common/indexed_ruleset_unittest.cc
index cc4bc72..858efaf 100644
--- a/components/subresource_filter/core/common/indexed_ruleset_unittest.cc
+++ b/components/subresource_filter/core/common/indexed_ruleset_unittest.cc
@@ -72,14 +72,14 @@
 
   bool AddSimpleAllowlistRule(base::StringPiece url_pattern) {
     auto rule = MakeUrlRule(UrlPattern(url_pattern, testing::kSubstring));
-    rule.set_semantics(proto::RULE_SEMANTICS_WHITELIST);
+    rule.set_semantics(proto::RULE_SEMANTICS_ALLOWLIST);
     return AddUrlRule(rule);
   }
 
   bool AddSimpleAllowlistRule(base::StringPiece url_pattern,
                               int32_t activation_types) {
     auto rule = MakeUrlRule(UrlPattern(url_pattern, testing::kSubstring));
-    rule.set_semantics(proto::RULE_SEMANTICS_WHITELIST);
+    rule.set_semantics(proto::RULE_SEMANTICS_ALLOWLIST);
     rule.clear_element_types();
     rule.set_activation_types(activation_types);
     return AddUrlRule(rule);
diff --git a/components/subresource_filter/core/common/test_ruleset_utils.cc b/components/subresource_filter/core/common/test_ruleset_utils.cc
index ddf32f0..2e13d78 100644
--- a/components/subresource_filter/core/common/test_ruleset_utils.cc
+++ b/components/subresource_filter/core/common/test_ruleset_utils.cc
@@ -14,7 +14,7 @@
 proto::UrlRule CreateSubstringRule(base::StringPiece substring) {
   proto::UrlRule rule;
 
-  rule.set_semantics(proto::RULE_SEMANTICS_BLACKLIST);
+  rule.set_semantics(proto::RULE_SEMANTICS_BLOCKLIST);
   rule.set_source_type(proto::SOURCE_TYPE_ANY);
   rule.set_element_types(proto::ELEMENT_TYPE_ALL);
   rule.set_url_pattern_type(proto::URL_PATTERN_TYPE_SUBSTRING);
@@ -27,7 +27,7 @@
 
 proto::UrlRule CreateSuffixRule(base::StringPiece suffix) {
   proto::UrlRule rule;
-  rule.set_semantics(proto::RULE_SEMANTICS_BLACKLIST);
+  rule.set_semantics(proto::RULE_SEMANTICS_BLOCKLIST);
   rule.set_source_type(proto::SOURCE_TYPE_ANY);
   rule.set_element_types(proto::ELEMENT_TYPE_ALL);
   rule.set_url_pattern_type(proto::URL_PATTERN_TYPE_SUBSTRING);
@@ -39,7 +39,7 @@
 
 proto::UrlRule CreateAllowlistSuffixRule(base::StringPiece suffix) {
   proto::UrlRule rule;
-  rule.set_semantics(proto::RULE_SEMANTICS_WHITELIST);
+  rule.set_semantics(proto::RULE_SEMANTICS_ALLOWLIST);
   rule.set_source_type(proto::SOURCE_TYPE_ANY);
   rule.set_element_types(proto::ELEMENT_TYPE_ALL);
   rule.set_url_pattern_type(proto::URL_PATTERN_TYPE_SUBSTRING);
@@ -54,7 +54,7 @@
     int32_t activation_types,
     std::vector<std::string> domains) {
   proto::UrlRule rule;
-  rule.set_semantics(proto::RULE_SEMANTICS_WHITELIST);
+  rule.set_semantics(proto::RULE_SEMANTICS_ALLOWLIST);
   rule.set_source_type(proto::SOURCE_TYPE_ANY);
   rule.set_activation_types(activation_types);
 
diff --git a/components/subresource_filter/core/common/unindexed_ruleset_unittest.cc b/components/subresource_filter/core/common/unindexed_ruleset_unittest.cc
index 7d68fa2..ff7c95d 100644
--- a/components/subresource_filter/core/common/unindexed_ruleset_unittest.cc
+++ b/components/subresource_filter/core/common/unindexed_ruleset_unittest.cc
@@ -55,7 +55,7 @@
                   bool is_allowlist = false) {
     auto rule = testing::MakeUrlRule(url_pattern);
     if (is_allowlist)
-      rule.set_semantics(proto::RULE_SEMANTICS_WHITELIST);
+      rule.set_semantics(proto::RULE_SEMANTICS_ALLOWLIST);
     rule.set_source_type(source_type);
 
     url_rules_.push_back(rule);
diff --git a/components/subresource_filter/tools/filter_tool.cc b/components/subresource_filter/tools/filter_tool.cc
index ac1f8e7..2d56b66 100644
--- a/components/subresource_filter/tools/filter_tool.cc
+++ b/components/subresource_filter/tools/filter_tool.cc
@@ -144,7 +144,7 @@
                           ParseRequestUrl(url), ParseType(type));
 
   *blocked = rule && !(rule->options() &
-                       url_pattern_index::flat::OptionFlag_IS_WHITELIST);
+                       url_pattern_index::flat::OptionFlag_IS_ALLOWLIST);
   return rule;
 }
 
diff --git a/components/subresource_filter/tools/rule_parser/rule.cc b/components/subresource_filter/tools/rule_parser/rule.cc
index 0b9fa91..9882dce 100644
--- a/components/subresource_filter/tools/rule_parser/rule.cc
+++ b/components/subresource_filter/tools/rule_parser/rule.cc
@@ -81,8 +81,8 @@
   url_pattern_index::proto::UrlRule result;
 
   result.set_semantics(
-      is_allowlist ? url_pattern_index::proto::RULE_SEMANTICS_WHITELIST
-                   : url_pattern_index::proto::RULE_SEMANTICS_BLACKLIST);
+      is_allowlist ? url_pattern_index::proto::RULE_SEMANTICS_ALLOWLIST
+                   : url_pattern_index::proto::RULE_SEMANTICS_BLOCKLIST);
   switch (is_third_party) {
     case TriState::DONT_CARE:
       result.set_source_type(url_pattern_index::proto::SOURCE_TYPE_ANY);
@@ -151,8 +151,8 @@
   url_pattern_index::proto::CssRule result;
 
   result.set_semantics(
-      is_allowlist ? url_pattern_index::proto::RULE_SEMANTICS_WHITELIST
-                   : url_pattern_index::proto::RULE_SEMANTICS_BLACKLIST);
+      is_allowlist ? url_pattern_index::proto::RULE_SEMANTICS_ALLOWLIST
+                   : url_pattern_index::proto::RULE_SEMANTICS_BLOCKLIST);
 
   for (const std::string& domain : domains) {
     url_pattern_index::proto::DomainListItem* list_item = result.add_domains();
@@ -206,9 +206,9 @@
   std::string result;
 
   switch (rule.semantics()) {
-    case url_pattern_index::proto::RULE_SEMANTICS_BLACKLIST:
+    case url_pattern_index::proto::RULE_SEMANTICS_BLOCKLIST:
       break;
-    case url_pattern_index::proto::RULE_SEMANTICS_WHITELIST:
+    case url_pattern_index::proto::RULE_SEMANTICS_ALLOWLIST:
       result += "@@";
       break;
     default:
@@ -327,10 +327,10 @@
     DomainListJoin(rule.domains(), ',', &result);
 
   switch (rule.semantics()) {
-    case url_pattern_index::proto::RULE_SEMANTICS_BLACKLIST:
+    case url_pattern_index::proto::RULE_SEMANTICS_BLOCKLIST:
       result += "##";
       break;
-    case url_pattern_index::proto::RULE_SEMANTICS_WHITELIST:
+    case url_pattern_index::proto::RULE_SEMANTICS_ALLOWLIST:
       result += "#@#";
       break;
     default:
diff --git a/components/sync/driver/active_devices_provider.h b/components/sync/driver/active_devices_provider.h
index 3aa0708..992342b 100644
--- a/components/sync/driver/active_devices_provider.h
+++ b/components/sync/driver/active_devices_provider.h
@@ -5,11 +5,14 @@
 #ifndef COMPONENTS_SYNC_DRIVER_ACTIVE_DEVICES_PROVIDER_H_
 #define COMPONENTS_SYNC_DRIVER_ACTIVE_DEVICES_PROVIDER_H_
 
+#include <string>
+#include <vector>
+
 #include "base/callback.h"
 
 namespace syncer {
 
-// An interface helping to get the number of active devices. Devices are
+// An interface helping to get the information about active devices. Devices are
 // considered active if there are DeviceInfo entries that are (typically) less
 // than one day old (with a little margin around half an hour).
 class ActiveDevicesProvider {
@@ -22,6 +25,12 @@
   // known yet (e.g. data types are not configured).
   virtual size_t CountActiveDevicesIfAvailable() = 0;
 
+  // Returns a list with all remote FCM registration tokens known to the current
+  // device. If |local_cache_guid| is not empty, then the corresponding device
+  // will be filtered out.
+  virtual std::vector<std::string> CollectFCMRegistrationTokensForInvalidations(
+      const std::string& local_cache_guid) = 0;
+
   // The |callback| will be called on each change in device infos. It might be
   // called multiple times with the same number of active devices. The
   // |callback| must be cleared before this object is destroyed.
diff --git a/components/sync/driver/glue/sync_engine_backend.cc b/components/sync/driver/glue/sync_engine_backend.cc
index a8d46f9..36930e1 100644
--- a/components/sync/driver/glue/sync_engine_backend.cc
+++ b/components/sync/driver/glue/sync_engine_backend.cc
@@ -527,12 +527,16 @@
   }
 }
 
-void SyncEngineBackend::DoOnActiveDevicesChanged(size_t active_devices) {
+void SyncEngineBackend::DoOnActiveDevicesChanged(
+    size_t active_devices,
+    std::vector<std::string> fcm_registration_tokens) {
   // If |active_devices| is 0, then current client doesn't know if there are any
   // other devices. It's safer to consider that there are some other active
   // devices.
   const bool single_client = active_devices == 1;
   sync_manager_->UpdateSingleClientStatus(single_client);
+  sync_manager_->UpdateActiveDeviceFCMRegistrationTokens(
+      std::move(fcm_registration_tokens));
 }
 
 void SyncEngineBackend::GetNigoriNodeForDebugging(AllNodesCallback callback) {
diff --git a/components/sync/driver/glue/sync_engine_backend.h b/components/sync/driver/glue/sync_engine_backend.h
index a51d1a4..65bfc36 100644
--- a/components/sync/driver/glue/sync_engine_backend.h
+++ b/components/sync/driver/glue/sync_engine_backend.h
@@ -154,8 +154,12 @@
   bool HasUnsyncedItemsForTest() const;
 
   // Called on each device infos change and might be called more than once with
-  // the same |active_devices|.
-  void DoOnActiveDevicesChanged(size_t active_devices);
+  // the same |active_devices|. |fcm_registration_tokens| contains a list of
+  // tokens for all known active devices (if available and excluding the local
+  // device if reflections are disabled).
+  void DoOnActiveDevicesChanged(
+      size_t active_devices,
+      std::vector<std::string> fcm_registration_tokens);
 
  private:
   friend class base::RefCountedThreadSafe<SyncEngineBackend>;
diff --git a/components/sync/driver/glue/sync_engine_impl.cc b/components/sync/driver/glue/sync_engine_impl.cc
index 4aecd1f..e422d437 100644
--- a/components/sync/driver/glue/sync_engine_impl.cc
+++ b/components/sync/driver/glue/sync_engine_impl.cc
@@ -18,6 +18,7 @@
 #include "components/invalidation/public/topic_invalidation_map.h"
 #include "components/sync/base/bind_to_task_runner.h"
 #include "components/sync/base/invalidation_helper.h"
+#include "components/sync/base/sync_base_switches.h"
 #include "components/sync/base/sync_prefs.h"
 #include "components/sync/driver/active_devices_provider.h"
 #include "components/sync/driver/glue/sync_engine_backend.h"
@@ -459,11 +460,19 @@
 
 void SyncEngineImpl::OnActiveDevicesChanged() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  std::string local_cache_guid;
+  if (!base::FeatureList::IsEnabled(switches::kSyncE2ELatencyMeasurement)) {
+    // End-to-end latency measurement relies on reflection, so if this is
+    // enabled, don't filter out the local device.
+    local_cache_guid = cached_status_.sync_id;
+  }
   sync_task_runner_->PostTask(
       FROM_HERE,
-      base::BindOnce(
-          &SyncEngineBackend::DoOnActiveDevicesChanged, backend_,
-          active_devices_provider_->CountActiveDevicesIfAvailable()));
+      base::BindOnce(&SyncEngineBackend::DoOnActiveDevicesChanged, backend_,
+                     active_devices_provider_->CountActiveDevicesIfAvailable(),
+                     active_devices_provider_
+                         ->CollectFCMRegistrationTokensForInvalidations(
+                             local_cache_guid)));
 }
 
 }  // namespace syncer
diff --git a/components/sync/driver/glue/sync_engine_impl_unittest.cc b/components/sync/driver/glue/sync_engine_impl_unittest.cc
index e40c6a0..de46d76 100644
--- a/components/sync/driver/glue/sync_engine_impl_unittest.cc
+++ b/components/sync/driver/glue/sync_engine_impl_unittest.cc
@@ -182,6 +182,10 @@
               SetActiveDevicesChangedCallback,
               (ActiveDevicesProvider::ActiveDevicesChangedCallback),
               (override));
+  MOCK_METHOD(std::vector<std::string>,
+              CollectFCMRegistrationTokensForInvalidations,
+              (const std::string&),
+              (override));
 };
 
 std::unique_ptr<HttpPostProviderFactory> CreateHttpBridgeFactory() {
diff --git a/components/sync/engine/sync_manager.h b/components/sync/engine/sync_manager.h
index 4f21bb8..e944f33 100644
--- a/components/sync/engine/sync_manager.h
+++ b/components/sync/engine/sync_manager.h
@@ -243,6 +243,10 @@
 
   // Notifies SyncManager that there are no other known active devices.
   virtual void UpdateSingleClientStatus(bool single_client) = 0;
+
+  // Updates the list of known active device FCM registration tokens.
+  virtual void UpdateActiveDeviceFCMRegistrationTokens(
+      std::vector<std::string> fcm_registration_tokens) = 0;
 };
 
 }  // namespace syncer
diff --git a/components/sync/engine_impl/commit.cc b/components/sync/engine_impl/commit.cc
index 97294fe0..b1dddd9 100644
--- a/components/sync/engine_impl/commit.cc
+++ b/components/sync/engine_impl/commit.cc
@@ -86,14 +86,16 @@
 Commit::~Commit() = default;
 
 // static
-std::unique_ptr<Commit> Commit::Init(ModelTypeSet enabled_types,
-                                     size_t max_entries,
-                                     const std::string& account_name,
-                                     const std::string& cache_guid,
-                                     bool cookie_jar_mismatch,
-                                     bool single_client,
-                                     CommitProcessor* commit_processor,
-                                     ExtensionsActivity* extensions_activity) {
+std::unique_ptr<Commit> Commit::Init(
+    ModelTypeSet enabled_types,
+    size_t max_entries,
+    const std::string& account_name,
+    const std::string& cache_guid,
+    bool cookie_jar_mismatch,
+    bool single_client,
+    const std::vector<std::string>& fcm_registration_tokens,
+    CommitProcessor* commit_processor,
+    ExtensionsActivity* extensions_activity) {
   // Gather per-type contributions.
   ContributionMap contributions =
       commit_processor->GatherCommitContributions(max_entries);
@@ -124,7 +126,8 @@
 
   // Set the client config params.
   commit_util::AddClientConfigParamsToMessage(
-      enabled_types, cookie_jar_mismatch, single_client, commit_message);
+      enabled_types, cookie_jar_mismatch, single_client,
+      fcm_registration_tokens, commit_message);
 
   // Finally, serialize all our contributions.
   for (const auto& contribution : contributions) {
diff --git a/components/sync/engine_impl/commit.h b/components/sync/engine_impl/commit.h
index 8478310..138397c 100644
--- a/components/sync/engine_impl/commit.h
+++ b/components/sync/engine_impl/commit.h
@@ -10,6 +10,7 @@
 #include <map>
 #include <memory>
 #include <string>
+#include <vector>
 
 #include "base/macros.h"
 #include "components/sync/base/extensions_activity.h"
@@ -45,14 +46,16 @@
   ~Commit();
 
   // |extensions_activity| may be null.
-  static std::unique_ptr<Commit> Init(ModelTypeSet enabled_types,
-                                      size_t max_entries,
-                                      const std::string& account_name,
-                                      const std::string& cache_guid,
-                                      bool cookie_jar_mismatch,
-                                      bool single_client,
-                                      CommitProcessor* commit_processor,
-                                      ExtensionsActivity* extensions_activity);
+  static std::unique_ptr<Commit> Init(
+      ModelTypeSet enabled_types,
+      size_t max_entries,
+      const std::string& account_name,
+      const std::string& cache_guid,
+      bool cookie_jar_mismatch,
+      bool single_client,
+      const std::vector<std::string>& fcm_registration_tokens,
+      CommitProcessor* commit_processor,
+      ExtensionsActivity* extensions_activity);
 
   // |extensions_activity| may be null.
   SyncerError PostAndProcessResponse(NudgeTracker* nudge_tracker,
diff --git a/components/sync/engine_impl/commit_util.cc b/components/sync/engine_impl/commit_util.cc
index faf4cca..6dc9a578 100644
--- a/components/sync/engine_impl/commit_util.cc
+++ b/components/sync/engine_impl/commit_util.cc
@@ -32,10 +32,12 @@
   }
 }
 
-void AddClientConfigParamsToMessage(ModelTypeSet enabled_types,
-                                    bool cookie_jar_mismatch,
-                                    bool single_client,
-                                    sync_pb::CommitMessage* message) {
+void AddClientConfigParamsToMessage(
+    ModelTypeSet enabled_types,
+    bool cookie_jar_mismatch,
+    bool single_client,
+    const std::vector<std::string>& fcm_registration_tokens,
+    sync_pb::CommitMessage* message) {
   sync_pb::ClientConfigParams* config_params = message->mutable_config_params();
   for (ModelType type : enabled_types) {
     if (ProxyTypes().Has(type))
@@ -46,6 +48,9 @@
   config_params->set_tabs_datatype_enabled(enabled_types.Has(PROXY_TABS));
   config_params->set_cookie_jar_mismatch(cookie_jar_mismatch);
   config_params->set_single_client(single_client);
+  for (const std::string& token : fcm_registration_tokens) {
+    *config_params->add_devices_fcm_registration_tokens() = token;
+  }
 }
 
 }  // namespace commit_util
diff --git a/components/sync/engine_impl/commit_util.h b/components/sync/engine_impl/commit_util.h
index bb00847..ba6aa86 100644
--- a/components/sync/engine_impl/commit_util.h
+++ b/components/sync/engine_impl/commit_util.h
@@ -6,6 +6,8 @@
 #define COMPONENTS_SYNC_ENGINE_IMPL_COMMIT_UTIL_H_
 
 #include <stdint.h>
+#include <string>
+#include <vector>
 
 #include "components/sync/base/extensions_activity.h"
 #include "components/sync/base/model_type.h"
@@ -26,10 +28,12 @@
     sync_pb::CommitMessage* message);
 
 // Fills the config_params field of |message|.
-void AddClientConfigParamsToMessage(ModelTypeSet enabled_types,
-                                    bool cookie_jar_mismatch,
-                                    bool single_client,
-                                    sync_pb::CommitMessage* message);
+void AddClientConfigParamsToMessage(
+    ModelTypeSet enabled_types,
+    bool cookie_jar_mismatch,
+    bool single_client,
+    const std::vector<std::string>& fcm_registration_tokens,
+    sync_pb::CommitMessage* message);
 
 }  // namespace commit_util
 
diff --git a/components/sync/engine_impl/cycle/sync_cycle_context.h b/components/sync/engine_impl/cycle/sync_cycle_context.h
index bc7b81e..f4b734e 100644
--- a/components/sync/engine_impl/cycle/sync_cycle_context.h
+++ b/components/sync/engine_impl/cycle/sync_cycle_context.h
@@ -8,6 +8,7 @@
 #include <stdint.h>
 
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/macros.h"
@@ -121,6 +122,15 @@
     poll_interval_ = interval;
   }
 
+  const std::vector<std::string>& active_device_fcm_registration_tokens()
+      const {
+    return active_device_fcm_registration_tokens_;
+  }
+  void set_active_device_fcm_registration_tokens(
+      std::vector<std::string> fcm_registration_tokens) {
+    active_device_fcm_registration_tokens_ = std::move(fcm_registration_tokens);
+  }
+
  private:
   base::ObserverList<SyncEngineEventListener>::Unchecked listeners_;
 
@@ -169,6 +179,9 @@
   // If there are no other known active devices.
   bool single_client_;
 
+  // A list of FCM registration tokens to send invalidations.
+  std::vector<std::string> active_device_fcm_registration_tokens_;
+
   base::TimeDelta poll_interval_;
 
   DISALLOW_COPY_AND_ASSIGN(SyncCycleContext);
diff --git a/components/sync/engine_impl/sync_manager_impl.cc b/components/sync/engine_impl/sync_manager_impl.cc
index 4d41c63..f5b57880 100644
--- a/components/sync/engine_impl/sync_manager_impl.cc
+++ b/components/sync/engine_impl/sync_manager_impl.cc
@@ -568,4 +568,10 @@
   cycle_context_->set_single_client(single_client);
 }
 
+void SyncManagerImpl::UpdateActiveDeviceFCMRegistrationTokens(
+    std::vector<std::string> fcm_registration_tokens) {
+  cycle_context_->set_active_device_fcm_registration_tokens(
+      std::move(fcm_registration_tokens));
+}
+
 }  // namespace syncer
diff --git a/components/sync/engine_impl/sync_manager_impl.h b/components/sync/engine_impl/sync_manager_impl.h
index b45a65c..607e43f 100644
--- a/components/sync/engine_impl/sync_manager_impl.h
+++ b/components/sync/engine_impl/sync_manager_impl.h
@@ -85,6 +85,8 @@
   void OnCookieJarChanged(bool account_mismatch) override;
   void UpdateInvalidationClientId(const std::string& client_id) override;
   void UpdateSingleClientStatus(bool single_client) override;
+  void UpdateActiveDeviceFCMRegistrationTokens(
+      std::vector<std::string> fcm_registration_tokens) override;
 
   // SyncEncryptionHandler::Observer implementation.
   void OnPassphraseRequired(
diff --git a/components/sync/engine_impl/syncer.cc b/components/sync/engine_impl/syncer.cc
index 6b06059..b1fba8d 100644
--- a/components/sync/engine_impl/syncer.cc
+++ b/components/sync/engine_impl/syncer.cc
@@ -150,8 +150,9 @@
         cycle->context()->max_commit_batch_size(),
         cycle->context()->account_name(), cycle->context()->cache_guid(),
         cycle->context()->cookie_jar_mismatch(),
-        cycle->context()->single_client(), &commit_processor,
-        cycle->context()->extensions_activity()));
+        cycle->context()->single_client(),
+        cycle->context()->active_device_fcm_registration_tokens(),
+        &commit_processor, cycle->context()->extensions_activity()));
     if (!commit) {
       break;
     }
diff --git a/components/sync/protocol/sync.proto b/components/sync/protocol/sync.proto
index b1347fb..9234a208 100644
--- a/components/sync/protocol/sync.proto
+++ b/components/sync/protocol/sync.proto
@@ -447,6 +447,20 @@
   // the committed data. The client is considered active if it's DeviceInfo has
   // updated recent enough.
   optional bool single_client = 4;
+
+  // A list of FCM registration tokens which are obtained from other clients.
+  // This list is used by the server to send invalidations to all other clients.
+  // If the list is empty, the server should treat this as "there is no
+  // information about other clients". In practice, this happens by the next
+  // causes:
+  // 1. This is the old client which doesn't set this field.
+  // 2. There are too many active devices and the list would have too many
+  // items.
+  // 3. An empty list could also mean that the current client is the only
+  // client. This case should be covered by the |single_client| field instead
+  // (otherwise it could be mixed up with older clients). The server doesn't
+  // have to use this field and can ignore it.
+  repeated string devices_fcm_registration_tokens = 5;
 }
 
 message CommitMessage {
diff --git a/components/sync/test/engine/fake_sync_manager.cc b/components/sync/test/engine/fake_sync_manager.cc
index 192f00a..81d18c1 100644
--- a/components/sync/test/engine/fake_sync_manager.cc
+++ b/components/sync/test/engine/fake_sync_manager.cc
@@ -196,4 +196,9 @@
   // Do nothing.
 }
 
+void FakeSyncManager::UpdateActiveDeviceFCMRegistrationTokens(
+    std::vector<std::string> fcm_registration_tokens) {
+  // Do nothing.
+}
+
 }  // namespace syncer
diff --git a/components/sync/test/engine/fake_sync_manager.h b/components/sync/test/engine/fake_sync_manager.h
index ec0a207..811cd56 100644
--- a/components/sync/test/engine/fake_sync_manager.h
+++ b/components/sync/test/engine/fake_sync_manager.h
@@ -98,6 +98,8 @@
   void OnCookieJarChanged(bool account_mismatch) override;
   void UpdateInvalidationClientId(const std::string&) override;
   void UpdateSingleClientStatus(bool single_client) override;
+  void UpdateActiveDeviceFCMRegistrationTokens(
+      std::vector<std::string> fcm_registration_tokens) override;
 
  private:
   scoped_refptr<base::SequencedTaskRunner> sync_task_runner_;
diff --git a/components/url_pattern_index/flat/url_pattern_index.fbs b/components/url_pattern_index/flat/url_pattern_index.fbs
index fc55c34..10f16fe 100644
--- a/components/url_pattern_index/flat/url_pattern_index.fbs
+++ b/components/url_pattern_index/flat/url_pattern_index.fbs
@@ -25,7 +25,7 @@
 // url_pattern_index::proto::UrlRule, but here, they are represented as flags
 // of the same bitmask to allow for compact storage.
 enum OptionFlag : ubyte (bit_flags) {
-  IS_WHITELIST,
+  IS_ALLOWLIST,
   APPLIES_TO_FIRST_PARTY,
   APPLIES_TO_THIRD_PARTY,
   IS_CASE_INSENSITIVE,
diff --git a/components/url_pattern_index/proto/rules.proto b/components/url_pattern_index/proto/rules.proto
index 780fec79..04a8805 100644
--- a/components/url_pattern_index/proto/rules.proto
+++ b/components/url_pattern_index/proto/rules.proto
@@ -96,10 +96,10 @@
 
   // Matching subresource requests should be aborted, matching elements should
   // be hidden.
-  RULE_SEMANTICS_BLACKLIST = 1;
-  // If the rule matches, it suppresses any matching RULE_SEMANTICS_BLACKLIST
+  RULE_SEMANTICS_BLOCKLIST = 1;
+  // If the rule matches, it suppresses any matching RULE_SEMANTICS_BLOCKLIST
   // rule.
-  RULE_SEMANTICS_WHITELIST = 2;
+  RULE_SEMANTICS_ALLOWLIST = 2;
 }
 
 // The type of relation between the source of the requested subresource and that
diff --git a/components/url_pattern_index/url_pattern_index.cc b/components/url_pattern_index/url_pattern_index.cc
index 73a48ff5..3863491b 100644
--- a/components/url_pattern_index/url_pattern_index.cc
+++ b/components/url_pattern_index/url_pattern_index.cc
@@ -241,9 +241,9 @@
     static_assert(flat::OptionFlag_ANY <= std::numeric_limits<uint8_t>::max(),
                   "Option flags can not be stored in uint8_t.");
 
-    if (rule_.semantics() == proto::RULE_SEMANTICS_WHITELIST) {
-      options_ |= flat::OptionFlag_IS_WHITELIST;
-    } else if (rule_.semantics() != proto::RULE_SEMANTICS_BLACKLIST) {
+    if (rule_.semantics() == proto::RULE_SEMANTICS_ALLOWLIST) {
+      options_ |= flat::OptionFlag_IS_ALLOWLIST;
+    } else if (rule_.semantics() != proto::RULE_SEMANTICS_BLOCKLIST) {
       return false;  // Unsupported semantics.
     }
 
diff --git a/components/url_pattern_index/url_pattern_index_unittest.cc b/components/url_pattern_index/url_pattern_index_unittest.cc
index 51d80f3..46da07f 100644
--- a/components/url_pattern_index/url_pattern_index_unittest.cc
+++ b/components/url_pattern_index/url_pattern_index_unittest.cc
@@ -604,7 +604,7 @@
         << "; ActivationType: " << static_cast<int>(test_case.activation_type));
 
     auto rule = MakeUrlRule(UrlPattern(test_case.url_pattern, kSubstring));
-    rule.set_semantics(proto::RULE_SEMANTICS_WHITELIST);
+    rule.set_semantics(proto::RULE_SEMANTICS_ALLOWLIST);
     rule.clear_element_types();
     rule.set_activation_types(test_case.activation_types);
     ASSERT_TRUE(AddUrlRule(rule));
@@ -626,7 +626,7 @@
 
 TEST_F(UrlPatternIndexTest, OneRuleWithElementAndActivationTypes) {
   auto rule = MakeUrlRule(UrlPattern("allow.ex.com", kSubstring));
-  rule.set_semantics(proto::RULE_SEMANTICS_WHITELIST);
+  rule.set_semantics(proto::RULE_SEMANTICS_ALLOWLIST);
   rule.set_element_types(testing::kSubdocument);
   rule.set_activation_types(kDocument);
   ASSERT_TRUE(AddUrlRule(rule));
@@ -811,7 +811,7 @@
 
   for (const auto& rule_data : kRules) {
     auto rule = MakeUrlRule(UrlPattern("example.com", kSubstring));
-    rule.set_semantics(proto::RULE_SEMANTICS_WHITELIST);
+    rule.set_semantics(proto::RULE_SEMANTICS_ALLOWLIST);
     rule.set_element_types(rule_data.element_types);
     rule.set_activation_types(rule_data.activation_types);
     EXPECT_TRUE(AddUrlRule(rule))
diff --git a/components/url_pattern_index/url_rule_test_support.cc b/components/url_pattern_index/url_rule_test_support.cc
index 86a518a..5654e15 100644
--- a/components/url_pattern_index/url_rule_test_support.cc
+++ b/components/url_pattern_index/url_rule_test_support.cc
@@ -15,7 +15,7 @@
 proto::UrlRule MakeUrlRule(const UrlPattern& url_pattern) {
   proto::UrlRule rule;
 
-  rule.set_semantics(proto::RULE_SEMANTICS_BLACKLIST);
+  rule.set_semantics(proto::RULE_SEMANTICS_BLOCKLIST);
   rule.set_source_type(proto::SOURCE_TYPE_ANY);
   rule.set_element_types(kAllElementTypes);
 
diff --git a/components/url_pattern_index/url_rule_util.cc b/components/url_pattern_index/url_rule_util.cc
index d2e39e6..d2dd89b 100644
--- a/components/url_pattern_index/url_rule_util.cc
+++ b/components/url_pattern_index/url_rule_util.cc
@@ -153,7 +153,7 @@
 std::string FlatUrlRuleToFilterlistString(const flat::UrlRule* flat_rule) {
   std::string out;
 
-  if (flat_rule->options() & url_pattern_index::flat::OptionFlag_IS_WHITELIST)
+  if (flat_rule->options() & url_pattern_index::flat::OptionFlag_IS_ALLOWLIST)
     out += "@@";
 
   out += AnchorToString(flat_rule->anchor_left());
diff --git a/components/url_pattern_index/url_rule_util_unittest.cc b/components/url_pattern_index/url_rule_util_unittest.cc
index b06fad8..69337da 100644
--- a/components/url_pattern_index/url_rule_util_unittest.cc
+++ b/components/url_pattern_index/url_rule_util_unittest.cc
@@ -79,37 +79,37 @@
   DISALLOW_COPY_AND_ASSIGN(UrlRuleUtilTest);
 };
 
-TEST_F(UrlRuleUtilTest, Blacklist) {
+TEST_F(UrlRuleUtilTest, Blocklist) {
   const flat::UrlRule* flat_rule = MakeFlatRule(
-      MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com/"),
+      MakeProtoRule(proto::RULE_SEMANTICS_BLOCKLIST, UrlPattern("example.com/"),
                     proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
   EXPECT_EQ("example.com/", FlatUrlRuleToFilterlistString(flat_rule));
 }
 
-TEST_F(UrlRuleUtilTest, Whitelist) {
+TEST_F(UrlRuleUtilTest, Allowlist) {
   const flat::UrlRule* flat_rule = MakeFlatRule(
-      MakeProtoRule(proto::RULE_SEMANTICS_WHITELIST, UrlPattern("example.com/"),
+      MakeProtoRule(proto::RULE_SEMANTICS_ALLOWLIST, UrlPattern("example.com/"),
                     proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
   EXPECT_EQ("@@example.com/", FlatUrlRuleToFilterlistString(flat_rule));
 }
 
 TEST_F(UrlRuleUtilTest, LeftAnchor) {
   const flat::UrlRule* flat_rule = MakeFlatRule(
-      MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST,
+      MakeProtoRule(proto::RULE_SEMANTICS_BLOCKLIST,
                     UrlPattern("example.com/", proto::ANCHOR_TYPE_NONE,
                                proto::ANCHOR_TYPE_NONE),
                     proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
   EXPECT_EQ("example.com/", FlatUrlRuleToFilterlistString(flat_rule));
 
   flat_rule = MakeFlatRule(
-      MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST,
+      MakeProtoRule(proto::RULE_SEMANTICS_BLOCKLIST,
                     UrlPattern("example.com/", proto::ANCHOR_TYPE_BOUNDARY,
                                proto::ANCHOR_TYPE_NONE),
                     proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
   EXPECT_EQ("|example.com/", FlatUrlRuleToFilterlistString(flat_rule));
 
   flat_rule = MakeFlatRule(
-      MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST,
+      MakeProtoRule(proto::RULE_SEMANTICS_BLOCKLIST,
                     UrlPattern("example.com/", proto::ANCHOR_TYPE_SUBDOMAIN,
                                proto::ANCHOR_TYPE_NONE),
                     proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
@@ -118,14 +118,14 @@
 
 TEST_F(UrlRuleUtilTest, RightAnchor) {
   const flat::UrlRule* flat_rule = MakeFlatRule(
-      MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST,
+      MakeProtoRule(proto::RULE_SEMANTICS_BLOCKLIST,
                     UrlPattern("example.com", proto::ANCHOR_TYPE_NONE,
                                proto::ANCHOR_TYPE_NONE),
                     proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
   EXPECT_EQ("example.com", FlatUrlRuleToFilterlistString(flat_rule));
 
   flat_rule = MakeFlatRule(
-      MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST,
+      MakeProtoRule(proto::RULE_SEMANTICS_BLOCKLIST,
                     UrlPattern("example.com", proto::ANCHOR_TYPE_NONE,
                                proto::ANCHOR_TYPE_BOUNDARY),
                     proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
@@ -134,7 +134,7 @@
 
 TEST_F(UrlRuleUtilTest, BothSidesAnchored) {
   const flat::UrlRule* flat_rule = MakeFlatRule(
-      MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST,
+      MakeProtoRule(proto::RULE_SEMANTICS_BLOCKLIST,
                     UrlPattern("example.com", proto::ANCHOR_TYPE_SUBDOMAIN,
                                proto::ANCHOR_TYPE_BOUNDARY),
                     proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
@@ -143,13 +143,13 @@
 
 TEST_F(UrlRuleUtilTest, NonRegex) {
   const flat::UrlRule* flat_rule = MakeFlatRule(
-      MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("/foo/"),
+      MakeProtoRule(proto::RULE_SEMANTICS_BLOCKLIST, UrlPattern("/foo/"),
                     proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
   EXPECT_EQ("/foo/*", FlatUrlRuleToFilterlistString(flat_rule));
 
-  // Show that whitelist rules work too.
+  // Show that allowlist rules work too.
   flat_rule = MakeFlatRule(
-      MakeProtoRule(proto::RULE_SEMANTICS_WHITELIST, UrlPattern("/foo/"),
+      MakeProtoRule(proto::RULE_SEMANTICS_ALLOWLIST, UrlPattern("/foo/"),
                     proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
   EXPECT_EQ("@@/foo/*", FlatUrlRuleToFilterlistString(flat_rule));
 
@@ -159,13 +159,13 @@
 
 TEST_F(UrlRuleUtilTest, Party) {
   const flat::UrlRule* flat_rule = MakeFlatRule(MakeProtoRule(
-      proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com/"),
+      proto::RULE_SEMANTICS_BLOCKLIST, UrlPattern("example.com/"),
       proto::SOURCE_TYPE_THIRD_PARTY, proto::ELEMENT_TYPE_ALL, {}));
   EXPECT_EQ("example.com/$third-party",
             FlatUrlRuleToFilterlistString(flat_rule));
 
   flat_rule = MakeFlatRule(MakeProtoRule(
-      proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com/"),
+      proto::RULE_SEMANTICS_BLOCKLIST, UrlPattern("example.com/"),
       proto::SOURCE_TYPE_FIRST_PARTY, proto::ELEMENT_TYPE_ALL, {}));
   EXPECT_EQ("example.com/$~third-party",
             FlatUrlRuleToFilterlistString(flat_rule));
@@ -173,7 +173,7 @@
 
 TEST_F(UrlRuleUtilTest, MultipleOptions) {
   const flat::UrlRule* flat_rule = MakeFlatRule(MakeProtoRule(
-      proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com/"),
+      proto::RULE_SEMANTICS_BLOCKLIST, UrlPattern("example.com/"),
       proto::SOURCE_TYPE_THIRD_PARTY, proto::ELEMENT_TYPE_SCRIPT, {}));
   EXPECT_EQ("example.com/$third-party,script",
             FlatUrlRuleToFilterlistString(flat_rule));
@@ -182,20 +182,20 @@
 TEST_F(UrlRuleUtilTest, ElementType) {
   // Test a single type.
   const flat::UrlRule* flat_rule = MakeFlatRule(
-      MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com/"),
+      MakeProtoRule(proto::RULE_SEMANTICS_BLOCKLIST, UrlPattern("example.com/"),
                     proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_SCRIPT, {}));
   EXPECT_EQ("example.com/$script", FlatUrlRuleToFilterlistString(flat_rule));
 
   // Test blocking every type.
   flat_rule = MakeFlatRule(
-      MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com/"),
+      MakeProtoRule(proto::RULE_SEMANTICS_BLOCKLIST, UrlPattern("example.com/"),
                     proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
   EXPECT_EQ("example.com/", FlatUrlRuleToFilterlistString(flat_rule));
 
   // Block everything except other. This test will need to be updated as
   // proto::ElementType is changed.
   flat_rule = MakeFlatRule(MakeProtoRule(
-      proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com/"),
+      proto::RULE_SEMANTICS_BLOCKLIST, UrlPattern("example.com/"),
       proto::SOURCE_TYPE_ANY,
       static_cast<proto::ElementType>(proto::ELEMENT_TYPE_ALL - 1), {}));
   std::string expected =
@@ -209,13 +209,13 @@
 TEST_F(UrlRuleUtilTest, ActivationType) {
   // Test with no activiation type.
   const flat::UrlRule* flat_rule = MakeFlatRule(
-      MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com/"),
+      MakeProtoRule(proto::RULE_SEMANTICS_BLOCKLIST, UrlPattern("example.com/"),
                     proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
   EXPECT_EQ("example.com/", FlatUrlRuleToFilterlistString(flat_rule));
 
   // Test with a document activation type.
   auto proto_rule =
-      MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com/"),
+      MakeProtoRule(proto::RULE_SEMANTICS_BLOCKLIST, UrlPattern("example.com/"),
                     proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {});
   proto_rule.set_activation_types(proto::ACTIVATION_TYPE_DOCUMENT);
   flat_rule = MakeFlatRule(proto_rule);
@@ -232,13 +232,13 @@
 TEST_F(UrlRuleUtilTest, DomainList) {
   //  Test with no domains set.
   const flat::UrlRule* flat_rule = MakeFlatRule(
-      MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com/"),
+      MakeProtoRule(proto::RULE_SEMANTICS_BLOCKLIST, UrlPattern("example.com/"),
                     proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
   EXPECT_EQ("example.com/", FlatUrlRuleToFilterlistString(flat_rule));
 
   // Test with domains set.
   flat_rule = MakeFlatRule(
-      MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com/"),
+      MakeProtoRule(proto::RULE_SEMANTICS_BLOCKLIST, UrlPattern("example.com/"),
                     proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL,
                     {"foo.example.com", "~bar.example.com"}));
   EXPECT_EQ("example.com/$domain=foo.example.com|~bar.example.com",
diff --git a/components/viz/common/display/overlay_strategy.h b/components/viz/common/display/overlay_strategy.h
index 3fa5ede..549b11f 100644
--- a/components/viz/common/display/overlay_strategy.h
+++ b/components/viz/common/display/overlay_strategy.h
@@ -22,7 +22,8 @@
   kUnderlay = 4,
   kUnderlayCast = 5,
   kNoStrategyAllFail = 6,
-  kMaxValue = kNoStrategyAllFail,
+  kNoStrategyFailMin = 7,
+  kMaxValue = kNoStrategyFailMin,
 };
 
 // Parses a comma separated list of overlay strategy types and returns a list
diff --git a/components/viz/service/display/overlay_candidate.cc b/components/viz/service/display/overlay_candidate.cc
index a282da4..4fa7f92 100644
--- a/components/viz/service/display/overlay_candidate.cc
+++ b/components/viz/service/display/overlay_candidate.cc
@@ -31,8 +31,6 @@
 constexpr uint32_t OverlayCandidate::kInvalidDamageIndex;
 
 namespace {
-// Tolerance for considering axis vector elements to be zero.
-const SkScalar kEpsilon = std::numeric_limits<float>::epsilon();
 
 const gfx::BufferFormat kOverlayFormats[] = {
     gfx::BufferFormat::RGBX_8888, gfx::BufferFormat::RGBA_8888,
@@ -43,14 +41,14 @@
 enum Axis { NONE, AXIS_POS_X, AXIS_NEG_X, AXIS_POS_Y, AXIS_NEG_Y };
 
 Axis VectorToAxis(const gfx::Vector3dF& vec) {
-  if (std::abs(vec.z()) > kEpsilon)
+  if (!cc::MathUtil::IsWithinEpsilon(vec.z(), 0.f))
     return NONE;
-  const bool x_zero = (std::abs(vec.x()) <= kEpsilon);
-  const bool y_zero = (std::abs(vec.y()) <= kEpsilon);
+  const bool x_zero = cc::MathUtil::IsWithinEpsilon(vec.x(), 0.f);
+  const bool y_zero = cc::MathUtil::IsWithinEpsilon(vec.y(), 0.f);
   if (x_zero && !y_zero)
-    return (vec.y() > 0) ? AXIS_POS_Y : AXIS_NEG_Y;
+    return (vec.y() > 0.f) ? AXIS_POS_Y : AXIS_NEG_Y;
   else if (y_zero && !x_zero)
-    return (vec.x() > 0) ? AXIS_POS_X : AXIS_NEG_X;
+    return (vec.x() > 0.f) ? AXIS_POS_X : AXIS_NEG_X;
   else
     return NONE;
 }
@@ -64,7 +62,7 @@
   gfx::Vector3dF x_axis = cc::MathUtil::GetXAxis(quad_transform);
   gfx::Vector3dF y_axis = cc::MathUtil::GetYAxis(quad_transform);
   if (y_flipped) {
-    y_axis.Scale(-1);
+    y_axis.Scale(-1.f);
   }
 
   Axis x_to = VectorToAxis(x_axis);
@@ -121,20 +119,7 @@
 
 }  // namespace
 
-OverlayCandidate::OverlayCandidate()
-    : transform(gfx::OVERLAY_TRANSFORM_NONE),
-      format(gfx::BufferFormat::RGBA_8888),
-      uv_rect(0.f, 0.f, 1.f, 1.f),
-      is_clipped(false),
-      is_opaque(false),
-      resource_id(0),
-#if defined(OS_ANDROID)
-      is_backed_by_surface_texture(false),
-      is_promotable_hint(false),
-#endif
-      overlay_handled(false),
-      gpu_fence_id(0) {
-}
+OverlayCandidate::OverlayCandidate() = default;
 
 OverlayCandidate::OverlayCandidate(const OverlayCandidate& other) = default;
 
@@ -153,23 +138,26 @@
   if (!output_color_matrix.isIdentity())
     return false;
 
-  // We don't support an opacity value different than one for an overlay plane.
-  if (quad->shared_quad_state->opacity != 1.f)
-    return false;
+  const SharedQuadState* sqs = quad->shared_quad_state;
 
-  candidate->overlay_damage_index =
-      quad->shared_quad_state->overlay_damage_index.value_or(
-          kInvalidDamageIndex);
+  // We don't support an opacity value different than one for an overlay plane.
+  if (sqs->opacity != 1.f)
+    return false;
 
   // We can't support overlays with mask filter.
-  if (!quad->shared_quad_state->mask_filter_info.IsEmpty())
+  if (!sqs->mask_filter_info.IsEmpty())
     return false;
   // We support only kSrc (no blending) and kSrcOver (blending with premul).
-  if (!(quad->shared_quad_state->blend_mode == SkBlendMode::kSrc ||
-        quad->shared_quad_state->blend_mode == SkBlendMode::kSrcOver)) {
+  if (!(sqs->blend_mode == SkBlendMode::kSrc ||
+        sqs->blend_mode == SkBlendMode::kSrcOver)) {
     return false;
   }
 
+  candidate->requires_overlay = OverlayCandidate::RequiresOverlay(quad);
+
+  candidate->overlay_damage_index =
+      sqs->overlay_damage_index.value_or(kInvalidDamageIndex);
+
   switch (quad->material) {
     case DrawQuad::Material::kTextureContent:
       return FromTextureQuad(resource_provider, surface_damage_rect_list,
@@ -192,14 +180,14 @@
 // static
 bool OverlayCandidate::IsInvisibleQuad(const DrawQuad* quad) {
   float opacity = quad->shared_quad_state->opacity;
-  if (opacity < std::numeric_limits<float>::epsilon())
+  if (cc::MathUtil::IsWithinEpsilon(opacity, 0.f))
     return true;
   if (quad->material != DrawQuad::Material::kSolidColor)
     return false;
   const SkColor color = SolidColorDrawQuad::MaterialCast(quad)->color;
-  const float alpha = (SkColorGetA(color) * (1.0f / 255.0f)) * opacity;
+  const float alpha = (SkColorGetA(color) * (1.f / 255.f)) * opacity;
   return quad->ShouldDrawWithBlending() &&
-         alpha < std::numeric_limits<float>::epsilon();
+         cc::MathUtil::IsWithinEpsilon(alpha, 0.f);
 }
 
 // static
@@ -313,17 +301,18 @@
   if (!base::Contains(kOverlayFormats, candidate->format))
     return false;
 
-  gfx::OverlayTransform overlay_transform = GetOverlayTransform(
-      quad->shared_quad_state->quad_to_target_transform, y_flipped);
+  const SharedQuadState* sqs = quad->shared_quad_state;
+  gfx::OverlayTransform overlay_transform =
+      GetOverlayTransform(sqs->quad_to_target_transform, y_flipped);
   if (overlay_transform == gfx::OVERLAY_TRANSFORM_INVALID)
     return false;
 
-  auto& transform = quad->shared_quad_state->quad_to_target_transform;
+  auto& transform = sqs->quad_to_target_transform;
   candidate->display_rect = gfx::RectF(quad->rect);
   transform.TransformRect(&candidate->display_rect);
 
-  candidate->clip_rect = quad->shared_quad_state->clip_rect;
-  candidate->is_clipped = quad->shared_quad_state->is_clipped;
+  candidate->clip_rect = sqs->clip_rect;
+  candidate->is_clipped = sqs->is_clipped;
   candidate->is_opaque = !quad->ShouldDrawWithBlending();
   // For underlays the function 'EstimateVisibleDamage()' is called to update
   // |damage_area_estimate| to more accurately reflect the actual visible
@@ -333,7 +322,7 @@
   candidate->resource_id = resource_id;
   candidate->transform = overlay_transform;
   candidate->mailbox = resource_provider->GetMailbox(resource_id);
-  candidate->requires_overlay = OverlayCandidate::RequiresOverlay(quad);
+
   return true;
 }
 
@@ -359,7 +348,6 @@
   // damage.
   candidate->damage_area_estimate =
       GetDamageRect(quad, surface_damage_rect_list).size().GetArea();
-  candidate->requires_overlay = OverlayCandidate::RequiresOverlay(quad);
   return true;
 }
 
@@ -375,6 +363,7 @@
       (quad->background_color != SK_ColorBLACK ||
        quad->ShouldDrawWithBlending()))
     return false;
+
   if (!FromDrawQuadResource(resource_provider, surface_damage_rect_list, quad,
                             quad->resource_id(), quad->y_flipped, candidate)) {
     return false;
@@ -446,15 +435,15 @@
       candidate->uv_rect, candidate->resource_size_in_pixels.width(),
       candidate->resource_size_in_pixels.height());
   // Make it an integral multiple of the subsampling factor.
-  constexpr int kSubsamplingFactor = 2;
-  src_rect.set_x(kSubsamplingFactor *
-                 (std::lround(src_rect.x()) / kSubsamplingFactor));
-  src_rect.set_y(kSubsamplingFactor *
-                 (std::lround(src_rect.y()) / kSubsamplingFactor));
-  src_rect.set_width(kSubsamplingFactor *
-                     (std::lround(src_rect.width()) / kSubsamplingFactor));
-  src_rect.set_height(kSubsamplingFactor *
-                      (std::lround(src_rect.height()) / kSubsamplingFactor));
+  auto subsample_round = [](float val) {
+    constexpr int kSubsamplingFactor = 2;
+    return (std::lround(val) / kSubsamplingFactor) * kSubsamplingFactor;
+  };
+
+  src_rect.set_x(subsample_round(src_rect.x()));
+  src_rect.set_y(subsample_round(src_rect.y()));
+  src_rect.set_width(subsample_round(src_rect.width()));
+  src_rect.set_height(subsample_round(src_rect.height()));
   // Scale it back into UV space and set it in the candidate.
   candidate->uv_rect = gfx::ScaleRect(
       src_rect, 1.0f / candidate->resource_size_in_pixels.width(),
diff --git a/components/viz/service/display/overlay_candidate.h b/components/viz/service/display/overlay_candidate.h
index e7f2bca..ffef7a57 100644
--- a/components/viz/service/display/overlay_candidate.h
+++ b/components/viz/service/display/overlay_candidate.h
@@ -81,9 +81,9 @@
   ~OverlayCandidate();
 
   // Transformation to apply to layer during composition.
-  gfx::OverlayTransform transform;
+  gfx::OverlayTransform transform = gfx::OVERLAY_TRANSFORM_NONE;
   // Format of the buffer to scanout.
-  gfx::BufferFormat format;
+  gfx::BufferFormat format = gfx::BufferFormat::RGBA_8888;
   // ColorSpace of the buffer for scanout.
   gfx::ColorSpace color_space;
   // Size of the resource, in pixels.
@@ -92,15 +92,15 @@
   // to integer coordinates if setting |overlay_handled| to true.
   gfx::RectF display_rect;
   // Crop within the buffer to be placed inside |display_rect|.
-  gfx::RectF uv_rect;
+  gfx::RectF uv_rect = gfx::RectF(0.f, 0.f, 1.f, 1.f);
   // Clip rect in the target content space after composition.
   gfx::Rect clip_rect;
   // If the quad is clipped after composition.
-  bool is_clipped;
+  bool is_clipped = false;
   // If the quad doesn't require blending.
-  bool is_opaque;
+  bool is_opaque = false;
   // Texture resource to present in an overlay.
-  unsigned resource_id;
+  unsigned resource_id = 0;
   // Mailbox from resource_id. It is used by SkiaRenderer.
   gpu::Mailbox mailbox;
 
@@ -108,11 +108,7 @@
   // For candidates from StreamVideoDrawQuads, this records whether the quad is
   // marked as being backed by a SurfaceTexture or not.  If so, it's not really
   // promotable to an overlay.
-  bool is_backed_by_surface_texture;
-
-  // Filled in by the OverlayCandidateValidator to indicate whether this is a
-  // promotable candidate or not.
-  bool is_promotable_hint;
+  bool is_backed_by_surface_texture = false;
 #endif
 
   // Stacking order of the overlay plane relative to the main surface,
@@ -121,20 +117,20 @@
 
   // To be modified by the implementer if this candidate can go into
   // an overlay.
-  bool overlay_handled;
+  bool overlay_handled = false;
 
   // Gpu fence to wait for before overlay is ready for display.
-  unsigned gpu_fence_id;
+  unsigned gpu_fence_id = 0;
 
   // The total area in square pixels of damage for this candidate's quad. This
   // is an estimate when 'EstimateOccludedDamage' function is used.
   int damage_area_estimate = 0;
 
-  // Result of call to 'RequiresOverlay' function w/ associated quad.
   static constexpr uint32_t kInvalidDamageIndex = UINT_MAX;
+  // Damage index for |SurfaceDamageRectList|.
   uint32_t overlay_damage_index = kInvalidDamageIndex;
 
-  // Cached result of call to 'RequiresOverlay' function.
+  // Is true if an HW overlay is required for the quad content.
   bool requires_overlay = false;
 
  private:
diff --git a/components/viz/service/display/overlay_candidate_temporal_tracker.cc b/components/viz/service/display/overlay_candidate_temporal_tracker.cc
index ba81334f..db9e060 100644
--- a/components/viz/service/display/overlay_candidate_temporal_tracker.cc
+++ b/components/viz/service/display/overlay_candidate_temporal_tracker.cc
@@ -41,8 +41,9 @@
     uint64_t curr_frame,
     float damage_area_ratio,
     unsigned resource_id,
-    const OverlayCandidateTemporalTracker::Config& config) {
-  if (prev_resource_id != resource_id &&
+    const OverlayCandidateTemporalTracker::Config& config,
+    bool force_resource_update) {
+  if ((prev_resource_id != resource_id || force_resource_update) &&
       frame_record[(next_index + kNumRecords - 1) % kNumRecords] !=
           curr_frame) {
     frame_record[next_index] = curr_frame;
diff --git a/components/viz/service/display/overlay_candidate_temporal_tracker.h b/components/viz/service/display/overlay_candidate_temporal_tracker.h
index 42afda5..aebcee1 100644
--- a/components/viz/service/display/overlay_candidate_temporal_tracker.h
+++ b/components/viz/service/display/overlay_candidate_temporal_tracker.h
@@ -55,10 +55,16 @@
 
   // This function adds a new record to the tracker if the |resource_id| has
   // changed since last update.
+  // The |force_resource_update| flag has been added for the case when the
+  // resource has been updated but the |resource_id| has not changed. The case
+  // for when this occurs is a low latency surface (ink). Fortunately, we can
+  // use surface damage to ascertain when these surfaces have changed despite
+  // the |resource_id| remaining constant.
   void AddRecord(uint64_t curr_frame,
                  float damage_area_ratio,
                  unsigned resource_id,
-                 const Config& config);
+                 const Config& config,
+                 bool force_resource_update = false);
 
   // This function returns true when this tracker's 'AddRecord' was not called
   // in the previous frame. We require this behavior in order to know when an
diff --git a/components/viz/service/display/overlay_processor_using_strategy.cc b/components/viz/service/display/overlay_processor_using_strategy.cc
index 1c0080a..329258f 100644
--- a/components/viz/service/display/overlay_processor_using_strategy.cc
+++ b/components/viz/service/display/overlay_processor_using_strategy.cc
@@ -16,6 +16,7 @@
 #include "components/viz/common/quads/solid_color_draw_quad.h"
 #include "components/viz/service/display/display_resource_provider.h"
 #include "components/viz/service/display/output_surface.h"
+#include "components/viz/service/display/overlay_candidate.h"
 #include "components/viz/service/display/overlay_strategy_single_on_top.h"
 #include "components/viz/service/display/overlay_strategy_underlay.h"
 #include "ui/gfx/geometry/rect_conversions.h"
@@ -285,7 +286,9 @@
     track_data.AddRecord(
         frame_sequence_number_,
         static_cast<float>(it->candidate.damage_area_estimate) / display_area,
-        it->candidate.resource_id, tracker_config_);
+        it->candidate.resource_id, tracker_config_,
+        it->candidate.overlay_damage_index !=
+            OverlayCandidate::kInvalidDamageIndex);
 
     // Here a series of criteria are considered for wholesale rejection of a
     // candidate. The rational for rejection is usually power improvements but
@@ -357,7 +360,6 @@
     std::vector<gfx::Rect>* content_bounds,
     gfx::Rect* incoming_damage) {
   last_successful_strategy_ = nullptr;
-
   Strategy::OverlayProposedCandidateList proposed_candidates;
   for (const auto& strategy : strategies_) {
     strategy->ProposePrioritized(
@@ -366,13 +368,20 @@
         &proposed_candidates, content_bounds);
   }
 
+  size_t num_proposed_pre_sort = proposed_candidates.size();
   UMA_HISTOGRAM_COUNTS_1000(
       "Viz.DisplayCompositor.OverlayNumProposedCandidates",
-      proposed_candidates.size());
+      num_proposed_pre_sort);
 
   SortProposedOverlayCandidatesPrioritized(&proposed_candidates);
 
   for (auto&& candidate : proposed_candidates) {
+    // Underlays change the material so we save it here to record proper UMA.
+    DrawQuad::Material quad_material =
+        candidate.strategy->GetUMAEnum() != OverlayStrategy::kUnknown
+            ? candidate.quad_iter->material
+            : DrawQuad::Material::kInvalid;
+
     if (candidate.strategy->AttemptPrioritized(
             output_color_matrix, render_pass_backdrop_filters,
             resource_provider, render_pass_list, surface_damage_rect_list,
@@ -383,12 +392,16 @@
       LogStrategyEnumUMA(candidate.strategy->GetUMAEnum());
       last_successful_strategy_ = candidate.strategy;
       OnOverlaySwitchUMA(ToProposeKey(candidate));
+      UMA_HISTOGRAM_ENUMERATION("Viz.DisplayCompositor.OverlayQuadMaterial",
+                                quad_material);
       return true;
     }
   }
 
   if (proposed_candidates.size() == 0) {
-    LogStrategyEnumUMA(OverlayStrategy::kNoStrategyUsed);
+    LogStrategyEnumUMA(num_proposed_pre_sort != 0
+                           ? OverlayStrategy::kNoStrategyFailMin
+                           : OverlayStrategy::kNoStrategyUsed);
   } else {
     LogStrategyEnumUMA(OverlayStrategy::kNoStrategyAllFail);
   }
diff --git a/components/viz/service/display/overlay_unittest.cc b/components/viz/service/display/overlay_unittest.cc
index 6dff1b2..cfcd49e 100644
--- a/components/viz/service/display/overlay_unittest.cc
+++ b/components/viz/service/display/overlay_unittest.cc
@@ -2555,6 +2555,28 @@
   wait_1_frame();
   tracker.AddRecord(frame_counter, 0.0f, get_id(), config);
   EXPECT_FALSE(tracker.IsAbsent());
+
+  // Tracker forced updates were added to support quads that change content but
+  // not resource ids (example here is low latency ink surface). Here we test
+  // this small feature by keeping the resource id constant but passing in true
+  // to the force update param.
+  static const float kDamageRatio = 0.7f;
+  static const int kFakeConstantResourceId = 13;
+  for (int i = 0; i < OverlayCandidateTemporalTracker::kNumRecords; i++) {
+    wait_1_frame();
+    tracker.AddRecord(frame_counter, kDamageRatio, kFakeConstantResourceId,
+                      config, true);
+  }
+  EXPECT_FLOAT_EQ(kDamageRatio, tracker.MeanFrameRatioRate(config));
+
+  // Now test the false case for the force update param.
+  for (int i = 0; i < OverlayCandidateTemporalTracker::kNumRecords; i++) {
+    wait_1_frame();
+    tracker.AddRecord(frame_counter, 0.9f, kFakeConstantResourceId, config,
+                      false);
+  }
+  // The damage should remain unchanged.
+  EXPECT_FLOAT_EQ(kDamageRatio, tracker.MeanFrameRatioRate(config));
 }
 
 TEST_F(UnderlayTest, UpdateDamageRectWhenNoPromotion) {
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc
index d4d0c56..6bb2ab6f 100644
--- a/components/viz/service/display/skia_renderer.cc
+++ b/components/viz/service/display/skia_renderer.cc
@@ -1064,8 +1064,6 @@
 
     // Only sample from pixels behind the RPDQ for backdrop filters to avoid
     // color bleeding with pixel-moving filters.
-    // TODO(crbug.com/1165868): Add web platform test to verify this clip is
-    // done correctly.
     if (rpdq_params.bypass_geometry) {
       crop_rect.Intersect(rpdq_params.bypass_geometry->rect);
     } else {
diff --git a/content/browser/background_fetch/background_fetch_data_manager.cc b/content/browser/background_fetch/background_fetch_data_manager.cc
index 5368a47..66d736c 100644
--- a/content/browser/background_fetch/background_fetch_data_manager.cc
+++ b/content/browser/background_fetch/background_fetch_data_manager.cc
@@ -10,6 +10,7 @@
 #include "base/containers/queue.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
+#include "components/services/storage/public/mojom/cache_storage_control.mojom.h"
 #include "content/browser/background_fetch/background_fetch_constants.h"
 #include "content/browser/background_fetch/background_fetch_data_manager_observer.h"
 #include "content/browser/background_fetch/background_fetch_request_info.h"
@@ -94,7 +95,8 @@
   DCHECK(cache_storage_context_);
   cache_storage_context_->AddReceiver(
       cross_origin_embedder_policy, mojo::NullRemote(), origin,
-      CacheStorageOwner::kBackgroundFetch, remote.BindNewPipeAndPassReceiver());
+      storage::mojom::CacheStorageOwner::kBackgroundFetch,
+      remote.BindNewPipeAndPassReceiver());
 
   auto result = cache_storage_remote_map_.emplace(unique_id, std::move(remote));
   DCHECK(result.second);
diff --git a/content/browser/cache_storage/cache_storage_cache_entry_handler.cc b/content/browser/cache_storage/cache_storage_cache_entry_handler.cc
index 309f306..a315d7a 100644
--- a/content/browser/cache_storage/cache_storage_cache_entry_handler.cc
+++ b/content/browser/cache_storage/cache_storage_cache_entry_handler.cc
@@ -354,13 +354,13 @@
 // static
 std::unique_ptr<CacheStorageCacheEntryHandler>
 CacheStorageCacheEntryHandler::CreateCacheEntryHandler(
-    CacheStorageOwner owner,
+    storage::mojom::CacheStorageOwner owner,
     scoped_refptr<BlobStorageContextWrapper> blob_storage_context) {
   switch (owner) {
-    case CacheStorageOwner::kCacheAPI:
+    case storage::mojom::CacheStorageOwner::kCacheAPI:
       return std::make_unique<CacheStorageCacheEntryHandlerImpl>(
           std::move(blob_storage_context));
-    case CacheStorageOwner::kBackgroundFetch:
+    case storage::mojom::CacheStorageOwner::kBackgroundFetch:
       return std::make_unique<background_fetch::CacheEntryHandlerImpl>(
           std::move(blob_storage_context));
   }
diff --git a/content/browser/cache_storage/cache_storage_cache_entry_handler.h b/content/browser/cache_storage/cache_storage_cache_entry_handler.h
index bcbdd04..9a780db 100644
--- a/content/browser/cache_storage/cache_storage_cache_entry_handler.h
+++ b/content/browser/cache_storage/cache_storage_cache_entry_handler.h
@@ -13,6 +13,7 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/types/pass_key.h"
+#include "components/services/storage/public/mojom/cache_storage_control.mojom.h"
 #include "content/browser/cache_storage/cache_storage_cache.h"
 #include "content/browser/cache_storage/cache_storage_cache_handle.h"
 #include "content/browser/cache_storage/cache_storage_manager.h"
@@ -29,8 +30,6 @@
 
 namespace content {
 
-enum class CacheStorageOwner;
-
 // The state needed to pass when writing to a cache.
 struct PutContext {
   using ErrorCallback =
@@ -119,7 +118,7 @@
                                    blink::mojom::FetchAPIRequest* request) = 0;
 
   static std::unique_ptr<CacheStorageCacheEntryHandler> CreateCacheEntryHandler(
-      CacheStorageOwner owner,
+      storage::mojom::CacheStorageOwner owner,
       scoped_refptr<BlobStorageContextWrapper> blob_storage_context);
 
   void InvalidateDiskCacheBlobEntrys();
diff --git a/content/browser/cache_storage/cache_storage_cache_unittest.cc b/content/browser/cache_storage/cache_storage_cache_unittest.cc
index 2495bd8..0fba61f6 100644
--- a/content/browser/cache_storage/cache_storage_cache_unittest.cc
+++ b/content/browser/cache_storage/cache_storage_cache_unittest.cc
@@ -26,6 +26,7 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
+#include "components/services/storage/public/mojom/cache_storage_control.mojom.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
 #include "content/browser/cache_storage/cache_storage_cache.h"
 #include "content/browser/cache_storage/cache_storage_cache_handle.h"
@@ -444,7 +445,7 @@
       const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
       scoped_refptr<BlobStorageContextWrapper> blob_storage_context)
       : LegacyCacheStorageCache(origin,
-                                CacheStorageOwner::kCacheAPI,
+                                storage::mojom::CacheStorageOwner::kCacheAPI,
                                 cache_name,
                                 path,
                                 cache_storage,
@@ -521,7 +522,7 @@
       scoped_refptr<BlobStorageContextWrapper> blob_storage_context,
       LegacyCacheStorageManager* cache_storage_manager,
       const url::Origin& origin,
-      CacheStorageOwner owner)
+      storage::mojom::CacheStorageOwner owner)
       : LegacyCacheStorage(origin_path,
                            memory_only,
                            cache_task_runner,
@@ -589,7 +590,8 @@
         temp_dir_path_, MemoryOnly(), base::ThreadTaskRunnerHandle::Get().get(),
         base::ThreadTaskRunnerHandle::Get(), quota_manager_proxy_,
         blob_storage_context_, /* cache_storage_manager = */ nullptr,
-        url::Origin::Create(kTestUrl), CacheStorageOwner::kCacheAPI);
+        url::Origin::Create(kTestUrl),
+        storage::mojom::CacheStorageOwner::kCacheAPI);
 
     InitCache(mock_cache_storage_.get());
   }
diff --git a/content/browser/cache_storage/cache_storage_context_impl.cc b/content/browser/cache_storage/cache_storage_context_impl.cc
index e2b2f8a8..6c8ac38 100644
--- a/content/browser/cache_storage/cache_storage_context_impl.cc
+++ b/content/browser/cache_storage/cache_storage_context_impl.cc
@@ -103,7 +103,7 @@
     mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>
         coep_reporter,
     const url::Origin& origin,
-    CacheStorageOwner owner,
+    storage::mojom::CacheStorageOwner owner,
     mojo::PendingReceiver<blink::mojom::CacheStorage> receiver) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (!dispatcher_host_) {
@@ -190,8 +190,9 @@
               std::move(callback).Run(std::vector<StorageUsageInfo>());
               return;
             }
-            manager->GetAllOriginsUsage(CacheStorageOwner::kCacheAPI,
-                                        std::move(callback));
+            manager->GetAllOriginsUsage(
+                storage::mojom::CacheStorageOwner::kCacheAPI,
+                std::move(callback));
           },
           base::RetainedRef(this), std::move(callback)));
 }
@@ -206,8 +207,9 @@
                            context->CacheManager();
                        if (!manager)
                          return;
-                       manager->DeleteOriginData(origin,
-                                                 CacheStorageOwner::kCacheAPI);
+                       manager->DeleteOriginData(
+                           origin,
+                           storage::mojom::CacheStorageOwner::kCacheAPI);
                      },
                      base::RetainedRef(this), origin));
 }
@@ -244,7 +246,7 @@
   if (special_storage_policy_ &&
       special_storage_policy_->HasSessionOnlyOrigins()) {
     cache_manager_->GetAllOriginsUsage(
-        CacheStorageOwner::kCacheAPI,
+        storage::mojom::CacheStorageOwner::kCacheAPI,
         base::BindOnce(
             [](scoped_refptr<CacheStorageManager> cache_manager,
                scoped_refptr<storage::SpecialStoragePolicy>
@@ -256,7 +258,7 @@
                     !special_storage_policy->IsStorageProtected(
                         info.origin.GetURL())) {
                   cache_manager->DeleteOriginData(
-                      info.origin, CacheStorageOwner::kCacheAPI,
+                      info.origin, storage::mojom::CacheStorageOwner::kCacheAPI,
 
                       // Retain a reference to the manager until the deletion is
                       // complete, since it internally uses weak pointers for
@@ -309,12 +311,12 @@
     return;
   quota_manager_proxy->RegisterClient(
       base::MakeRefCounted<CacheStorageQuotaClient>(
-          manager, CacheStorageOwner::kCacheAPI),
+          manager, storage::mojom::CacheStorageOwner::kCacheAPI),
       storage::QuotaClientType::kServiceWorkerCache,
       {blink::mojom::StorageType::kTemporary});
   quota_manager_proxy->RegisterClient(
       base::MakeRefCounted<CacheStorageQuotaClient>(
-          manager, CacheStorageOwner::kBackgroundFetch),
+          manager, storage::mojom::CacheStorageOwner::kBackgroundFetch),
       storage::QuotaClientType::kBackgroundFetch,
       {blink::mojom::StorageType::kTemporary});
 }
diff --git a/content/browser/cache_storage/cache_storage_context_impl.h b/content/browser/cache_storage/cache_storage_context_impl.h
index a060f38..ad02266 100644
--- a/content/browser/cache_storage/cache_storage_context_impl.h
+++ b/content/browser/cache_storage/cache_storage_context_impl.h
@@ -14,6 +14,7 @@
 #include "base/synchronization/lock.h"
 #include "base/threading/sequence_bound.h"
 #include "components/services/storage/public/mojom/blob_storage_context.mojom.h"
+#include "components/services/storage/public/mojom/cache_storage_control.mojom.h"
 #include "content/browser/cache_storage/cache_storage_manager.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/cache_storage_context.h"
@@ -62,7 +63,8 @@
 // CacheStorageManager instance, which is only accessed on the target
 // sequence.
 class CONTENT_EXPORT CacheStorageContextImpl
-    : public CacheStorageContextWithManager {
+    : public CacheStorageContextWithManager,
+      public storage::mojom::CacheStorageControl {
  public:
   CacheStorageContextImpl();
 
@@ -91,8 +93,8 @@
       mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>
           coep_reporter_remote,
       const url::Origin& origin,
-      CacheStorageOwner owner,
-      mojo::PendingReceiver<blink::mojom::CacheStorage> receiver);
+      storage::mojom::CacheStorageOwner owner,
+      mojo::PendingReceiver<blink::mojom::CacheStorage> receiver) override;
 
   // If called on the cache_storage target sequence the real manager will be
   // returned directly.  If called on any other sequence then a cross-sequence
diff --git a/content/browser/cache_storage/cache_storage_dispatcher_host.cc b/content/browser/cache_storage/cache_storage_dispatcher_host.cc
index 6d2630d5..7c7d2979 100644
--- a/content/browser/cache_storage/cache_storage_dispatcher_host.cc
+++ b/content/browser/cache_storage/cache_storage_dispatcher_host.cc
@@ -170,7 +170,7 @@
       const CrossOriginEmbedderPolicy& cross_origin_embedder_policy,
       mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>
           coep_reporter,
-      CacheStorageOwner owner)
+      storage::mojom::CacheStorageOwner owner)
       : host_(host),
         cache_handle_(std::move(cache_handle)),
         origin_(origin),
@@ -369,7 +369,7 @@
                             GetAllMatchedEntriesCallback callback) override {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-    if (owner_ != CacheStorageOwner::kBackgroundFetch) {
+    if (owner_ != storage::mojom::CacheStorageOwner::kBackgroundFetch) {
       host_->cache_receivers_.ReportBadMessage("CSDH_BAD_OWNER");
       return;
     }
@@ -607,7 +607,7 @@
   const CrossOriginEmbedderPolicy cross_origin_embedder_policy_;
   mojo::Remote<network::mojom::CrossOriginEmbedderPolicyReporter>
       coep_reporter_;
-  const CacheStorageOwner owner_;
+  const storage::mojom::CacheStorageOwner owner_;
   SEQUENCE_CHECKER(sequence_checker_);
 
   base::WeakPtrFactory<CacheImpl> weak_factory_{this};
@@ -628,7 +628,7 @@
       const CrossOriginEmbedderPolicy& cross_origin_embedder_policy,
       mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>
           coep_reporter,
-      CacheStorageOwner owner)
+      storage::mojom::CacheStorageOwner owner)
       : host_(host),
         origin_(origin),
         cross_origin_embedder_policy_(cross_origin_embedder_policy),
@@ -950,7 +950,7 @@
   const CrossOriginEmbedderPolicy cross_origin_embedder_policy_;
   mojo::Remote<network::mojom::CrossOriginEmbedderPolicyReporter>
       coep_reporter_;
-  const CacheStorageOwner owner_;
+  const storage::mojom::CacheStorageOwner owner_;
   CacheStorageHandle cache_storage_handle_;
 
   SEQUENCE_CHECKER(sequence_checker_);
@@ -974,7 +974,7 @@
     mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>
         coep_reporter,
     const url::Origin& origin,
-    CacheStorageOwner owner,
+    storage::mojom::CacheStorageOwner owner,
     mojo::PendingReceiver<blink::mojom::CacheStorage> receiver) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   bool incognito = context_ ? context_->is_incognito() : false;
@@ -998,7 +998,7 @@
 
 CacheStorageHandle CacheStorageDispatcherHost::OpenCacheStorage(
     const url::Origin& origin,
-    CacheStorageOwner owner) {
+    storage::mojom::CacheStorageOwner owner) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!context_ || !OriginCanAccessCacheStorage(origin))
     return CacheStorageHandle();
diff --git a/content/browser/cache_storage/cache_storage_dispatcher_host.h b/content/browser/cache_storage/cache_storage_dispatcher_host.h
index 529656c..b3fe63a 100644
--- a/content/browser/cache_storage/cache_storage_dispatcher_host.h
+++ b/content/browser/cache_storage/cache_storage_dispatcher_host.h
@@ -7,6 +7,7 @@
 
 #include <stdint.h>
 
+#include "components/services/storage/public/mojom/cache_storage_control.mojom.h"
 #include "content/browser/cache_storage/cache_storage_handle.h"
 #include "content/browser/cache_storage/cache_storage_manager.h"
 #include "mojo/public/cpp/bindings/pending_associated_receiver.h"
@@ -50,7 +51,7 @@
       mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>
           coep_reporter,
       const url::Origin& origin,
-      CacheStorageOwner owner,
+      storage::mojom::CacheStorageOwner owner,
       mojo::PendingReceiver<blink::mojom::CacheStorage> receiver);
 
   void Shutdown();
@@ -65,7 +66,7 @@
       mojo::PendingAssociatedReceiver<blink::mojom::CacheStorageCache>
           receiver);
   CacheStorageHandle OpenCacheStorage(const url::Origin& origin,
-                                      CacheStorageOwner owner);
+                                      storage::mojom::CacheStorageOwner owner);
 
   scoped_refptr<CacheStorageContextImpl> context_;
 
diff --git a/content/browser/cache_storage/cache_storage_manager.h b/content/browser/cache_storage/cache_storage_manager.h
index 80cdfaa..6a10432 100644
--- a/content/browser/cache_storage/cache_storage_manager.h
+++ b/content/browser/cache_storage/cache_storage_manager.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/macros.h"
+#include "components/services/storage/public/mojom/cache_storage_control.mojom.h"
 #include "content/browser/blob_storage/blob_storage_context_wrapper.h"
 #include "content/browser/cache_storage/cache_storage_handle.h"
 #include "content/common/content_export.h"
@@ -22,18 +23,6 @@
 
 namespace content {
 
-enum class CacheStorageOwner {
-  kMinValue,
-
-  // Caches that can be accessed by the JS CacheStorage API (developer facing).
-  kCacheAPI = kMinValue,
-
-  // Private cache to store background fetch downloads.
-  kBackgroundFetch,
-
-  kMaxValue = kBackgroundFetch
-};
-
 // Keeps track of a CacheStorage per origin. There is one CacheStorageManager
 // per CacheStorageOwner. Created and accessed from a single sequence.
 // TODO(jkarlin): Remove CacheStorage from memory once they're no
@@ -43,30 +32,31 @@
  public:
   // Open the CacheStorage for the given origin and owner.  A reference counting
   // handle is returned which can be stored and used similar to a weak pointer.
-  virtual CacheStorageHandle OpenCacheStorage(const url::Origin& origin,
-                                              CacheStorageOwner owner) = 0;
+  virtual CacheStorageHandle OpenCacheStorage(
+      const url::Origin& origin,
+      storage::mojom::CacheStorageOwner owner) = 0;
 
   // QuotaClient and Browsing Data Deletion support.
   virtual void GetAllOriginsUsage(
-      CacheStorageOwner owner,
+      storage::mojom::CacheStorageOwner owner,
       CacheStorageContext::GetUsageInfoCallback callback) = 0;
   virtual void GetOriginUsage(
       const url::Origin& origin_url,
-      CacheStorageOwner owner,
+      storage::mojom::CacheStorageOwner owner,
       storage::QuotaClient::GetOriginUsageCallback callback) = 0;
   virtual void GetOrigins(
-      CacheStorageOwner owner,
+      storage::mojom::CacheStorageOwner owner,
       storage::QuotaClient::GetOriginsForTypeCallback callback) = 0;
   virtual void GetOriginsForHost(
       const std::string& host,
-      CacheStorageOwner owner,
+      storage::mojom::CacheStorageOwner owner,
       storage::QuotaClient::GetOriginsForHostCallback callback) = 0;
   virtual void DeleteOriginData(
       const url::Origin& origin,
-      CacheStorageOwner owner,
+      storage::mojom::CacheStorageOwner owner,
       storage::QuotaClient::DeleteOriginDataCallback callback) = 0;
   virtual void DeleteOriginData(const url::Origin& origin,
-                                CacheStorageOwner owner) = 0;
+                                storage::mojom::CacheStorageOwner owner) = 0;
 
   // This must be called before any of the public Cache functions above.
   virtual void SetBlobParametersForCache(
diff --git a/content/browser/cache_storage/cache_storage_manager_unittest.cc b/content/browser/cache_storage/cache_storage_manager_unittest.cc
index e14a618..8bb2398 100644
--- a/content/browser/cache_storage/cache_storage_manager_unittest.cc
+++ b/content/browser/cache_storage/cache_storage_manager_unittest.cc
@@ -26,6 +26,7 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
+#include "components/services/storage/public/mojom/cache_storage_control.mojom.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
 #include "content/browser/cache_storage/cache_storage.pb.h"
 #include "content/browser/cache_storage/cache_storage_cache_handle.h"
@@ -456,7 +457,8 @@
 
   bool Open(const url::Origin& origin,
             const std::string& cache_name,
-            CacheStorageOwner owner = CacheStorageOwner::kCacheAPI) {
+            storage::mojom::CacheStorageOwner owner =
+                storage::mojom::CacheStorageOwner::kCacheAPI) {
     base::HistogramTester histogram_tester;
     base::RunLoop loop;
     CacheStorageHandle cache_storage =
@@ -479,7 +481,8 @@
 
   bool Has(const url::Origin& origin,
            const std::string& cache_name,
-           CacheStorageOwner owner = CacheStorageOwner::kCacheAPI) {
+           storage::mojom::CacheStorageOwner owner =
+               storage::mojom::CacheStorageOwner::kCacheAPI) {
     base::HistogramTester histogram_tester;
     base::RunLoop loop;
     CacheStorageHandle cache_storage =
@@ -495,7 +498,8 @@
 
   bool Delete(const url::Origin& origin,
               const std::string& cache_name,
-              CacheStorageOwner owner = CacheStorageOwner::kCacheAPI) {
+              storage::mojom::CacheStorageOwner owner =
+                  storage::mojom::CacheStorageOwner::kCacheAPI) {
     base::HistogramTester histogram_tester;
     base::RunLoop loop;
     CacheStorageHandle cache_storage =
@@ -510,7 +514,8 @@
   }
 
   size_t Keys(const url::Origin& origin,
-              CacheStorageOwner owner = CacheStorageOwner::kCacheAPI) {
+              storage::mojom::CacheStorageOwner owner =
+                  storage::mojom::CacheStorageOwner::kCacheAPI) {
     base::HistogramTester histogram_tester;
     base::RunLoop loop;
     CacheStorageHandle cache_storage =
@@ -528,7 +533,8 @@
                     const std::string& cache_name,
                     const GURL& url,
                     blink::mojom::CacheQueryOptionsPtr match_options = nullptr,
-                    CacheStorageOwner owner = CacheStorageOwner::kCacheAPI) {
+                    storage::mojom::CacheStorageOwner owner =
+                        storage::mojom::CacheStorageOwner::kCacheAPI) {
     auto request = blink::mojom::FetchAPIRequest::New();
     request->url = url;
     return StorageMatchWithRequest(origin, cache_name, std::move(request),
@@ -540,7 +546,8 @@
       const std::string& cache_name,
       blink::mojom::FetchAPIRequestPtr request,
       blink::mojom::CacheQueryOptionsPtr match_options = nullptr,
-      CacheStorageOwner owner = CacheStorageOwner::kCacheAPI) {
+      storage::mojom::CacheStorageOwner owner =
+          storage::mojom::CacheStorageOwner::kCacheAPI) {
     base::HistogramTester histogram_tester;
     base::RunLoop loop;
     CacheStorageHandle cache_storage =
@@ -570,7 +577,8 @@
       const url::Origin& origin,
       blink::mojom::FetchAPIRequestPtr request,
       blink::mojom::CacheQueryOptionsPtr match_options = nullptr,
-      CacheStorageOwner owner = CacheStorageOwner::kCacheAPI) {
+      storage::mojom::CacheStorageOwner owner =
+          storage::mojom::CacheStorageOwner::kCacheAPI) {
     base::HistogramTester histogram_tester;
     base::RunLoop loop;
     CacheStorageHandle cache_storage =
@@ -587,7 +595,7 @@
   }
 
   bool Write(const url::Origin& origin,
-             CacheStorageOwner owner,
+             storage::mojom::CacheStorageOwner owner,
              const std::string& cache_name,
              const std::string& request_url) {
     auto request = blink::mojom::FetchAPIRequest::New();
@@ -725,13 +733,13 @@
   }
 
   CacheStorageHandle CacheStorageForOrigin(const url::Origin& origin) {
-    return cache_manager_->OpenCacheStorage(origin,
-                                            CacheStorageOwner::kCacheAPI);
+    return cache_manager_->OpenCacheStorage(
+        origin, storage::mojom::CacheStorageOwner::kCacheAPI);
   }
 
-  int64_t GetOriginUsage(
-      const url::Origin& origin,
-      CacheStorageOwner owner = CacheStorageOwner::kCacheAPI) {
+  int64_t GetOriginUsage(const url::Origin& origin,
+                         storage::mojom::CacheStorageOwner owner =
+                             storage::mojom::CacheStorageOwner::kCacheAPI) {
     base::RunLoop loop;
     cache_manager_->GetOriginUsage(
         origin, owner,
@@ -747,7 +755,8 @@
   }
 
   std::vector<StorageUsageInfo> GetAllOriginsUsage(
-      CacheStorageOwner owner = CacheStorageOwner::kCacheAPI) {
+      storage::mojom::CacheStorageOwner owner =
+          storage::mojom::CacheStorageOwner::kCacheAPI) {
     base::RunLoop loop;
     cache_manager_->GetAllOriginsUsage(
         owner, base::BindLambdaForTesting(
@@ -876,9 +885,11 @@
 }
 
 TEST_P(CacheStorageManagerTestP, OpenSameCacheDifferentOwners) {
-  EXPECT_TRUE(Open(origin1_, "foo", CacheStorageOwner::kCacheAPI));
+  EXPECT_TRUE(
+      Open(origin1_, "foo", storage::mojom::CacheStorageOwner::kCacheAPI));
   CacheStorageCacheHandle cache_handle = std::move(callback_cache_handle_);
-  EXPECT_TRUE(Open(origin1_, "foo", CacheStorageOwner::kBackgroundFetch));
+  EXPECT_TRUE(Open(origin1_, "foo",
+                   storage::mojom::CacheStorageOwner::kBackgroundFetch));
   EXPECT_NE(callback_cache_handle_.value(), cache_handle.value());
 }
 
@@ -910,17 +921,23 @@
 }
 
 TEST_P(CacheStorageManagerTestP, HasCacheDifferentOwners) {
-  EXPECT_TRUE(Open(origin1_, "public", CacheStorageOwner::kCacheAPI));
-  EXPECT_TRUE(Open(origin1_, "bgf", CacheStorageOwner::kBackgroundFetch));
+  EXPECT_TRUE(
+      Open(origin1_, "public", storage::mojom::CacheStorageOwner::kCacheAPI));
+  EXPECT_TRUE(Open(origin1_, "bgf",
+                   storage::mojom::CacheStorageOwner::kBackgroundFetch));
 
-  EXPECT_TRUE(Has(origin1_, "public", CacheStorageOwner::kCacheAPI));
+  EXPECT_TRUE(
+      Has(origin1_, "public", storage::mojom::CacheStorageOwner::kCacheAPI));
   EXPECT_TRUE(callback_bool_);
-  EXPECT_FALSE(Has(origin1_, "bgf", CacheStorageOwner::kCacheAPI));
+  EXPECT_FALSE(
+      Has(origin1_, "bgf", storage::mojom::CacheStorageOwner::kCacheAPI));
   EXPECT_FALSE(callback_bool_);
 
-  EXPECT_TRUE(Has(origin1_, "bgf", CacheStorageOwner::kBackgroundFetch));
+  EXPECT_TRUE(Has(origin1_, "bgf",
+                  storage::mojom::CacheStorageOwner::kBackgroundFetch));
   EXPECT_TRUE(callback_bool_);
-  EXPECT_FALSE(Has(origin1_, "public", CacheStorageOwner::kBackgroundFetch));
+  EXPECT_FALSE(Has(origin1_, "public",
+                   storage::mojom::CacheStorageOwner::kBackgroundFetch));
   EXPECT_FALSE(callback_bool_);
 }
 
@@ -1029,24 +1046,30 @@
 }
 
 TEST_P(CacheStorageManagerTestP, StorageMatchDifferentOwners) {
-  EXPECT_TRUE(Open(origin1_, "foo", CacheStorageOwner::kCacheAPI));
+  EXPECT_TRUE(
+      Open(origin1_, "foo", storage::mojom::CacheStorageOwner::kCacheAPI));
   EXPECT_TRUE(CachePut(callback_cache_handle_.value(),
                        GURL("http://example.com/public")));
-  EXPECT_TRUE(Open(origin1_, "foo", CacheStorageOwner::kBackgroundFetch));
+  EXPECT_TRUE(Open(origin1_, "foo",
+                   storage::mojom::CacheStorageOwner::kBackgroundFetch));
   EXPECT_TRUE(
       CachePut(callback_cache_handle_.value(), GURL("http://example.com/bgf")));
 
   // Check the public cache.
   EXPECT_TRUE(StorageMatch(origin1_, "foo", GURL("http://example.com/public"),
-                           nullptr, CacheStorageOwner::kCacheAPI));
+                           nullptr,
+                           storage::mojom::CacheStorageOwner::kCacheAPI));
   EXPECT_FALSE(StorageMatch(origin1_, "foo", GURL("http://example.com/bgf"),
-                            nullptr, CacheStorageOwner::kCacheAPI));
+                            nullptr,
+                            storage::mojom::CacheStorageOwner::kCacheAPI));
 
   // Check the internal cache.
-  EXPECT_FALSE(StorageMatch(origin1_, "foo", GURL("http://example.com/public"),
-                            nullptr, CacheStorageOwner::kBackgroundFetch));
-  EXPECT_TRUE(StorageMatch(origin1_, "foo", GURL("http://example.com/bgf"),
-                           nullptr, CacheStorageOwner::kBackgroundFetch));
+  EXPECT_FALSE(
+      StorageMatch(origin1_, "foo", GURL("http://example.com/public"), nullptr,
+                   storage::mojom::CacheStorageOwner::kBackgroundFetch));
+  EXPECT_TRUE(
+      StorageMatch(origin1_, "foo", GURL("http://example.com/bgf"), nullptr,
+                   storage::mojom::CacheStorageOwner::kBackgroundFetch));
 }
 
 TEST_F(CacheStorageManagerTest, StorageReuseCacheName) {
@@ -1687,28 +1710,34 @@
 }
 
 TEST_P(CacheStorageManagerTestP, GetAllOriginsUsageDifferentOwners) {
-  EXPECT_EQ(0ULL, GetAllOriginsUsage(CacheStorageOwner::kCacheAPI).size());
-  EXPECT_EQ(0ULL,
-            GetAllOriginsUsage(CacheStorageOwner::kBackgroundFetch).size());
+  EXPECT_EQ(
+      0ULL,
+      GetAllOriginsUsage(storage::mojom::CacheStorageOwner::kCacheAPI).size());
+  EXPECT_EQ(0ULL, GetAllOriginsUsage(
+                      storage::mojom::CacheStorageOwner::kBackgroundFetch)
+                      .size());
 
   // Put one entry in a cache of owner 1.
-  EXPECT_TRUE(Open(origin1_, "foo", CacheStorageOwner::kCacheAPI));
+  EXPECT_TRUE(
+      Open(origin1_, "foo", storage::mojom::CacheStorageOwner::kCacheAPI));
   EXPECT_TRUE(
       CachePut(callback_cache_handle_.value(), GURL("http://example.com/foo")));
 
   // Put two entries (of identical size) in two origins in a cache of owner 2.
-  EXPECT_TRUE(Open(origin1_, "foo", CacheStorageOwner::kBackgroundFetch));
+  EXPECT_TRUE(Open(origin1_, "foo",
+                   storage::mojom::CacheStorageOwner::kBackgroundFetch));
   EXPECT_TRUE(
       CachePut(callback_cache_handle_.value(), GURL("http://example.com/foo")));
-  EXPECT_TRUE(Open(origin2_, "foo", CacheStorageOwner::kBackgroundFetch));
+  EXPECT_TRUE(Open(origin2_, "foo",
+                   storage::mojom::CacheStorageOwner::kBackgroundFetch));
   EXPECT_TRUE(
       CachePut(callback_cache_handle_.value(), GURL("http://example.com/bar")));
 
   std::vector<StorageUsageInfo> usage_cache =
-      GetAllOriginsUsage(CacheStorageOwner::kCacheAPI);
+      GetAllOriginsUsage(storage::mojom::CacheStorageOwner::kCacheAPI);
   EXPECT_EQ(1ULL, usage_cache.size());
   std::vector<StorageUsageInfo> usage_bgf =
-      GetAllOriginsUsage(CacheStorageOwner::kBackgroundFetch);
+      GetAllOriginsUsage(storage::mojom::CacheStorageOwner::kBackgroundFetch);
   EXPECT_EQ(2ULL, usage_bgf.size());
 
   int origin1_index = usage_bgf[0].origin == origin1_ ? 0 : 1;
@@ -1900,9 +1929,11 @@
 }
 
 TEST_P(CacheStorageManagerLegacyOnlyTestP, GetSizeThenCloseAllCachesTwoOwners) {
-  EXPECT_TRUE(Open(origin1_, "foo", CacheStorageOwner::kCacheAPI));
+  EXPECT_TRUE(
+      Open(origin1_, "foo", storage::mojom::CacheStorageOwner::kCacheAPI));
   CacheStorageCacheHandle public_handle = std::move(callback_cache_handle_);
-  EXPECT_TRUE(Open(origin1_, "foo", CacheStorageOwner::kBackgroundFetch));
+  EXPECT_TRUE(Open(origin1_, "foo",
+                   storage::mojom::CacheStorageOwner::kBackgroundFetch));
   CacheStorageCacheHandle bgf_handle = std::move(callback_cache_handle_);
 
   EXPECT_TRUE(
@@ -1949,7 +1980,8 @@
   auto* legacy_manager =
       static_cast<LegacyCacheStorageManager*>(cache_manager_.get());
   base::FilePath origin_path = LegacyCacheStorageManager::ConstructOriginPath(
-      legacy_manager->root_path(), origin1_, CacheStorageOwner::kCacheAPI);
+      legacy_manager->root_path(), origin1_,
+      storage::mojom::CacheStorageOwner::kCacheAPI);
   base::FilePath unreferenced_path = origin_path.AppendASCII("bar");
   EXPECT_TRUE(CreateDirectory(unreferenced_path));
   EXPECT_TRUE(base::DirectoryExists(unreferenced_path));
@@ -2267,27 +2299,34 @@
 }
 
 TEST_P(CacheStorageManagerTestP, StorageWriteToCache) {
-  EXPECT_TRUE(Open(origin1_, "foo", CacheStorageOwner::kBackgroundFetch));
+  EXPECT_TRUE(Open(origin1_, "foo",
+                   storage::mojom::CacheStorageOwner::kBackgroundFetch));
 
-  EXPECT_TRUE(Write(origin1_, CacheStorageOwner::kBackgroundFetch, "foo",
+  EXPECT_TRUE(Write(origin1_,
+                    storage::mojom::CacheStorageOwner::kBackgroundFetch, "foo",
                     "http://example.com/foo"));
 
   // Match request we just wrote.
-  EXPECT_TRUE(StorageMatch(origin1_, "foo", GURL("http://example.com/foo"),
-                           nullptr, CacheStorageOwner::kBackgroundFetch));
+  EXPECT_TRUE(
+      StorageMatch(origin1_, "foo", GURL("http://example.com/foo"), nullptr,
+                   storage::mojom::CacheStorageOwner::kBackgroundFetch));
 
   // Don't match with different origin.
-  EXPECT_FALSE(StorageMatch(origin2_, "foo", GURL("http://example.com/foo"),
-                            nullptr, CacheStorageOwner::kBackgroundFetch));
+  EXPECT_FALSE(
+      StorageMatch(origin2_, "foo", GURL("http://example.com/foo"), nullptr,
+                   storage::mojom::CacheStorageOwner::kBackgroundFetch));
   // Don't match with different cache name.
-  EXPECT_FALSE(StorageMatch(origin1_, "bar", GURL("http://example.com/foo"),
-                            nullptr, CacheStorageOwner::kBackgroundFetch));
+  EXPECT_FALSE(
+      StorageMatch(origin1_, "bar", GURL("http://example.com/foo"), nullptr,
+                   storage::mojom::CacheStorageOwner::kBackgroundFetch));
   // Don't match with different request.
-  EXPECT_FALSE(StorageMatch(origin1_, "foo", GURL("http://example.com/bar"),
-                            nullptr, CacheStorageOwner::kBackgroundFetch));
+  EXPECT_FALSE(
+      StorageMatch(origin1_, "foo", GURL("http://example.com/bar"), nullptr,
+                   storage::mojom::CacheStorageOwner::kBackgroundFetch));
   // Don't match with different owner.
   EXPECT_FALSE(StorageMatch(origin1_, "foo", GURL("http://example.com/foo"),
-                            nullptr, CacheStorageOwner::kCacheAPI));
+                            nullptr,
+                            storage::mojom::CacheStorageOwner::kCacheAPI));
 }
 
 TEST_F(CacheStorageManagerTest, WriteIndexOnlyScheduledWhenValueChanges) {
@@ -2377,7 +2416,7 @@
   void SetUp() override {
     CacheStorageManagerTest::SetUp();
     quota_client_ = base::MakeRefCounted<CacheStorageQuotaClient>(
-        cache_manager_, CacheStorageOwner::kCacheAPI);
+        cache_manager_, storage::mojom::CacheStorageOwner::kCacheAPI);
   }
 
   void QuotaUsageCallback(base::RunLoop* run_loop, int64_t usage) {
@@ -2479,9 +2518,10 @@
 TEST_P(CacheStorageQuotaClientTestP, QuotaGetOriginsForTypeDifferentOwners) {
   EXPECT_EQ(0u, QuotaGetOriginsForType());
   EXPECT_TRUE(Open(origin1_, "foo"));
-  // The |quota_client_| is registered for CacheStorageOwner::kCacheAPI, so this
-  // Open is ignored.
-  EXPECT_TRUE(Open(origin2_, "bar", CacheStorageOwner::kBackgroundFetch));
+  // The |quota_client_| is registered for
+  // storage::mojom::CacheStorageOwner::kCacheAPI, so this Open is ignored.
+  EXPECT_TRUE(Open(origin2_, "bar",
+                   storage::mojom::CacheStorageOwner::kBackgroundFetch));
   EXPECT_EQ(1u, QuotaGetOriginsForType());
 }
 
@@ -2543,7 +2583,7 @@
   quota_manager_proxy_->SimulateQuotaManagerDestroyed();
   RecreateStorageManager();
   quota_client_ = base::MakeRefCounted<CacheStorageQuotaClient>(
-      cache_manager_, CacheStorageOwner::kCacheAPI);
+      cache_manager_, storage::mojom::CacheStorageOwner::kCacheAPI);
 
   EXPECT_TRUE(QuotaDeleteOriginData(origin1_));
   EXPECT_EQ(0, QuotaGetOriginUsage(origin1_));
diff --git a/content/browser/cache_storage/cache_storage_quota_client.cc b/content/browser/cache_storage/cache_storage_quota_client.cc
index 7af4c17..bc68517 100644
--- a/content/browser/cache_storage/cache_storage_quota_client.cc
+++ b/content/browser/cache_storage/cache_storage_quota_client.cc
@@ -14,7 +14,7 @@
 
 CacheStorageQuotaClient::CacheStorageQuotaClient(
     scoped_refptr<CacheStorageManager> cache_manager,
-    CacheStorageOwner owner)
+    storage::mojom::CacheStorageOwner owner)
     : cache_manager_(std::move(cache_manager)), owner_(owner) {}
 
 CacheStorageQuotaClient::~CacheStorageQuotaClient() = default;
@@ -77,11 +77,11 @@
 
 // static
 storage::QuotaClientType CacheStorageQuotaClient::GetClientTypeFromOwner(
-    CacheStorageOwner owner) {
+    storage::mojom::CacheStorageOwner owner) {
   switch (owner) {
-    case CacheStorageOwner::kCacheAPI:
+    case storage::mojom::CacheStorageOwner::kCacheAPI:
       return storage::QuotaClientType::kServiceWorkerCache;
-    case CacheStorageOwner::kBackgroundFetch:
+    case storage::mojom::CacheStorageOwner::kBackgroundFetch:
       return storage::QuotaClientType::kBackgroundFetch;
   }
 }
diff --git a/content/browser/cache_storage/cache_storage_quota_client.h b/content/browser/cache_storage/cache_storage_quota_client.h
index bdccd07..6eee96c 100644
--- a/content/browser/cache_storage/cache_storage_quota_client.h
+++ b/content/browser/cache_storage/cache_storage_quota_client.h
@@ -7,6 +7,7 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "components/services/storage/public/mojom/cache_storage_control.mojom.h"
 #include "content/common/content_export.h"
 #include "storage/browser/quota/quota_client.h"
 #include "storage/browser/quota/quota_client_type.h"
@@ -16,7 +17,6 @@
 namespace content {
 
 class CacheStorageManager;
-enum class CacheStorageOwner;
 
 // CacheStorageQuotaClient is owned by the QuotaManager. There is one per
 // CacheStorageManager/CacheStorageOwner tuple.  Created and accessed on
@@ -24,7 +24,7 @@
 class CONTENT_EXPORT CacheStorageQuotaClient : public storage::QuotaClient {
  public:
   CacheStorageQuotaClient(scoped_refptr<CacheStorageManager> cache_manager,
-                          CacheStorageOwner owner);
+                          storage::mojom::CacheStorageOwner owner);
 
   // QuotaClient.
   void OnQuotaManagerDestroyed() override;
@@ -43,13 +43,13 @@
                              PerformStorageCleanupCallback callback) override;
 
   static storage::QuotaClientType GetClientTypeFromOwner(
-      CacheStorageOwner owner);
+      storage::mojom::CacheStorageOwner owner);
 
  private:
   ~CacheStorageQuotaClient() override;
 
   const scoped_refptr<CacheStorageManager> cache_manager_;
-  const CacheStorageOwner owner_;
+  const storage::mojom::CacheStorageOwner owner_;
 
   DISALLOW_COPY_AND_ASSIGN(CacheStorageQuotaClient);
 };
diff --git a/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage.cc b/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage.cc
index bb5e5f0..0221b14 100644
--- a/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage.cc
+++ b/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage.cc
@@ -23,7 +23,7 @@
                               blink::mojom::CacheStorageError)>;
 
   Inner(const url::Origin& origin,
-        CacheStorageOwner owner,
+        storage::mojom::CacheStorageOwner owner,
         scoped_refptr<CacheStorageContextWithManager> context) {
     scoped_refptr<CacheStorageManager> manager = context->CacheManager();
     if (manager)
@@ -158,7 +158,7 @@
 
 CrossSequenceCacheStorage::CrossSequenceCacheStorage(
     const url::Origin& origin,
-    CacheStorageOwner owner,
+    storage::mojom::CacheStorageOwner owner,
     scoped_refptr<base::SequencedTaskRunner> target_task_runner,
     scoped_refptr<CacheStorageContextWithManager> context)
     : CacheStorage(origin),
diff --git a/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage.h b/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage.h
index d4a8a41..d7ae67b 100644
--- a/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage.h
+++ b/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage.h
@@ -8,6 +8,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
 #include "base/threading/sequence_bound.h"
+#include "components/services/storage/public/mojom/cache_storage_control.mojom.h"
 #include "content/browser/cache_storage/cache_storage.h"
 #include "content/browser/cache_storage/cache_storage_manager.h"
 
@@ -29,7 +30,7 @@
  public:
   CrossSequenceCacheStorage(
       const url::Origin& origin,
-      CacheStorageOwner owner,
+      storage::mojom::CacheStorageOwner owner,
       scoped_refptr<base::SequencedTaskRunner> target_task_runner,
       scoped_refptr<CacheStorageContextWithManager> context);
 
diff --git a/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_manager.cc b/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_manager.cc
index df47e3e..90e8851 100644
--- a/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_manager.cc
+++ b/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_manager.cc
@@ -25,20 +25,20 @@
     DCHECK(target_manager_);
   }
 
-  void GetAllOriginsUsage(CacheStorageOwner owner,
+  void GetAllOriginsUsage(storage::mojom::CacheStorageOwner owner,
                           CacheStorageContext::GetUsageInfoCallback callback) {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     target_manager_->GetAllOriginsUsage(owner, std::move(callback));
   }
 
   void GetOriginUsage(const url::Origin& origin_url,
-                      CacheStorageOwner owner,
+                      storage::mojom::CacheStorageOwner owner,
                       storage::QuotaClient::GetOriginUsageCallback callback) {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     target_manager_->GetOriginUsage(origin_url, owner, std::move(callback));
   }
 
-  void GetOrigins(CacheStorageOwner owner,
+  void GetOrigins(storage::mojom::CacheStorageOwner owner,
                   storage::QuotaClient::GetOriginsForTypeCallback callback) {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     target_manager_->GetOrigins(owner, std::move(callback));
@@ -46,7 +46,7 @@
 
   void GetOriginsForHost(
       const std::string& host,
-      CacheStorageOwner owner,
+      storage::mojom::CacheStorageOwner owner,
       storage::QuotaClient::GetOriginsForHostCallback callback) {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     target_manager_->GetOriginsForHost(host, owner, std::move(callback));
@@ -54,7 +54,7 @@
 
   void DeleteOriginData(
       const url::Origin& origin,
-      CacheStorageOwner owner,
+      storage::mojom::CacheStorageOwner owner,
       storage::QuotaClient::DeleteOriginDataCallback callback) {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     target_manager_->DeleteOriginData(origin, owner, std::move(callback));
@@ -74,7 +74,7 @@
 
 CacheStorageHandle CrossSequenceCacheStorageManager::OpenCacheStorage(
     const url::Origin& origin,
-    CacheStorageOwner owner) {
+    storage::mojom::CacheStorageOwner owner) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // Construct the CrossSequenceCacheStorage object immediately on our current
   // sequence.  This is necessary in order to return a Handle synchronously.
@@ -86,7 +86,7 @@
 }
 
 void CrossSequenceCacheStorageManager::GetAllOriginsUsage(
-    CacheStorageOwner owner,
+    storage::mojom::CacheStorageOwner owner,
     CacheStorageContext::GetUsageInfoCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   inner_.Post(FROM_HERE, &Inner::GetAllOriginsUsage, owner,
@@ -95,7 +95,7 @@
 
 void CrossSequenceCacheStorageManager::GetOriginUsage(
     const url::Origin& origin_url,
-    CacheStorageOwner owner,
+    storage::mojom::CacheStorageOwner owner,
     storage::QuotaClient::GetOriginUsageCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   inner_.Post(FROM_HERE, &Inner::GetOriginUsage, origin_url, owner,
@@ -103,7 +103,7 @@
 }
 
 void CrossSequenceCacheStorageManager::GetOrigins(
-    CacheStorageOwner owner,
+    storage::mojom::CacheStorageOwner owner,
     storage::QuotaClient::GetOriginsForTypeCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   inner_.Post(FROM_HERE, &Inner::GetOrigins, owner,
@@ -112,7 +112,7 @@
 
 void CrossSequenceCacheStorageManager::GetOriginsForHost(
     const std::string& host,
-    CacheStorageOwner owner,
+    storage::mojom::CacheStorageOwner owner,
     storage::QuotaClient::GetOriginsForHostCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   inner_.Post(FROM_HERE, &Inner::GetOriginsForHost, host, owner,
@@ -121,7 +121,7 @@
 
 void CrossSequenceCacheStorageManager::DeleteOriginData(
     const url::Origin& origin,
-    CacheStorageOwner owner,
+    storage::mojom::CacheStorageOwner owner,
     storage::QuotaClient::DeleteOriginDataCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   inner_.Post(FROM_HERE, &Inner::DeleteOriginData, origin, owner,
@@ -130,7 +130,7 @@
 
 void CrossSequenceCacheStorageManager::DeleteOriginData(
     const url::Origin& origin,
-    CacheStorageOwner owner) {
+    storage::mojom::CacheStorageOwner owner) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DeleteOriginData(origin, owner, base::DoNothing());
 }
diff --git a/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_manager.h b/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_manager.h
index 489ee5b..bd76a2e 100644
--- a/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_manager.h
+++ b/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_manager.h
@@ -7,6 +7,7 @@
 
 #include "base/sequence_checker.h"
 #include "base/threading/sequence_bound.h"
+#include "components/services/storage/public/mojom/cache_storage_control.mojom.h"
 #include "content/browser/cache_storage/cache_storage_manager.h"
 
 namespace content {
@@ -28,28 +29,29 @@
       scoped_refptr<CacheStorageContextWithManager> context);
 
   // CacheStorageManager
-  CacheStorageHandle OpenCacheStorage(const url::Origin& origin,
-                                      CacheStorageOwner owner) override;
+  CacheStorageHandle OpenCacheStorage(
+      const url::Origin& origin,
+      storage::mojom::CacheStorageOwner owner) override;
   void GetAllOriginsUsage(
-      CacheStorageOwner owner,
+      storage::mojom::CacheStorageOwner owner,
       CacheStorageContext::GetUsageInfoCallback callback) override;
   void GetOriginUsage(
       const url::Origin& origin_url,
-      CacheStorageOwner owner,
+      storage::mojom::CacheStorageOwner owner,
       storage::QuotaClient::GetOriginUsageCallback callback) override;
   void GetOrigins(
-      CacheStorageOwner owner,
+      storage::mojom::CacheStorageOwner owner,
       storage::QuotaClient::GetOriginsForTypeCallback callback) override;
   void GetOriginsForHost(
       const std::string& host,
-      CacheStorageOwner owner,
+      storage::mojom::CacheStorageOwner owner,
       storage::QuotaClient::GetOriginsForHostCallback callback) override;
   void DeleteOriginData(
       const url::Origin& origin,
-      CacheStorageOwner owner,
+      storage::mojom::CacheStorageOwner owner,
       storage::QuotaClient::DeleteOriginDataCallback callback) override;
   void DeleteOriginData(const url::Origin& origin,
-                        CacheStorageOwner owner) override;
+                        storage::mojom::CacheStorageOwner owner) override;
   void SetBlobParametersForCache(
       scoped_refptr<BlobStorageContextWrapper> blob_storage_context) override;
 
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage.cc b/content/browser/cache_storage/legacy/legacy_cache_storage.cc
index 0c0beb6..5e85bd8 100644
--- a/content/browser/cache_storage/legacy/legacy_cache_storage.cc
+++ b/content/browser/cache_storage/legacy/legacy_cache_storage.cc
@@ -99,7 +99,7 @@
               scoped_refptr<BlobStorageContextWrapper> blob_storage_context,
               LegacyCacheStorage* cache_storage,
               const url::Origin& origin,
-              CacheStorageOwner owner)
+              storage::mojom::CacheStorageOwner owner)
       : cache_task_runner_(cache_task_runner),
         scheduler_task_runner_(std::move(scheduler_task_runner)),
         quota_manager_proxy_(std::move(quota_manager_proxy)),
@@ -158,7 +158,7 @@
   LegacyCacheStorage* cache_storage_;
 
   url::Origin origin_;
-  CacheStorageOwner owner_;
+  storage::mojom::CacheStorageOwner owner_;
 };
 
 // Creates memory-only ServiceWorkerCaches. Because these caches have no
@@ -174,7 +174,7 @@
                scoped_refptr<BlobStorageContextWrapper> blob_storage_context,
                LegacyCacheStorage* cache_storage,
                const url::Origin& origin,
-               CacheStorageOwner owner)
+               storage::mojom::CacheStorageOwner owner)
       : CacheLoader(cache_task_runner,
                     std::move(scheduler_task_runner),
                     std::move(quota_manager_proxy),
@@ -246,7 +246,7 @@
       scoped_refptr<BlobStorageContextWrapper> blob_storage_context,
       LegacyCacheStorage* cache_storage,
       const url::Origin& origin,
-      CacheStorageOwner owner)
+      storage::mojom::CacheStorageOwner owner)
       : CacheLoader(cache_task_runner,
                     std::move(scheduler_task_runner),
                     std::move(quota_manager_proxy),
@@ -589,7 +589,7 @@
     scoped_refptr<BlobStorageContextWrapper> blob_storage_context,
     LegacyCacheStorageManager* cache_storage_manager,
     const url::Origin& origin,
-    CacheStorageOwner owner)
+    storage::mojom::CacheStorageOwner owner)
     : CacheStorage(origin),
       initialized_(false),
       initializing_(false),
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage.h b/content/browser/cache_storage/legacy/legacy_cache_storage.h
index 145f49d..516ca13 100644
--- a/content/browser/cache_storage/legacy/legacy_cache_storage.h
+++ b/content/browser/cache_storage/legacy/legacy_cache_storage.h
@@ -17,6 +17,7 @@
 #include "base/memory/weak_ptr.h"
 #include "build/build_config.h"
 #include "components/services/storage/public/mojom/blob_storage_context.mojom.h"
+#include "components/services/storage/public/mojom/cache_storage_control.mojom.h"
 #include "content/browser/cache_storage/cache_storage.h"
 #include "content/browser/cache_storage/cache_storage_cache_observer.h"
 #include "content/browser/cache_storage/cache_storage_manager.h"
@@ -35,7 +36,6 @@
 namespace content {
 class CacheStorageIndex;
 class CacheStorageScheduler;
-enum class CacheStorageOwner;
 class LegacyCacheStorageManager;
 
 namespace cache_storage_manager_unittest {
@@ -65,7 +65,7 @@
       scoped_refptr<BlobStorageContextWrapper> blob_storage_context,
       LegacyCacheStorageManager* cache_storage_manager,
       const url::Origin& origin,
-      CacheStorageOwner owner);
+      storage::mojom::CacheStorageOwner owner);
 
   // Any unfinished asynchronous operations may not complete or call their
   // callbacks.
@@ -317,7 +317,7 @@
   scoped_refptr<BlobStorageContextWrapper> blob_storage_context_;
 
   // The owner that this CacheStorage is associated with.
-  CacheStorageOwner owner_;
+  storage::mojom::CacheStorageOwner owner_;
 
   CacheStorageSchedulerId init_id_ = -1;
 
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc
index 349446b..1fc6fe2 100644
--- a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc
+++ b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc
@@ -549,7 +549,7 @@
 std::unique_ptr<LegacyCacheStorageCache>
 LegacyCacheStorageCache::CreateMemoryCache(
     const url::Origin& origin,
-    CacheStorageOwner owner,
+    storage::mojom::CacheStorageOwner owner,
     const std::string& cache_name,
     LegacyCacheStorage* cache_storage,
     scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner,
@@ -570,7 +570,7 @@
 std::unique_ptr<LegacyCacheStorageCache>
 LegacyCacheStorageCache::CreatePersistentCache(
     const url::Origin& origin,
-    CacheStorageOwner owner,
+    storage::mojom::CacheStorageOwner owner,
     const std::string& cache_name,
     LegacyCacheStorage* cache_storage,
     const base::FilePath& path,
@@ -1022,7 +1022,7 @@
 
 LegacyCacheStorageCache::LegacyCacheStorageCache(
     const url::Origin& origin,
-    CacheStorageOwner owner,
+    storage::mojom::CacheStorageOwner owner,
     const std::string& cache_name,
     const base::FilePath& path,
     LegacyCacheStorage* cache_storage,
@@ -1079,7 +1079,7 @@
     return;
   }
 
-  if (owner_ != CacheStorageOwner::kBackgroundFetch &&
+  if (owner_ != storage::mojom::CacheStorageOwner::kBackgroundFetch &&
       (!options || !options->ignore_method) && request &&
       !request->method.empty() &&
       request->method != net::HttpRequestHeaders::kGetMethod) {
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.h b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.h
index 659ed7c..c35024f4 100644
--- a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.h
+++ b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.h
@@ -17,6 +17,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
+#include "components/services/storage/public/mojom/cache_storage_control.mojom.h"
 #include "content/browser/cache_storage/cache_storage_cache.h"
 #include "content/browser/cache_storage/cache_storage_handle.h"
 #include "content/browser/cache_storage/cache_storage_manager.h"
@@ -41,7 +42,6 @@
 class CacheStorageCacheEntryHandler;
 class CacheStorageCacheObserver;
 class CacheStorageScheduler;
-enum class CacheStorageOwner;
 class LegacyCacheStorage;
 struct PutContext;
 
@@ -64,7 +64,7 @@
 
   static std::unique_ptr<LegacyCacheStorageCache> CreateMemoryCache(
       const url::Origin& origin,
-      CacheStorageOwner owner,
+      storage::mojom::CacheStorageOwner owner,
       const std::string& cache_name,
       LegacyCacheStorage* cache_storage,
       scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner,
@@ -73,7 +73,7 @@
       std::unique_ptr<crypto::SymmetricKey> cache_padding_key);
   static std::unique_ptr<LegacyCacheStorageCache> CreatePersistentCache(
       const url::Origin& origin,
-      CacheStorageOwner owner,
+      storage::mojom::CacheStorageOwner owner,
       const std::string& cache_name,
       LegacyCacheStorage* cache_storage,
       const base::FilePath& path,
@@ -244,7 +244,7 @@
 
   LegacyCacheStorageCache(
       const url::Origin& origin,
-      CacheStorageOwner owner,
+      storage::mojom::CacheStorageOwner owner,
       const std::string& cache_name,
       const base::FilePath& path,
       LegacyCacheStorage* cache_storage,
@@ -509,7 +509,7 @@
   std::unique_ptr<disk_cache::Backend> backend_;
 
   url::Origin origin_;
-  CacheStorageOwner owner_;
+  storage::mojom::CacheStorageOwner owner_;
   const std::string cache_name_;
   base::FilePath path_;
 
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage_manager.cc b/content/browser/cache_storage/legacy/legacy_cache_storage_manager.cc
index 52f34e2..5503dee 100644
--- a/content/browser/cache_storage/legacy/legacy_cache_storage_manager.cc
+++ b/content/browser/cache_storage/legacy/legacy_cache_storage_manager.cc
@@ -128,7 +128,7 @@
 void ListOriginsAndLastModifiedOnTaskRunner(
     std::vector<StorageUsageInfo>* usages,
     base::FilePath root_path,
-    CacheStorageOwner owner) {
+    storage::mojom::CacheStorageOwner owner) {
   base::FileEnumerator file_enum(root_path, false /* recursive */,
                                  base::FileEnumerator::DIRECTORIES);
 
@@ -162,9 +162,10 @@
     auto origin_path = LegacyCacheStorageManager::ConstructOriginPath(
         root_path, origin, owner);
     if (path != origin_path) {
-      CacheStorageOwner other_owner = owner == CacheStorageOwner::kCacheAPI
-                                          ? CacheStorageOwner::kBackgroundFetch
-                                          : CacheStorageOwner::kCacheAPI;
+      storage::mojom::CacheStorageOwner other_owner =
+          owner == storage::mojom::CacheStorageOwner::kCacheAPI
+              ? storage::mojom::CacheStorageOwner::kBackgroundFetch
+              : storage::mojom::CacheStorageOwner::kCacheAPI;
       auto other_owner_path = LegacyCacheStorageManager::ConstructOriginPath(
           root_path, origin, other_owner);
       // Some of the paths in the |root_path| directory are for a different
@@ -186,8 +187,9 @@
   }
 }
 
-std::vector<url::Origin> ListOriginsOnTaskRunner(base::FilePath root_path,
-                                                 CacheStorageOwner owner) {
+std::vector<url::Origin> ListOriginsOnTaskRunner(
+    base::FilePath root_path,
+    storage::mojom::CacheStorageOwner owner) {
   std::vector<StorageUsageInfo> usages;
   ListOriginsAndLastModifiedOnTaskRunner(&usages, root_path, owner);
 
@@ -269,7 +271,7 @@
 
 CacheStorageHandle LegacyCacheStorageManager::OpenCacheStorage(
     const url::Origin& origin,
-    CacheStorageOwner owner) {
+    storage::mojom::CacheStorageOwner owner) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // Wait to create the MemoryPressureListener until the first CacheStorage
@@ -323,7 +325,7 @@
 void LegacyCacheStorageManager::CacheStorageUnreferenced(
     LegacyCacheStorage* cache_storage,
     const url::Origin& origin,
-    CacheStorageOwner owner) {
+    storage::mojom::CacheStorageOwner owner) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(cache_storage);
   cache_storage->AssertUnreferenced();
@@ -337,7 +339,7 @@
 }
 
 void LegacyCacheStorageManager::GetAllOriginsUsage(
-    CacheStorageOwner owner,
+    storage::mojom::CacheStorageOwner owner,
     CacheStorageContext::GetUsageInfoCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
@@ -392,8 +394,8 @@
       scheduler_task_runner_->PostTask(FROM_HERE, barrier_closure);
       continue;
     }
-    CacheStorageHandle cache_storage =
-        OpenCacheStorage(usage.origin, CacheStorageOwner::kCacheAPI);
+    CacheStorageHandle cache_storage = OpenCacheStorage(
+        usage.origin, storage::mojom::CacheStorageOwner::kCacheAPI);
     LegacyCacheStorage::From(cache_storage)
         ->Size(base::BindOnce(&OneOriginSizeReported, barrier_closure, &usage));
   }
@@ -401,7 +403,7 @@
 
 void LegacyCacheStorageManager::GetOriginUsage(
     const url::Origin& origin,
-    CacheStorageOwner owner,
+    storage::mojom::CacheStorageOwner owner,
     storage::QuotaClient::GetOriginUsageCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
@@ -410,7 +412,7 @@
 }
 
 void LegacyCacheStorageManager::GetOrigins(
-    CacheStorageOwner owner,
+    storage::mojom::CacheStorageOwner owner,
     storage::QuotaClient::GetOriginsForTypeCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
@@ -433,7 +435,7 @@
 
 void LegacyCacheStorageManager::GetOriginsForHost(
     const std::string& host,
-    CacheStorageOwner owner,
+    storage::mojom::CacheStorageOwner owner,
     storage::QuotaClient::GetOriginsForHostCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
@@ -459,7 +461,7 @@
 
 void LegacyCacheStorageManager::DeleteOriginData(
     const url::Origin& origin,
-    CacheStorageOwner owner,
+    storage::mojom::CacheStorageOwner owner,
     storage::QuotaClient::DeleteOriginDataCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
@@ -478,15 +480,16 @@
                      std::move(callback), base::WrapUnique(cache_storage)));
 }
 
-void LegacyCacheStorageManager::DeleteOriginData(const url::Origin& origin,
-                                                 CacheStorageOwner owner) {
+void LegacyCacheStorageManager::DeleteOriginData(
+    const url::Origin& origin,
+    storage::mojom::CacheStorageOwner owner) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DeleteOriginData(origin, owner, base::DoNothing());
 }
 
 void LegacyCacheStorageManager::DeleteOriginDidClose(
     const url::Origin& origin,
-    CacheStorageOwner owner,
+    storage::mojom::CacheStorageOwner owner,
     storage::QuotaClient::DeleteOriginDataCallback callback,
     std::unique_ptr<LegacyCacheStorage> cache_storage,
     int64_t origin_size) {
@@ -500,7 +503,7 @@
       CacheStorageQuotaClient::GetClientTypeFromOwner(owner), origin,
       blink::mojom::StorageType::kTemporary, -1 * origin_size);
 
-  if (owner == CacheStorageOwner::kCacheAPI)
+  if (owner == storage::mojom::CacheStorageOwner::kCacheAPI)
     NotifyCacheListChanged(origin);
 
   if (IsMemoryBacked()) {
@@ -533,9 +536,9 @@
 base::FilePath LegacyCacheStorageManager::ConstructOriginPath(
     const base::FilePath& root_path,
     const url::Origin& origin,
-    CacheStorageOwner owner) {
+    storage::mojom::CacheStorageOwner owner) {
   std::string identifier = storage::GetIdentifierFromOrigin(origin);
-  if (owner != CacheStorageOwner::kCacheAPI) {
+  if (owner != storage::mojom::CacheStorageOwner::kCacheAPI) {
     identifier += "-" + std::to_string(static_cast<int>(owner));
   }
   const std::string origin_hash = base::SHA1HashString(identifier);
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage_manager.h b/content/browser/cache_storage/legacy/legacy_cache_storage_manager.h
index 8266ede..5f5666f 100644
--- a/content/browser/cache_storage/legacy/legacy_cache_storage_manager.h
+++ b/content/browser/cache_storage/legacy/legacy_cache_storage_manager.h
@@ -15,6 +15,7 @@
 #include "base/memory/memory_pressure_listener.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/sequence_checker.h"
+#include "components/services/storage/public/mojom/cache_storage_control.mojom.h"
 #include "content/browser/cache_storage/cache_storage_context_impl.h"
 #include "content/browser/cache_storage/cache_storage_manager.h"
 #include "content/browser/cache_storage/legacy/legacy_cache_storage.h"
@@ -54,35 +55,37 @@
       LegacyCacheStorageManager* old_manager);
 
   // Map a database identifier (computed from an origin) to the path.
-  static base::FilePath ConstructOriginPath(const base::FilePath& root_path,
-                                            const url::Origin& origin,
-                                            CacheStorageOwner owner);
+  static base::FilePath ConstructOriginPath(
+      const base::FilePath& root_path,
+      const url::Origin& origin,
+      storage::mojom::CacheStorageOwner owner);
 
   // Open the CacheStorage for the given origin and owner.  A reference counting
   // handle is returned which can be stored and used similar to a weak pointer.
-  CacheStorageHandle OpenCacheStorage(const url::Origin& origin,
-                                      CacheStorageOwner owner) override;
+  CacheStorageHandle OpenCacheStorage(
+      const url::Origin& origin,
+      storage::mojom::CacheStorageOwner owner) override;
 
   void GetAllOriginsUsage(
-      CacheStorageOwner owner,
+      storage::mojom::CacheStorageOwner owner,
       CacheStorageContext::GetUsageInfoCallback callback) override;
   void GetOriginUsage(
       const url::Origin& origin_url,
-      CacheStorageOwner owner,
+      storage::mojom::CacheStorageOwner owner,
       storage::QuotaClient::GetOriginUsageCallback callback) override;
   void GetOrigins(
-      CacheStorageOwner owner,
+      storage::mojom::CacheStorageOwner owner,
       storage::QuotaClient::GetOriginsForTypeCallback callback) override;
   void GetOriginsForHost(
       const std::string& host,
-      CacheStorageOwner owner,
+      storage::mojom::CacheStorageOwner owner,
       storage::QuotaClient::GetOriginsForHostCallback callback) override;
   void DeleteOriginData(
       const url::Origin& origin,
-      CacheStorageOwner owner,
+      storage::mojom::CacheStorageOwner owner,
       storage::QuotaClient::DeleteOriginDataCallback callback) override;
   void DeleteOriginData(const url::Origin& origin,
-                        CacheStorageOwner owner) override;
+                        storage::mojom::CacheStorageOwner owner) override;
 
   void SetBlobParametersForCache(
       scoped_refptr<BlobStorageContextWrapper> blob_storage_context) override;
@@ -97,13 +100,13 @@
   // instance is destroyed and its reference count drops to zero.
   void CacheStorageUnreferenced(LegacyCacheStorage* cache_storage,
                                 const url::Origin& origin,
-                                CacheStorageOwner owner);
+                                storage::mojom::CacheStorageOwner owner);
 
  private:
   friend class cache_storage_manager_unittest::CacheStorageManagerTest;
   friend class CacheStorageContextImpl;
 
-  typedef std::map<std::pair<url::Origin, CacheStorageOwner>,
+  typedef std::map<std::pair<url::Origin, storage::mojom::CacheStorageOwner>,
                    std::unique_ptr<LegacyCacheStorage>>
       CacheStorageMap;
 
@@ -122,7 +125,7 @@
 
   void DeleteOriginDidClose(
       const url::Origin& origin,
-      CacheStorageOwner owner,
+      storage::mojom::CacheStorageOwner owner,
       storage::QuotaClient::DeleteOriginDataCallback callback,
       std::unique_ptr<LegacyCacheStorage> cache_storage,
       int64_t origin_size);
diff --git a/content/browser/child_process_security_policy_impl.cc b/content/browser/child_process_security_policy_impl.cc
index c9f95a6..d403f38 100644
--- a/content/browser/child_process_security_policy_impl.cc
+++ b/content/browser/child_process_security_policy_impl.cc
@@ -1286,20 +1286,20 @@
 
   for (const network::DataElement& element : *body->elements()) {
     switch (element.type()) {
-      case network::mojom::DataElementType::kFile:
-        if (!CanReadFile(child_id, element.path()))
+      case network::DataElement::Tag::kFile:
+        if (!CanReadFile(child_id,
+                         element.As<network::DataElementFile>().path()))
           return false;
         break;
 
-      case network::mojom::DataElementType::kBytes:
+      case network::DataElement::Tag::kBytes:
         // Data is self-contained within |body| - no need to check access.
         break;
 
-      case network::mojom::DataElementType::kDataPipe:
+      case network::DataElement::Tag::kDataPipe:
         // Data is self-contained within |body| - no need to check access.
         break;
 
-      case network::mojom::DataElementType::kUnknown:
       default:
         // Fail safe - deny access.
         NOTREACHED();
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc
index 2e0dd90..bb92e30 100644
--- a/content/browser/devtools/protocol/network_handler.cc
+++ b/content/browser/devtools/protocol/network_handler.cc
@@ -524,14 +524,15 @@
     return false;
   for (const auto& element : *elements) {
     // TODO(caseq): Also support blobs.
-    if (element.type() != network::mojom::DataElementType::kBytes)
+    if (element.type() != network::DataElement::Tag::kBytes)
       return false;
-    auto bytes = protocol::Binary::fromSpan(
-        reinterpret_cast<const uint8_t*>(element.bytes()), element.length());
+    const std::vector<uint8_t>& bytes =
+        element.As<network::DataElementBytes>().bytes();
     auto data_entry = protocol::Network::PostDataEntry::Create().Build();
-    data_entry->SetBytes(std::move(bytes));
+    data_entry->SetBytes(
+        protocol::Binary::fromSpan(bytes.data(), bytes.size()));
     data_entries->push_back(std::move(data_entry));
-    result->append(element.bytes(), element.length());
+    result->append(reinterpret_cast<const char*>(bytes.data()), bytes.size());
   }
   return true;
 }
diff --git a/content/browser/direct_sockets/direct_sockets_browsertest.cc b/content/browser/direct_sockets/direct_sockets_browsertest.cc
index 074e0f9..f982e596 100644
--- a/content/browser/direct_sockets/direct_sockets_browsertest.cc
+++ b/content/browser/direct_sockets/direct_sockets_browsertest.cc
@@ -59,58 +59,40 @@
 class MockHostResolver : public network::mojom::HostResolver {
  public:
   explicit MockHostResolver(
-      mojo::PendingReceiver<network::mojom::HostResolver> resolver_receiver)
-      : receiver_(this) {
+      mojo::PendingReceiver<network::mojom::HostResolver> resolver_receiver,
+      net::HostResolver* internal_resolver)
+      : receiver_(this), internal_resolver_(internal_resolver) {
     receiver_.Bind(std::move(resolver_receiver));
   }
 
   MockHostResolver(const MockHostResolver&) = delete;
   MockHostResolver& operator=(const MockHostResolver&) = delete;
 
-  static std::map<std::string, std::string>& known_hosts() {
-    static base::NoDestructor<std::map<std::string, std::string>> hosts;
-    return *hosts;
-  }
-
-  void ResolveHost(const ::net::HostPortPair& host_port_pair,
+  void ResolveHost(const ::net::HostPortPair& host,
                    const ::net::NetworkIsolationKey& network_isolation_key,
                    network::mojom::ResolveHostParametersPtr optional_parameters,
                    ::mojo::PendingRemote<network::mojom::ResolveHostClient>
                        pending_response_client) override {
+    DCHECK(!internal_request_);
+    DCHECK(!response_client_.is_bound());
+
+    internal_request_ = internal_resolver_->CreateRequest(
+        host, network_isolation_key,
+        net::NetLogWithSource::Make(net::NetLog::Get(),
+                                    net::NetLogSourceType::NONE),
+        base::nullopt);
     mojo::Remote<network::mojom::ResolveHostClient> response_client(
         std::move(pending_response_client));
 
-    std::string host = host_port_pair.host();
-    auto iter = known_hosts().find(host);
-    if (iter != known_hosts().end())
-      host = iter->second;
-
-    net::IPAddress remote_address;
-    // TODO(crbug.com/1141241): Replace if/else with AssignFromIPLiteral.
-    if (host.find(':') != std::string::npos) {
-      // GURL expects IPv6 hostnames to be surrounded with brackets.
-      std::string host_brackets = base::StrCat({"[", host, "]"});
-      url::Component host_comp(0, host_brackets.size());
-      std::array<uint8_t, 16> bytes;
-      EXPECT_TRUE(url::IPv6AddressToNumber(host_brackets.data(), host_comp,
-                                           bytes.data()));
-      remote_address = net::IPAddress(bytes.data(), bytes.size());
-    } else {
-      // Otherwise the string is an IPv4 address.
-      url::Component host_comp(0, host.size());
-      std::array<uint8_t, 4> bytes;
-      int num_components;
-      url::CanonHostInfo::Family family = url::IPv4AddressToNumber(
-          host.data(), host_comp, bytes.data(), &num_components);
-      EXPECT_EQ(family, url::CanonHostInfo::IPV4);
-      EXPECT_EQ(num_components, 4);
-      remote_address = net::IPAddress(bytes.data(), bytes.size());
+    int rv = internal_request_->Start(
+        base::BindOnce(&MockHostResolver::OnComplete, base::Unretained(this)));
+    if (rv != net::ERR_IO_PENDING) {
+      response_client->OnComplete(rv, internal_request_->GetResolveErrorInfo(),
+                                  internal_request_->GetAddressResults());
+      return;
     }
-    EXPECT_EQ(remote_address.ToString(), host);
 
-    response_client->OnComplete(net::OK, net::ResolveErrorInfo(),
-                                net::AddressList::CreateFromIPAddress(
-                                    remote_address, host_port_pair.port()));
+    response_client_ = std::move(response_client);
   }
 
   void MdnsListen(
@@ -122,7 +104,20 @@
   }
 
  private:
+  void OnComplete(int error) {
+    DCHECK(response_client_.is_bound());
+    DCHECK(internal_request_);
+
+    response_client_->OnComplete(error,
+                                 internal_request_->GetResolveErrorInfo(),
+                                 internal_request_->GetAddressResults());
+    response_client_.reset();
+  }
+
+  std::unique_ptr<net::HostResolver::ResolveHostRequest> internal_request_;
+  mojo::Remote<network::mojom::ResolveHostClient> response_client_;
   mojo::Receiver<network::mojom::HostResolver> receiver_;
+  net::HostResolver* const internal_resolver_;
 };
 
 class MockNetworkContext : public network::TestNetworkContext {
@@ -163,13 +158,29 @@
       const base::Optional<net::DnsConfigOverrides>& config_overrides,
       mojo::PendingReceiver<network::mojom::HostResolver> receiver) override {
     DCHECK(!config_overrides.has_value());
+    DCHECK(!internal_resolver_);
     DCHECK(!host_resolver_);
-    host_resolver_ = std::make_unique<MockHostResolver>(std::move(receiver));
+
+    internal_resolver_ = net::HostResolver::CreateStandaloneResolver(
+        net::NetLog::Get(), /*options=*/base::nullopt, host_mapping_rules_,
+        /*enable_caching=*/false);
+    host_resolver_ = std::make_unique<MockHostResolver>(
+        std::move(receiver), internal_resolver_.get());
+  }
+
+  // If set to non-empty, the mapping rules will be applied to requests to the
+  // created internal host resolver. See MappedHostResolver for details. Should
+  // be called before CreateHostResolver().
+  void set_host_mapping_rules(std::string host_mapping_rules) {
+    DCHECK(!internal_resolver_);
+    host_mapping_rules_ = std::move(host_mapping_rules);
   }
 
  private:
   const net::Error result_;
   std::vector<RecordedCall> history_;
+  std::string host_mapping_rules_;
+  std::unique_ptr<net::HostResolver> internal_resolver_;
   std::unique_ptr<network::mojom::HostResolver> host_resolver_;
 };
 
@@ -287,9 +298,11 @@
 
   const char kExampleHostname[] = "mail.example.com";
   const char kExampleAddress[] = "98.76.54.32";
-  MockHostResolver::known_hosts()[kExampleHostname] = kExampleAddress;
+  const std::string mapping_rules =
+      base::StringPrintf("MAP %s %s", kExampleHostname, kExampleAddress);
 
   MockNetworkContext mock_network_context(net::OK);
+  mock_network_context.set_host_mapping_rules(mapping_rules);
   DirectSocketsServiceImpl::SetNetworkContextForTesting(&mock_network_context);
   const std::string expected_result = base::StringPrintf(
       "openTcp succeeded: {remoteAddress: \"%s\", remotePort: 993}",
diff --git a/content/browser/direct_sockets/direct_sockets_service_impl.cc b/content/browser/direct_sockets/direct_sockets_service_impl.cc
index b1176ab..5ef284b 100644
--- a/content/browser/direct_sockets/direct_sockets_service_impl.cc
+++ b/content/browser/direct_sockets/direct_sockets_service_impl.cc
@@ -53,7 +53,6 @@
   return local_addr;
 }
 
-// True if |hostname| ends with either ".local" or ".local.".
 bool ResemblesMulticastDNSName(const std::string& hostname) {
   return base::EndsWith(hostname, ".local") ||
          base::EndsWith(hostname, ".local.");
diff --git a/content/browser/media/session/media_session_browsertest.cc b/content/browser/media/session/media_session_browsertest.cc
index b016a97..7cbada9 100644
--- a/content/browser/media/session/media_session_browsertest.cc
+++ b/content/browser/media/session/media_session_browsertest.cc
@@ -249,7 +249,8 @@
 
 // Flaky on Linux and Android and Mac. http://crbug.com/1157239,
 // http://crbug.com/1157319
-#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_MAC)
+#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_MAC) || \
+    defined(OS_CHROMEOS)
 #define MAYBE_SimplePlayPause DISABLED_SimplePlayPause
 #else
 #define MAYBE_SimplePlayPause SimplePlayPause
diff --git a/content/browser/prerender/prerender_browsertest.cc b/content/browser/prerender/prerender_browsertest.cc
index 2ae486f..b526b33 100644
--- a/content/browser/prerender/prerender_browsertest.cc
+++ b/content/browser/prerender/prerender_browsertest.cc
@@ -8,6 +8,7 @@
 #include "base/thread_annotations.h"
 #include "content/browser/prerender/prerender_host.h"
 #include "content/browser/prerender/prerender_host_registry.h"
+#include "content/browser/renderer_host/frame_tree_node.h"
 #include "content/browser/renderer_host/render_frame_host_impl.h"
 #include "content/browser/storage_partition_impl.h"
 #include "content/public/browser/browser_context.h"
@@ -133,6 +134,49 @@
 
   bool IsActivationDisabled() const { return GetParam(); }
 
+  void TestRenderFrameHostPrerenderingState(const GURL& prerender_url) {
+    const GURL kInitialUrl = GetUrl("/prerender/add_prerender.html");
+
+    // Navigate to an initial page.
+    ASSERT_TRUE(NavigateToURL(shell(), kInitialUrl));
+
+    // The initial page should not be for prerendering.
+    RenderFrameHostImpl* initiator_render_frame_host =
+        static_cast<RenderFrameHostImpl*>(
+            shell()->web_contents()->GetMainFrame());
+    EXPECT_FALSE(initiator_render_frame_host->IsPrerendering());
+    // Start a prerender.
+    AddPrerender(prerender_url);
+    PrerenderHostRegistry& registry = GetPrerenderHostRegistry();
+    PrerenderHost* prerender_host =
+        registry.FindHostByUrlForTesting(prerender_url);
+
+    // Verify all RenderFrameHostImpl in the prerendered page know the
+    // prerendering state.
+    RenderFrameHostImpl* prerendered_render_frame_host =
+        prerender_host->GetPrerenderedMainFrameHostForTesting();
+    std::vector<RenderFrameHost*> frames =
+        prerendered_render_frame_host->GetFramesInSubtree();
+    for (auto* frame : frames) {
+      auto* rfhi = static_cast<RenderFrameHostImpl*>(frame);
+      EXPECT_TRUE(rfhi->IsPrerendering());
+    }
+
+    // Activate the prerendered page.
+    NavigateWithLocation(prerender_url);
+
+    // The activated page should no longer be in the prerendering state.
+    RenderFrameHostImpl* navigated_render_frame_host =
+        static_cast<RenderFrameHostImpl*>(
+            shell()->web_contents()->GetMainFrame());
+    // The new page shouldn't be in the prerendering state.
+    frames = navigated_render_frame_host->GetFramesInSubtree();
+    for (auto* frame : frames) {
+      auto* rfhi = static_cast<RenderFrameHostImpl*>(frame);
+      EXPECT_FALSE(rfhi->IsPrerendering());
+    }
+  }
+
  private:
   net::test_server::EmbeddedTestServer ssl_server_{
       net::test_server::EmbeddedTestServer::TYPE_HTTPS};
@@ -274,56 +318,6 @@
   }
 }
 
-IN_PROC_BROWSER_TEST_P(PrerenderBrowserTest, InformedRenderFrameHost) {
-  const GURL kInitialUrl = GetUrl("/prerender/add_prerender.html");
-  const GURL kPrerenderingUrl = GetUrl("/empty.html");
-
-  // Navigate to an initial page.
-  ASSERT_TRUE(NavigateToURL(shell(), kInitialUrl));
-  ASSERT_EQ(shell()->web_contents()->GetURL(), kInitialUrl);
-
-  // The initial page should not be for prerendering.
-  RenderFrameHostImpl* initiator_render_frame_host =
-      static_cast<RenderFrameHostImpl*>(
-          shell()->web_contents()->GetMainFrame());
-  EXPECT_FALSE(initiator_render_frame_host->IsPrerendering());
-
-  // Add <link rel=prerender> that will prerender `kPrerenderingUrl`.
-  ASSERT_EQ(GetRequestCount(kPrerenderingUrl), 0);
-  AddPrerender(kPrerenderingUrl);
-  EXPECT_EQ(GetRequestCount(kPrerenderingUrl), 1);
-
-  // A prerender host for the URL should be registered.
-  PrerenderHostRegistry& registry = GetPrerenderHostRegistry();
-  PrerenderHost* prerender_host =
-      registry.FindHostByUrlForTesting(kPrerenderingUrl);
-  EXPECT_NE(prerender_host, nullptr);
-
-  // Verify the corresponding RenderFrameHostImpl knows the prerendering state.
-  RenderFrameHostImpl* prerendered_render_frame_host =
-      prerender_host->GetPrerenderedMainFrameHostForTesting();
-  EXPECT_TRUE(prerendered_render_frame_host->IsPrerendering());
-
-  // Activate the prerendered page.
-  NavigateWithLocation(kPrerenderingUrl);
-  if (IsActivationDisabled()) {
-    // Activation is disabled, so the page should newly be rendered instead
-    // of the prerendered page.
-    RenderFrameHostImpl* new_render_frame_host =
-        static_cast<RenderFrameHostImpl*>(
-            shell()->web_contents()->GetMainFrame());
-    EXPECT_NE(prerendered_render_frame_host, new_render_frame_host);
-    // The new page shouldn't be in the prerendering state.
-    EXPECT_FALSE(new_render_frame_host->IsPrerendering());
-  } else {
-    // The prerendered page is activated. The page should no longer be in
-    // the prerendering state.
-    ASSERT_EQ(prerendered_render_frame_host,
-              shell()->web_contents()->GetMainFrame());
-    EXPECT_FALSE(prerendered_render_frame_host->IsPrerendering());
-  }
-}
-
 // Makes sure that activations on navigations for iframes don't happen.
 IN_PROC_BROWSER_TEST_P(PrerenderBrowserTest, Activation_iFrame) {
   const GURL kInitialUrl = GetUrl("/prerender/add_prerender.html");
@@ -410,6 +404,18 @@
   EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), kInitialUrl);
 }
 
+// Tests that all RenderFrameHostImpls in the prerendering page know the
+// prerendering state.
+IN_PROC_BROWSER_TEST_P(PrerenderBrowserTest, PrerenderIframe) {
+  TestRenderFrameHostPrerenderingState(GetUrl("/page_with_iframe.html"));
+}
+
+// Blank <iframe> is a special case. Tests that the blank iframe knows the
+// prerendering state as well.
+IN_PROC_BROWSER_TEST_P(PrerenderBrowserTest, PrerenderBlankIframe) {
+  TestRenderFrameHostPrerenderingState(GetUrl("/page_with_blank_iframe.html"));
+}
+
 // TODO(https://crbug.com/1132746): Test canceling prerendering.
 
 // TODO(https://crbug.com/1132746): Test prerendering for 404 page, redirection,
diff --git a/content/browser/renderer_host/code_cache_host_impl.cc b/content/browser/renderer_host/code_cache_host_impl.cc
index 8f73fd3..285c870 100644
--- a/content/browser/renderer_host/code_cache_host_impl.cc
+++ b/content/browser/renderer_host/code_cache_host_impl.cc
@@ -11,6 +11,7 @@
 #include "base/task/post_task.h"
 #include "base/threading/thread.h"
 #include "build/build_config.h"
+#include "components/services/storage/public/mojom/cache_storage_control.mojom.h"
 #include "content/browser/cache_storage/cache_storage_context_impl.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/code_cache/generated_code_cache.h"
@@ -210,7 +211,8 @@
   // storage::mojom::CacheStorageControl remote, similar to IndexedDBControl.
   cache_storage_context_->AddReceiver(
       cross_origin_embedder_policy, mojo::NullRemote(), cache_storage_origin,
-      CacheStorageOwner::kCacheAPI, remote.BindNewPipeAndPassReceiver());
+      storage::mojom::CacheStorageOwner::kCacheAPI,
+      remote.BindNewPipeAndPassReceiver());
 
   // Call the remote pointer directly so we can pass the remote to the callback
   // itself to preserve its lifetime.
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index c47bf32..302fbaa 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -766,6 +766,12 @@
     }
   }
 
+  // The prerendering state of a sub-frame is decided by its parent.
+  if (base::FeatureList::IsEnabled(blink::features::kPrerender2) &&
+      frame_tree_node->parent()) {
+    is_prerendering = frame_tree_node->parent()->IsPrerendering();
+  }
+
   std::unique_ptr<NavigationRequest> navigation_request(new NavigationRequest(
       frame_tree_node, std::move(common_params), std::move(navigation_params),
       std::move(commit_params), browser_initiated,
@@ -880,6 +886,13 @@
   int initiator_process_id =
       frame_tree_node->current_frame_host()->GetProcess()->GetID();
 
+  // For sub-frame navigations, inherit the prerendering state from the parent.
+  bool is_prerendering = false;
+  if (base::FeatureList::IsEnabled(blink::features::kPrerender2) &&
+      frame_tree_node->parent()) {
+    is_prerendering = frame_tree_node->parent()->IsPrerendering();
+  }
+
   // `was_opener_suppressed` can be true for renderer initiated navigations, but
   // only in cases which get routed through `CreateBrowserInitiated()` instead.
   std::unique_ptr<NavigationRequest> navigation_request(new NavigationRequest(
@@ -888,8 +901,9 @@
       false,  // browser_initiated
       true,   // from_begin_navigation
       false,  // is_for_commit
-      false,  // is_prerendering
-      nullptr, entry,
+      is_prerendering,
+      nullptr,  // frame_entry
+      entry,
       nullptr,  // navigation_ui_data
       std::move(navigation_client), std::move(navigation_initiator),
       nullptr,  // rfh_restored_from_back_forward_cache
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 4b68268..c634bac 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -7812,6 +7812,9 @@
   DCHECK(is_prerendering_);
   is_prerendering_ = false;
 
+  for (auto& child : children_)
+    child->current_frame_host()->OnPrerenderedPageActivated();
+
   // TODO(https://crbug.com/1132752): Inform `broker_` that the prerendered
   // frame is activated.
 }
@@ -8781,6 +8784,14 @@
     // create one in order to properly issue DidFinishNavigation calls to
     // WebContentsObservers.
     DCHECK(is_initial_empty_commit || is_same_document_navigation);
+
+    // Handle src-less <iframe> for prerendering.
+    // This is a special case that does not go through CommitNavigation path.
+    if (base::FeatureList::IsEnabled(blink::features::kPrerender2) &&
+        is_initial_empty_commit && !is_main_frame()) {
+      is_prerendering_ = parent_->IsPrerendering();
+    }
+
     // TODO(https://crbug.com/1131832): Do not use |params| to get the values,
     // depend on values known at commit time instead.
     navigation_request = CreateNavigationRequestForCommit(
@@ -10387,6 +10398,13 @@
   return document_used_web_otp_;
 }
 
+void RenderFrameHostImpl::SetPolicyContainerForEarlyCommitAfterCrash(
+    std::unique_ptr<PolicyContainerHost> policy_container_host) {
+  DCHECK_EQ(lifecycle_state_, LifecycleState::kSpeculative);
+  DCHECK(!policy_container_host_);
+  policy_container_host_ = std::move(policy_container_host);
+}
+
 std::ostream& operator<<(std::ostream& o,
                          const RenderFrameHostImpl::LifecycleState& s) {
   return o << LifecycleStateToString(s);
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h
index ad68264..484de79 100644
--- a/content/browser/renderer_host/render_frame_host_impl.h
+++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -1547,6 +1547,14 @@
     return policy_container_host_.get();
   }
 
+  // This is used by RenderFrameHostManager to ensure the replacement
+  // RenderFrameHost is properly initialized when performing an early commit
+  // as a recovery for a crashed frame.
+  // TODO(https://crbug.com/1072817): Remove this logic when removing the
+  // early commit.
+  void SetPolicyContainerForEarlyCommitAfterCrash(
+      std::unique_ptr<PolicyContainerHost> policy_container_host);
+
   // This function mimics DidCommitProvisionalLoad for navigations served from
   // the back-forward cache.
   void DidCommitBackForwardCacheNavigation(
diff --git a/content/browser/renderer_host/render_frame_host_manager.cc b/content/browser/renderer_host/render_frame_host_manager.cc
index d1446d9..8c5937f 100644
--- a/content/browser/renderer_host/render_frame_host_manager.cc
+++ b/content/browser/renderer_host/render_frame_host_manager.cc
@@ -905,6 +905,20 @@
       if (GetRenderFrameProxyHost(dest_site_instance.get()))
         navigation_rfh->SwapIn();
       navigation_rfh->OnCommittedSpeculativeBeforeNavigationCommit();
+
+      // An Active RenderFrameHost MUST always have a PolicyContainerHost. A new
+      // document is either:
+      // - The initial empty document, via frame creation.
+      // - A new document replacing the previous one, via a navigation.
+      // Here this is an additional case: A new document (in a weird state) is
+      // replacing the one crashed. In this case, it is not entirely clear what
+      // PolicyContainerHost should be used. In the absence of anything better,
+      // we simply keep the PolicyContainerHost that was previously active.
+      // TODO(https://crbug.com/1072817): Remove this logic when removing the
+      // early commit.
+      navigation_rfh->SetPolicyContainerForEarlyCommitAfterCrash(
+          current_frame_host()->policy_container_host()->Clone());
+
       CommitPending(std::move(speculative_render_frame_host_), nullptr,
                     request->coop_status().require_browsing_instance_swap());
     }
@@ -2086,7 +2100,8 @@
     }
   }
 
-  // BrowsingInstance unless the destination URL's cross-origin isolated state
+  // Start the new renderer in a new SiteInstance, but in the current
+  // BrowsingInstance, unless the destination URL's cross-origin isolated state
   // cannot be hosted by it.
   if (IsSiteInstanceCompatibleWithCoopCoepCrossOriginIsolation(
           render_frame_host_->GetSiteInstance(),
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 69c62ce..6eb6699b 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -74,6 +74,7 @@
 #include "components/discardable_memory/public/mojom/discardable_shared_memory_manager.mojom.h"
 #include "components/discardable_memory/service/discardable_shared_memory_manager.h"
 #include "components/metrics/single_sample_metrics.h"
+#include "components/services/storage/public/mojom/cache_storage_control.mojom.h"
 #include "components/tracing/common/tracing_switches.h"
 #include "components/viz/common/switches.h"
 #include "components/viz/host/gpu_client.h"
@@ -1949,7 +1950,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   storage_partition_impl_->GetCacheStorageContext()->AddReceiver(
       cross_origin_embedder_policy, std::move(coep_reporter_remote), origin,
-      CacheStorageOwner::kCacheAPI, std::move(receiver));
+      storage::mojom::CacheStorageOwner::kCacheAPI, std::move(receiver));
 }
 
 void RenderProcessHostImpl::BindIndexedDB(
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc
index 56bff13..7ca9019 100644
--- a/content/browser/service_worker/service_worker_browsertest.cc
+++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -30,6 +30,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
+#include "components/services/storage/public/mojom/cache_storage_control.mojom.h"
 #include "content/browser/cache_storage/cache_storage.h"
 #include "content/browser/cache_storage/cache_storage_cache.h"
 #include "content/browser/cache_storage/cache_storage_cache_handle.h"
@@ -2152,7 +2153,8 @@
   void OpenCacheOnCoreThread(int* result, base::OnceClosure continuation) {
     CacheStorageHandle cache_storage =
         cache_storage_context_->CacheManager()->OpenCacheStorage(
-            url::Origin::Create(origin_), CacheStorageOwner::kCacheAPI);
+            url::Origin::Create(origin_),
+            storage::mojom::CacheStorageOwner::kCacheAPI);
     cache_storage.value()->OpenCache(
         cache_name_, /* trace_id = */ 0,
         base::BindOnce(&self::OnCacheStorageOpenCallback, this, result,
diff --git a/content/browser/service_worker/service_worker_main_resource_loader_unittest.cc b/content/browser/service_worker/service_worker_main_resource_loader_unittest.cc
index 73db1d8e..772afca 100644
--- a/content/browser/service_worker/service_worker_main_resource_loader_unittest.cc
+++ b/content/browser/service_worker/service_worker_main_resource_loader_unittest.cc
@@ -197,8 +197,9 @@
     // So far this test expects a single bytes element.
     ASSERT_EQ(1u, elements->size());
     const network::DataElement& element = elements->front();
-    ASSERT_EQ(network::mojom::DataElementType::kBytes, element.type());
-    *out_string = std::string(element.bytes(), element.length());
+    ASSERT_EQ(network::DataElement::Tag::kBytes, element.type());
+    *out_string =
+        std::string(element.As<network::DataElementBytes>().AsStringPiece());
   }
 
   void RunUntilFetchEvent() {
diff --git a/content/browser/speech/speech_recognition_engine_unittest.cc b/content/browser/speech/speech_recognition_engine_unittest.cc
index 4515d1a..9578482 100644
--- a/content/browser/speech/speech_recognition_engine_unittest.cc
+++ b/content/browser/speech/speech_recognition_engine_unittest.cc
@@ -709,15 +709,15 @@
       EXPECT_TRUE(upstream_request);
       EXPECT_TRUE(upstream_request->request.request_body);
       EXPECT_EQ(1u, upstream_request->request.request_body->elements()->size());
-      EXPECT_EQ(
-          network::mojom::DataElementType::kChunkedDataPipe,
-          (*upstream_request->request.request_body->elements())[0].type());
-      network::TestURLLoaderFactory::PendingRequest* mutable_upstream_request =
-          const_cast<network::TestURLLoaderFactory::PendingRequest*>(
-              upstream_request);
-      chunked_data_pipe_getter_.Bind((*mutable_upstream_request->request
-                                           .request_body->elements_mutable())[0]
-                                         .ReleaseChunkedDataPipeGetter());
+      auto& element =
+          (*upstream_request->request.request_body->elements_mutable())[0];
+      if (element.type() != network::DataElement::Tag::kChunkedDataPipe) {
+        ADD_FAILURE() << "element type mismatch";
+        return "";
+      }
+      chunked_data_pipe_getter_.Bind(
+          element.As<network::DataElementChunkedDataPipe>()
+              .ReleaseChunkedDataPipeGetter());
     }
     mojo::DataPipe data_pipe;
     chunked_data_pipe_getter_->StartReading(
diff --git a/content/browser/speech/speech_recognizer_impl_unittest.cc b/content/browser/speech/speech_recognizer_impl_unittest.cc
index 27700e9..c31e3ff 100644
--- a/content/browser/speech/speech_recognizer_impl_unittest.cc
+++ b/content/browser/speech/speech_recognizer_impl_unittest.cc
@@ -433,15 +433,12 @@
       ASSERT_TRUE(GetUpstreamRequest(&upstream_request));
       ASSERT_TRUE(upstream_request->request.request_body);
       ASSERT_EQ(1u, upstream_request->request.request_body->elements()->size());
-      ASSERT_EQ(
-          network::mojom::DataElementType::kChunkedDataPipe,
-          (*upstream_request->request.request_body->elements())[0].type());
-      network::TestURLLoaderFactory::PendingRequest* mutable_upstream_request =
-          const_cast<network::TestURLLoaderFactory::PendingRequest*>(
-              upstream_request);
-      chunked_data_pipe_getter.Bind((*mutable_upstream_request->request
-                                          .request_body->elements_mutable())[0]
-                                        .ReleaseChunkedDataPipeGetter());
+      auto& element =
+          (*upstream_request->request.request_body->elements_mutable())[0];
+      ASSERT_EQ(network::DataElement::Tag::kChunkedDataPipe, element.type());
+      chunked_data_pipe_getter.Bind(
+          element.As<network::DataElementChunkedDataPipe>()
+              .ReleaseChunkedDataPipeGetter());
       chunked_data_pipe_getter->StartReading(
           std::move(data_pipe.producer_handle));
     }
diff --git a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
index 6bb8191..3b8c008 100644
--- a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
+++ b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
@@ -204,13 +204,14 @@
     // So far this test expects a single element (bytes or data pipe).
     ASSERT_EQ(1u, elements->size());
     network::DataElement& element = elements->front();
-    if (element.type() == network::mojom::DataElementType::kBytes) {
-      *out_string = std::string(element.bytes(), element.length());
-    } else if (element.type() == network::mojom::DataElementType::kDataPipe) {
+    if (element.type() == network::DataElement::Tag::kBytes) {
+      *out_string =
+          std::string(element.As<network::DataElementBytes>().AsStringPiece());
+    } else if (element.type() == network::DataElement::Tag::kDataPipe) {
       // Read the content into |data_pipe|.
       mojo::DataPipe data_pipe;
       mojo::Remote<network::mojom::DataPipeGetter> remote(
-          element.ReleaseDataPipeGetter());
+          element.As<network::DataElementDataPipe>().ReleaseDataPipeGetter());
       base::RunLoop run_loop;
       remote->Read(
           std::move(data_pipe.producer_handle),
diff --git a/content/test/gpu/gpu_tests/gpu_helper.py b/content/test/gpu/gpu_tests/gpu_helper.py
index 16621aad..ce9c9d5 100644
--- a/content/test/gpu/gpu_tests/gpu_helper.py
+++ b/content/test/gpu/gpu_tests/gpu_helper.py
@@ -142,14 +142,17 @@
   retval = 'skia-renderer-disabled'
   skia_renderer_enabled = (
       gpu_feature_status
-      and gpu_feature_status.get('skia_renderer') == 'enabled_on')
+      and gpu_feature_status.get('skia_renderer') == 'enabled_on'
+      and gpu_feature_status.get('gpu_compositing') == 'enabled')
   if skia_renderer_enabled:
     if HasDawnSkiaRenderer(extra_browser_args):
       retval = 'skia-renderer-dawn'
-    elif HasGlSkiaRenderer(extra_browser_args):
-      retval = 'skia-renderer-gl'
     elif HasVulkanSkiaRenderer(gpu_feature_status):
       retval = 'skia-renderer-vulkan'
+    # The check for GL must come after Vulkan since the 'opengl' feature can be
+    # enabled for WebGL and interop even if SkiaRenderer is using Vulkan.
+    elif HasGlSkiaRenderer(gpu_feature_status):
+      retval = 'skia-renderer-gl'
   return retval
 
 
@@ -162,12 +165,8 @@
   return False
 
 
-def HasGlSkiaRenderer(extra_browser_args):
-  if extra_browser_args:
-    for arg in extra_browser_args:
-      if '--use-gl=' in arg:
-        return True
-  return False
+def HasGlSkiaRenderer(gpu_feature_status):
+  return gpu_feature_status and gpu_feature_status.get('opengl') == 'enabled_on'
 
 
 def HasVulkanSkiaRenderer(gpu_feature_status):
diff --git a/docs/workflow/debugging-with-swarming.md b/docs/workflow/debugging-with-swarming.md
index ace0bb8..b0845a7 100644
--- a/docs/workflow/debugging-with-swarming.md
+++ b/docs/workflow/debugging-with-swarming.md
@@ -16,7 +16,7 @@
 An *isolate* is an archive containing all the files needed to do a specific task
 on the swarming infrastructure. It contains binaries as well as any libraries
 they link against or support data. An isolate can be thought of like a tarball,
-but held by the "isolate server" and identified by a hash of its contents. The
+but held by the CAS server and identified by a digest of its contents. The
 isolate also includes the command(s) to run, which is why the command is
 specified when building the isolate, not when executing it.
 
@@ -50,7 +50,7 @@
 or perhaps:
 
 ```
-  isolate = upload_to_isolate_server(target_you_built_locally)
+  isolate = upload_to_cas(target_you_built_locally)
   use_swarming_to_run(type, isolate)
 ```
 
@@ -167,19 +167,21 @@
 
 ## Uploading an isolate
 
-You can then upload the resulting isolate to the isolate server:
+You can then upload the resulting isolate to the CAS server:
 
 ```
 $ tools/luci-go/isolate archive \
-      -I https://isolateserver.appspot.com \
+      -cas-instance chroimum-swarm \
       -i $outdir/$target.isolate \
-      -s $outdir/$target.isolated
+      -dump-json $outdir/$target.archive.json
 ```
 
-The `isolate` tool will emit something like this:
+The archive json looks like this:
 
 ```
-e625130b712096e3908266252c8cd779d7f442f1  unit_tests
+{
+  "unit_tests": "5bee0815d2ddd2b876b49d4cce8aaa23de8a6f9e2dbf134ec409fbdc224e8c64/398"
+}
 ```
 
 Do not ctrl-c it after it does this, even if it seems to be hanging for a
@@ -187,16 +189,15 @@
 
 ## Running an isolate
 
-Now that the isolate is on the isolate server with hash `$hash` from the
+Now that the isolate is on the CAS server with digest `$digest` from the
 previous step, you can run on bots of your choice:
 
 ```
 $ tools/luci-go/swarming trigger \
     -server https://chromium-swarm.appspot.com \
-    -isolate-server https://isolateserver.appspot.com \
     -dimension pool=$pool \
     $criteria \
-    -isolated $hash
+    -digest $digest
 ```
 
 There are two more things you need to fill in here. The first is the pool name;
diff --git a/extensions/browser/api/declarative_net_request/filter_list_converter/converter.cc b/extensions/browser/api/declarative_net_request/filter_list_converter/converter.cc
index 75f3ffcb..656a07cd 100644
--- a/extensions/browser/api/declarative_net_request/filter_list_converter/converter.cc
+++ b/extensions/browser/api/declarative_net_request/filter_list_converter/converter.cc
@@ -407,13 +407,13 @@
     dnr_api::RuleActionType action_type = dnr_api::RULE_ACTION_TYPE_NONE;
 
     CHECK(!is_allow_all_requests_rule_ ||
-          input_rule_.semantics() == proto::RULE_SEMANTICS_WHITELIST);
+          input_rule_.semantics() == proto::RULE_SEMANTICS_ALLOWLIST);
 
     switch (input_rule_.semantics()) {
-      case proto::RULE_SEMANTICS_BLACKLIST:
+      case proto::RULE_SEMANTICS_BLOCKLIST:
         action_type = dnr_api::RULE_ACTION_TYPE_BLOCK;
         break;
-      case proto::RULE_SEMANTICS_WHITELIST:
+      case proto::RULE_SEMANTICS_ALLOWLIST:
         if (is_allow_all_requests_rule_)
           action_type = dnr_api::RULE_ACTION_TYPE_ALLOWALLREQUESTS;
         else
diff --git a/extensions/browser/api/declarative_net_request/flat_ruleset_indexer_unittest.cc b/extensions/browser/api/declarative_net_request/flat_ruleset_indexer_unittest.cc
index aa1deec..c5b38d2 100644
--- a/extensions/browser/api/declarative_net_request/flat_ruleset_indexer_unittest.cc
+++ b/extensions/browser/api/declarative_net_request/flat_ruleset_indexer_unittest.cc
@@ -452,7 +452,7 @@
 
   // Allow rules.
   rules_to_index.push_back(CreateIndexedRule(
-      17, kMinValidPriority, flat_rule::OptionFlag_IS_WHITELIST,
+      17, kMinValidPriority, flat_rule::OptionFlag_IS_ALLOWLIST,
       flat_rule::ElementType_PING | flat_rule::ElementType_SCRIPT,
       flat_rule::ActivationType_NONE, flat_rule::UrlPatternType_SUBSTRING,
       flat_rule::AnchorType_SUBDOMAIN, flat_rule::AnchorType_NONE,
@@ -460,7 +460,7 @@
       dnr_api::RULE_ACTION_TYPE_ALLOW, nullptr, base::nullopt, {}, {}));
   rules_to_index.push_back(CreateIndexedRule(
       16, kMinValidPriority,
-      flat_rule::OptionFlag_IS_WHITELIST |
+      flat_rule::OptionFlag_IS_ALLOWLIST |
           flat_rule::OptionFlag_IS_CASE_INSENSITIVE,
       flat_rule::ElementType_IMAGE, flat_rule::ActivationType_NONE,
       flat_rule::UrlPatternType_SUBSTRING, flat_rule::AnchorType_NONE,
diff --git a/extensions/browser/api/declarative_net_request/indexed_rule.cc b/extensions/browser/api/declarative_net_request/indexed_rule.cc
index aab5a41..10bfa81 100644
--- a/extensions/browser/api/declarative_net_request/indexed_rule.cc
+++ b/extensions/browser/api/declarative_net_request/indexed_rule.cc
@@ -143,7 +143,7 @@
   uint8_t mask = flat_rule::OptionFlag_NONE;
 
   if (parsed_rule.action.type == dnr_api::RULE_ACTION_TYPE_ALLOW)
-    mask |= flat_rule::OptionFlag_IS_WHITELIST;
+    mask |= flat_rule::OptionFlag_IS_ALLOWLIST;
 
   if (!IsCaseSensitive(parsed_rule))
     mask |= flat_rule::OptionFlag_IS_CASE_INSENSITIVE;
diff --git a/extensions/browser/api/declarative_net_request/indexed_rule_unittest.cc b/extensions/browser/api/declarative_net_request/indexed_rule_unittest.cc
index 4aa4b5d..a337d81 100644
--- a/extensions/browser/api/declarative_net_request/indexed_rule_unittest.cc
+++ b/extensions/browser/api/declarative_net_request/indexed_rule_unittest.cc
@@ -142,11 +142,11 @@
            flat_rule::OptionFlag_APPLIES_TO_FIRST_PARTY},
       {dnr_api::DOMAIN_TYPE_FIRSTPARTY, dnr_api::RULE_ACTION_TYPE_ALLOW,
        std::make_unique<bool>(true),
-       flat_rule::OptionFlag_IS_WHITELIST |
+       flat_rule::OptionFlag_IS_ALLOWLIST |
            flat_rule::OptionFlag_APPLIES_TO_FIRST_PARTY},
       {dnr_api::DOMAIN_TYPE_FIRSTPARTY, dnr_api::RULE_ACTION_TYPE_ALLOW,
        std::make_unique<bool>(false),
-       flat_rule::OptionFlag_IS_WHITELIST |
+       flat_rule::OptionFlag_IS_ALLOWLIST |
            flat_rule::OptionFlag_APPLIES_TO_FIRST_PARTY |
            flat_rule::OptionFlag_IS_CASE_INSENSITIVE},
   };
diff --git a/extensions/browser/api/web_request/web_request_info.cc b/extensions/browser/api/web_request/web_request_info.cc
index ad26c0ac..16e08f2 100644
--- a/extensions/browser/api/web_request/web_request_info.cc
+++ b/extensions/browser/api/web_request/web_request_info.cc
@@ -84,20 +84,19 @@
 
   for (auto& element : *request.request_body->elements()) {
     switch (element.type()) {
-      case network::mojom::DataElementType::kDataPipe:
+      case network::DataElement::Tag::kDataPipe:
         // TODO(https://crbug.com/721414): Support data pipe elements.
         break;
 
-      case network::mojom::DataElementType::kBytes:
+      case network::DataElement::Tag::kBytes:
         data_sources->push_back(std::make_unique<BytesUploadDataSource>(
-            base::StringPiece(element.bytes(), element.length())));
+            element.As<network::DataElementBytes>().AsStringPiece()));
         break;
-
-      case network::mojom::DataElementType::kFile:
+      case network::DataElement::Tag::kFile:
         // TODO(https://crbug.com/715679): This may not work when network
         // process is sandboxed.
-        data_sources->push_back(
-            std::make_unique<FileUploadDataSource>(element.path()));
+        data_sources->push_back(std::make_unique<FileUploadDataSource>(
+            element.As<network::DataElementFile>().path()));
         break;
 
       default:
diff --git a/google_apis/gaia/gaia_auth_fetcher_unittest.cc b/google_apis/gaia/gaia_auth_fetcher_unittest.cc
index 90c6033..72481f8f5 100644
--- a/google_apis/gaia/gaia_auth_fetcher_unittest.cc
+++ b/google_apis/gaia/gaia_auth_fetcher_unittest.cc
@@ -55,7 +55,10 @@
     return "";
   }
   const network::DataElement& elem = request->request_body->elements()->at(0);
-  return std::string(elem.bytes(), elem.length());
+  if (elem.type() != network::DataElement::Tag::kBytes) {
+    return "";
+  }
+  return std::string(elem.As<network::DataElementBytes>().AsStringPiece());
 }
 
 }  // namespace
diff --git a/ios/chrome/browser/signin/gaia_auth_fetcher_ios_ns_url_session_bridge.mm b/ios/chrome/browser/signin/gaia_auth_fetcher_ios_ns_url_session_bridge.mm
index 9488459..f12cf2d 100644
--- a/ios/chrome/browser/signin/gaia_auth_fetcher_ios_ns_url_session_bridge.mm
+++ b/ios/chrome/browser/signin/gaia_auth_fetcher_ios_ns_url_session_bridge.mm
@@ -10,7 +10,7 @@
 #include "base/callback_helpers.h"
 #include "base/mac/foundation_util.h"
 #include "base/strings/sys_string_conversions.h"
-#include "components/signin/ios/browser/account_consistency_service.h"
+#include "components/signin/core/browser/chrome_connected_header_helper.h"
 #include "ios/net/cookies/system_cookie_util.h"
 #include "ios/web/public/browser_state.h"
 #import "net/base/mac/url_conversions.h"
@@ -223,7 +223,7 @@
     // properties. Requests initiated from the browser services (e.g.
     // GaiaCookieManagerService) must not include this cookie.
     if (cookie_with_access_result.cookie.Name() ==
-        AccountConsistencyService::kChromeConnectedCookieName) {
+        signin::kChromeConnectedCookieName) {
       continue;
     }
     [http_cookies addObject:net::SystemCookieFromCanonicalCookie(
diff --git a/ios/chrome/browser/ui/authentication/cells/signin_promo_view_configurator.h b/ios/chrome/browser/ui/authentication/cells/signin_promo_view_configurator.h
index 533e79a..8c5f22c 100644
--- a/ios/chrome/browser/ui/authentication/cells/signin_promo_view_configurator.h
+++ b/ios/chrome/browser/ui/authentication/cells/signin_promo_view_configurator.h
@@ -6,6 +6,7 @@
 #define IOS_CHROME_BROWSER_UI_AUTHENTICATION_CELLS_SIGNIN_PROMO_VIEW_CONFIGURATOR_H_
 
 #import <UIKit/UIKit.h>
+#import "ios/chrome/browser/ui/authentication/cells/signin_promo_view_constants.h"
 
 @class SigninPromoView;
 
@@ -14,12 +15,14 @@
 
 - (instancetype)init NS_UNAVAILABLE;
 
-// Initializes the instance. For cold state mode, set all parameters to nil.
-// For warm state mode set at least the |userEmail| to not nil.
-- (instancetype)initWithUserEmail:(NSString*)userEmail
-                     userFullName:(NSString*)userFullName
-                        userImage:(UIImage*)userImage
-                   hasCloseButton:(BOOL