diff --git a/AUTHORS b/AUTHORS
index 42683765..a47907e 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1122,6 +1122,7 @@
 Takaaki Suzuki <takaakisuzuki.14@gmail.com>
 Takahiro Aoyagi <hogehoge@gachapin.jp>
 Takashi Fujita <tgfjt.mail@gmail.com>
+Takashi Mima <tks.m1205@gmail.com>
 Takeshi Kurosawa <taken.spc@gmail.com>
 Tanay Chowdhury <tanay.c@samsung.com>
 Tanvir Rizvi <tanvir.rizvi@samsung.com>
diff --git a/DEPS b/DEPS
index 5500b009f..ca6d4b14 100644
--- a/DEPS
+++ b/DEPS
@@ -245,15 +245,15 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '8af1eebedbfd5da48bb51c91ff99a761f5c2a529',
+  'skia_revision': '0aad22f5686a3a55af266f2ab21479feb00dae80',
   # 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': '9900f9d1643ae83db1e2637d4144107eae664e3c',
+  'v8_revision': 'e5acd25f590121376fd5b1e83081e2ffee87d09a',
   # 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': '2f4f5f8aa447790f417789f2de8ad7f2b311c308',
+  'angle_revision': 'd4412d0a01247291a8357933c9c844cc55cb7490',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -320,7 +320,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': 'ba9ce69bea5495b2f948a1de8a56c59af2707310',
+  'devtools_frontend_revision': 'ea3f685d39b2173e3287dd81d4bcfeee69658c6b',
   # 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.
@@ -356,11 +356,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'shaderc_revision': '4864297864494780c4424c625e1d987e9321ba00',
+  'shaderc_revision': 'e72186b66bb90ed06aaf15cbdc9a053581a0616b',
   # 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': 'fc2666486e0bba38114554059f9b4561c5b0c533',
+  'dawn_revision': 'a78192741e2300007799b1644783b13c9aaca708',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -404,7 +404,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.
-  'libcxxabi_revision':    '8829496cf6362cc08e1b3008e1769e6fb595fb9d',
+  'libcxxabi_revision':    '0c34f74b2c847a36c4e38894212f9eeff776e597',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -805,7 +805,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'kbDXkyz0Cat6aywgnFl4onZ4E8LXiWFZPcSwBSi4ip4C',
+          'version': 'bebl7HT6pBH_Y5G5q4holx3hZg80BJB9yRxLViJOONEC',
       },
     ],
     'condition': 'checkout_android',
@@ -1044,7 +1044,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '9fa0cb7230db34d3df4434523e5352b35bde7136',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '42afe9a2d34e88a5dbad922f493a3d81726a5221',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1184,7 +1184,7 @@
     Var('chromium_git') + '/chromium/deps/hunspell_dictionaries.git' + '@' + '18e09b9197a3b1d771c077c530d1a4ebad04c167',
 
   'src/third_party/icu':
-    Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'fbc6faf1c2c429cd27fabe615a89f0b217aa4213',
+    Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'b9f6d0a5c5375dc4643f35360d257dba37c1d3e1',
 
   'src/third_party/icu4j': {
       'packages': [
@@ -1648,7 +1648,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'fca7b339442bd70c5dc49bb33ee7f9466b560a97',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '5e05369cb27b1cff06b1ce4aaf50e2e47f3a15d0',
+    Var('webrtc_git') + '/src.git' + '@' + '4be9da34f464f5f2ba6094a478919b6cd64b91b0',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1718,7 +1718,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@7a22308b4e30fbedfe67de0a3f22facd10673e8e',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@feb2f8ee78ef33667c0f733b16bed1c5f49374b6',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 18108cb..650a614b 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -230,8 +230,6 @@
     "cancel_mode.h",
     "capture_mode/capture_label_view.cc",
     "capture_mode/capture_label_view.h",
-    "capture_mode/capture_mode_advanced_settings_view.cc",
-    "capture_mode/capture_mode_advanced_settings_view.h",
     "capture_mode/capture_mode_api.cc",
     "capture_mode/capture_mode_ash_notification_view.cc",
     "capture_mode/capture_mode_ash_notification_view.h",
@@ -254,8 +252,6 @@
     "capture_mode/capture_mode_session.h",
     "capture_mode/capture_mode_session_focus_cycler.cc",
     "capture_mode/capture_mode_session_focus_cycler.h",
-    "capture_mode/capture_mode_settings_entry_view.cc",
-    "capture_mode/capture_mode_settings_entry_view.h",
     "capture_mode/capture_mode_settings_view.cc",
     "capture_mode/capture_mode_settings_view.h",
     "capture_mode/capture_mode_source_view.cc",
@@ -2963,8 +2959,8 @@
     "assistant/test/test_assistant_service.h",
     "assistant/test/test_assistant_setup.cc",
     "assistant/test/test_assistant_setup.h",
-    "capture_mode/capture_mode_advanced_settings_test_api.cc",
-    "capture_mode/capture_mode_advanced_settings_test_api.h",
+    "capture_mode/capture_mode_settings_test_api.cc",
+    "capture_mode/capture_mode_settings_test_api.h",
     "capture_mode/fake_folder_selection_dialog_factory.cc",
     "capture_mode/fake_folder_selection_dialog_factory.h",
     "capture_mode/test_capture_mode_delegate.cc",
diff --git a/ash/accessibility/ui/accessibility_focus_ring_group.cc b/ash/accessibility/ui/accessibility_focus_ring_group.cc
index e88fc27d..035ec98a 100644
--- a/ash/accessibility/ui/accessibility_focus_ring_group.cc
+++ b/ash/accessibility/ui/accessibility_focus_ring_group.cc
@@ -13,6 +13,7 @@
 #include "ash/accessibility/ui/accessibility_layer.h"
 #include "ash/accessibility/ui/layer_animation_info.h"
 #include "ash/public/cpp/accessibility_focus_ring_info.h"
+#include "base/memory/values_equivalent.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/geometry/rect.h"
 
@@ -149,8 +150,7 @@
   }
 
   // If there is no change, don't do any work.
-  if ((!focus_ring_info_ && !focus_ring) ||
-      (focus_ring_info_ && focus_ring && *focus_ring_info_ == *focus_ring))
+  if (base::ValuesEquivalent(focus_ring_info_, focus_ring))
     return false;
 
   focus_ring_info_ = std::move(focus_ring);
diff --git a/ash/app_list/app_list_presenter_unittest.cc b/ash/app_list/app_list_presenter_unittest.cc
index 6d182da..c284496 100644
--- a/ash/app_list/app_list_presenter_unittest.cc
+++ b/ash/app_list/app_list_presenter_unittest.cc
@@ -3763,10 +3763,7 @@
   GetAppListTestHelper()->CheckState(AppListViewState::kClosed);
 }
 
-// Tests that tap the auto-hide shelf with app list opened should dismiss the
-// app list but keep shelf visible.
-// TODO(crbug.com/1273162): Fix for ProductivityLauncher.
-TEST_F(AppListPresenterTest, TapAutoHideShelfWithAppListOpened) {
+TEST_F(AppListPresenterTest, TapAppListThenSystemTrayShowsAutoHiddenShelf) {
   Shelf* shelf = GetPrimaryShelf();
   shelf->SetAutoHideBehavior(ShelfAutoHideBehavior::kAlways);
 
@@ -3789,13 +3786,22 @@
   EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState());
 
   // Tap to dismiss the app list and the auto-hide shelf.
-  ui::test::EventGenerator* generator = GetEventGenerator();
-  generator->GestureTapAt(gfx::Point(0, 0));
+  GetEventGenerator()->GestureTapAt(gfx::Point(0, 0));
   EXPECT_FALSE(GetPrimaryUnifiedSystemTray()->IsBubbleShown());
   EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState());
   GetAppListTestHelper()->CheckVisibility(false);
+}
 
-  // Show the AppList again.
+TEST_F(AppListPresenterTest, TapAppListThenShelfHidesAutoHiddenShelf) {
+  Shelf* shelf = GetPrimaryShelf();
+  shelf->SetAutoHideBehavior(ShelfAutoHideBehavior::kAlways);
+
+  // Create a normal unmaximized window; the shelf should be hidden.
+  std::unique_ptr<views::Widget> window = CreateTestWidget();
+  window->SetBounds(gfx::Rect(0, 0, 100, 100));
+  EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState());
+
+  // Show the AppList.
   GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId());
   GetAppListTestHelper()->CheckVisibility(true);
   EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState());
@@ -3812,8 +3818,9 @@
 
   // Test that tapping the auto-hidden shelf dismisses the app list when tapping
   // part of the shelf that does not contain the apps.
-  generator->GestureTapAt(shelf_view->GetBoundsInScreen().left_center() +
-                          gfx::Vector2d(10, 0));
+  GetEventGenerator()->GestureTapAt(
+      shelf_view->GetBoundsInScreen().left_center() + gfx::Vector2d(10, 0));
+  base::RunLoop().RunUntilIdle();  // Wait for autohide to be recomputed.
   GetAppListTestHelper()->CheckVisibility(false);
   EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState());
 
diff --git a/ash/app_list/views/app_list_folder_view.cc b/ash/app_list/views/app_list_folder_view.cc
index 9a5ee18..773f28e 100644
--- a/ash/app_list/views/app_list_folder_view.cc
+++ b/ash/app_list/views/app_list_folder_view.cc
@@ -1114,14 +1114,18 @@
     bool cancel_drag,
     std::unique_ptr<AppDragIconProxy> drag_icon_proxy) {
   folder_item_->NotifyOfDraggedItem(nullptr);
-  root_apps_grid_view_->EndDragFromReparentItemInRootLevel(
-      folder_item_view_, events_forwarded_to_drag_drop_host, cancel_drag,
-      std::move(drag_icon_proxy));
   folder_controller_->ReparentDragEnded();
 
+  // Cache `folder_item_view_`, as it will get reset in `HideViewImmediately()`.
+  AppListItemView* const folder_item_view = folder_item_view_;
+
   // The view was not hidden in order to keeping receiving mouse events. Hide it
   // now as the reparenting ended.
   HideViewImmediately();
+
+  root_apps_grid_view_->EndDragFromReparentItemInRootLevel(
+      folder_item_view, events_forwarded_to_drag_drop_host, cancel_drag,
+      std::move(drag_icon_proxy));
 }
 
 void AppListFolderView::HideViewImmediately() {
@@ -1164,6 +1168,8 @@
   folder_controller_->ReparentFolderItemTransit(folder_item_);
   root_apps_grid_view_->HandleKeyboardReparent(reparented_view,
                                                folder_item_view_, key_code);
+  folder_controller_->ReparentDragEnded();
+  HideViewImmediately();
 }
 
 bool AppListFolderView::IsPointWithinPageFlipBuffer(
diff --git a/ash/app_list/views/apps_grid_view.cc b/ash/app_list/views/apps_grid_view.cc
index 60d8fd8..86ca4b6 100644
--- a/ash/app_list/views/apps_grid_view.cc
+++ b/ash/app_list/views/apps_grid_view.cc
@@ -623,6 +623,8 @@
   if (!drag_item_)
     return;
 
+  AppListItem* drag_item = drag_item_;
+
   // Whether an icon was actually dragged (and not just clicked).
   const bool was_dragging = IsDragging();
 
@@ -630,13 +632,9 @@
   const bool landed_in_drag_and_drop_host =
       forward_events_to_drag_and_drop_host_;
 
-  // The drag ended by reparenting in a folder.
-  bool reparented_into_folder = false;
-
-  // This is the folder view to drop an item into. Cache the |drag_view_|'s item
-  // and its bounds for later use in folder dropping animation.
-  AppListItemView* folder_item_view = nullptr;
-  AppListItem* drag_item = drag_item_;
+  // The ID of the folder to which the item gets dropped. It will get set when
+  // the item is moved to a folder.
+  std::string target_folder_id;
 
   if (forward_events_to_drag_and_drop_host_) {
     DCHECK(!IsDraggingForReparentInRootLevelGridView());
@@ -676,9 +674,13 @@
       UpdateDropTargetRegion();
       if (drop_target_region_ == ON_ITEM && DraggedItemCanEnterFolder() &&
           DropTargetIsValidFolder()) {
-        MaybeCreateFolderDroppingAccessibilityEvent();
-        folder_item_view = MoveItemToFolder(drag_item_, drop_target_);
-        reparented_into_folder = true;
+        if (MoveItemToFolder(drag_item_, drop_target_, kMoveByDragIntoFolder,
+                             &target_folder_id)) {
+          MaybeCreateFolderDroppingAccessibilityEvent();
+          // If move to folder created a folder, layout the grid to ensure the
+          // created folder's bounds are correct.
+          Layout();
+        }
       } else if (IsValidReorderTargetIndex(drop_target_)) {
         // Ensure reorder event has already been announced by the end of drag.
         MaybeCreateDragReorderAccessibilityEvent();
@@ -699,11 +701,6 @@
     drag_view_hider_.reset();
   }
 
-  if (folder_item_view) {
-    folder_icon_item_hider_ = std::make_unique<FolderIconItemHider>(
-        static_cast<AppListFolderItem*>(folder_item_view->item()), drag_item);
-  }
-
   SetAsFolderDroppingTarget(drop_target_, false);
 
   ClearDragState();
@@ -739,8 +736,15 @@
   if (was_dragging)
     SetFocusAfterEndDrag();  // Maybe focus the search box.
 
-  AnimateDragIconToTargetPosition(reparented_into_folder, drag_item,
-                                  folder_item_view);
+  AnimateDragIconToTargetPosition(drag_item, target_folder_id);
+}
+
+AppListItemView* AppsGridView::GetItemViewForItem(const std::string& item_id) {
+  const AppListItem* const item = item_list_->FindItem(item_id);
+  if (!item)
+    return nullptr;
+
+  return GetItemViewAt(GetModelIndexOfItem(item));
 }
 
 AppListItemView* AppsGridView::GetItemViewAt(int index) const {
@@ -1327,18 +1331,21 @@
 }
 
 void AppsGridView::AnimateDragIconToTargetPosition(
-    bool dropping_into_folder,
     AppListItem* drag_item,
-    AppListItemView* target_folder_view) {
+    const std::string& target_folder_id) {
   // If drag icon proxy had not been created, just reshow the drag view.
   if (!drag_icon_proxy_) {
     OnDragIconDropDone();
     return;
   }
 
+  AppListItemView* target_folder_view =
+      !target_folder_id.empty() ? GetItemViewForItem(target_folder_id)
+                                : nullptr;
+
   // Calculate target item bounds.
   gfx::Rect drag_icon_drop_bounds;
-  if (!dropping_into_folder) {
+  if (target_folder_id.empty()) {
     // Find the view for drag item, and use its ideal bounds to calculate target
     // drop bounds.
     for (int i = 0; i < view_model_.view_size(); ++i) {
@@ -1369,6 +1376,12 @@
     return;
   }
 
+  if (target_folder_view) {
+    DCHECK(target_folder_view->is_folder());
+    folder_icon_item_hider_ = std::make_unique<FolderIconItemHider>(
+        static_cast<AppListFolderItem*>(target_folder_view->item()), drag_item);
+  }
+
   drag_icon_drop_bounds =
       items_container_->GetMirroredRect(drag_icon_drop_bounds);
   // Convert target bounds to in screen coordinates expected by drag icon proxy.
@@ -1570,14 +1583,16 @@
   const std::u16string target_view_title = target_view->title()->GetText();
   const bool target_view_is_folder = target_view->is_folder();
 
-  AppListItemView* folder_item =
-      MoveItemToFolder(selected_view_->item(), target_index);
-  a11y_announcer_->AnnounceKeyboardFoldering(
-      moving_view_title, target_view_title, target_view_is_folder);
-  Layout();
-  DCHECK(folder_item->is_folder());
-  folder_item->RequestFocus();
-  RecordAppMovingTypeMetrics(kMoveByKeyboardIntoFolder);
+  std::string folder_id;
+  if (MoveItemToFolder(selected_view_->item(), target_index,
+                       kMoveByKeyboardIntoFolder, &folder_id)) {
+    a11y_announcer_->AnnounceKeyboardFoldering(
+        moving_view_title, target_view_title, target_view_is_folder);
+    Layout();
+    AppListItemView* folder_view = GetItemViewForItem(folder_id);
+    if (folder_view)
+      folder_view->RequestFocus();
+  }
 }
 
 bool AppsGridView::CanMoveSelectedToTargetForKeyboardFoldering(
@@ -1697,27 +1712,34 @@
 
   drag_icon_proxy_ = std::move(drag_icon_proxy);
 
+  AppListItem* drag_item = drag_item_;
+
   DCHECK(IsDraggingForReparentInRootLevelGridView());
   bool cancel_reparent = cancel_drag || drop_target_region_ == NO_TARGET;
 
-  // This is the folder view to drop an item into. Cache the |drag_view_|'s item
-  // and its bounds for later use in folder dropping animation.
-  AppListItemView* folder_item_view =
-      cancel_reparent ? original_parent_item_view : nullptr;
-  AppListItem* drag_item = drag_item_;
+  // The ID of the folder to which the item gets dropped. It will get set when
+  // the item is moved to a folder. It will be set the to original folder ID if
+  // reparent is canceled.
+  std::string target_folder_id;
+
+  // Cache the original item folder id, as model updates may destroy the
+  // original folder item.
+  const std::string original_folder_id =
+      original_parent_item_view->item()->id();
 
   if (!events_forwarded_to_drag_drop_host && !cancel_reparent) {
     UpdateDropTargetRegion();
     if (drop_target_region_ == ON_ITEM && DropTargetIsValidFolder() &&
         DraggedItemCanEnterFolder()) {
-      cancel_reparent = !ReparentItemToAnotherFolder(drag_item, drop_target_);
-      // Announce folder dropping event before end of drag of reparented item.
-      MaybeCreateFolderDroppingAccessibilityEvent();
-      if (!cancel_reparent) {
-        folder_item_view =
-            GetViewDisplayedAtSlotOnCurrentPage(drop_target_.slot);
+      if (MoveItemToFolder(drag_item, drop_target_, kMoveIntoAnotherFolder,
+                           &target_folder_id)) {
+        // Announce folder dropping event before end of drag of reparented item.
+        MaybeCreateFolderDroppingAccessibilityEvent();
+        // If move to folder created a folder, layout the grid to ensure the
+        // created folder's bounds are correct.
+        Layout();
       } else {
-        folder_item_view = original_parent_item_view;
+        cancel_reparent = true;
       }
     } else if (drop_target_region_ != NO_TARGET &&
                IsValidReorderTargetIndex(drop_target_)) {
@@ -1731,13 +1753,10 @@
     }
   }
 
-  SetAsFolderDroppingTarget(drop_target_, false);
+  if (cancel_reparent)
+    target_folder_id = original_folder_id;
 
-  // Hide the drag item icon from the target folder icon.
-  if (folder_item_view) {
-    folder_icon_item_hider_ = std::make_unique<FolderIconItemHider>(
-        static_cast<AppListFolderItem*>(folder_item_view->item()), drag_item);
-  }
+  SetAsFolderDroppingTarget(drop_target_, false);
 
   UpdatePaging();
   ClearDragState();
@@ -1755,9 +1774,7 @@
   BeginHideCurrentGhostImageView();
   SetFocusAfterEndDrag();  // Maybe focus the search box.
 
-  AnimateDragIconToTargetPosition(
-      /*dropping_into_folder=*/cancel_reparent || folder_item_view, drag_item,
-      folder_item_view);
+  AnimateDragIconToTargetPosition(drag_item, target_folder_id);
 }
 
 void AppsGridView::EndDragForReparentInHiddenFolderGridView() {
@@ -1969,43 +1986,35 @@
   }
 }
 
-AppListItemView* AppsGridView::MoveItemToFolder(AppListItem* item,
-                                                const GridIndex& target) {
-  const std::string& source_item_id = item->id();
+bool AppsGridView::MoveItemToFolder(AppListItem* item,
+                                    const GridIndex& target,
+                                    AppListAppMovingType move_type,
+                                    std::string* folder_id) {
+  const std::string source_item_id = item->id();
+  const std::string source_folder_id = item->folder_id();
+
   AppListItemView* target_view =
       GetViewDisplayedAtSlotOnCurrentPage(target.slot);
   DCHECK(target_view);
-  const std::string& target_view_item_id = target_view->item()->id();
+  const std::string target_view_item_id = target_view->item()->id();
 
-  // Check that the item is not being dropped onto itself; this should not
-  // happen, but it can if something allows multiple views to share an
-  // item (e.g., if a folder drop does not clean up properly).
-  DCHECK_NE(source_item_id, target_view_item_id);
-
-  const bool is_dragged_view = drag_item_ == item;
-  // Make change to data model.
-  std::string folder_item_id;
+  // An app is being reparented to its original folder. Just cancel the
+  // reparent.
+  if (target_view_item_id == source_folder_id)
+    return false;
 
   {
     ScopedModelUpdate update(this);
-    folder_item_id = model_->MergeItems(target_view_item_id, source_item_id);
+    *folder_id = model_->MergeItems(target_view_item_id, source_item_id);
   }
 
-  if (folder_item_id.empty()) {
+  if (folder_id->empty()) {
     LOG(ERROR) << "Unable to merge into item id: " << target_view_item_id;
-    return nullptr;
+    return false;
   }
 
-  const AppListItem* const folder_item = item_list_->FindItem(folder_item_id);
-  if (!folder_item) {
-    LOG(ERROR) << "Unable to find target folder item " << folder_item_id;
-    return nullptr;
-  }
-
-  if (is_dragged_view)
-    RecordAppMovingTypeMetrics(kMoveByDragIntoFolder);
-
-  return GetItemViewAt(GetModelIndexOfItem(folder_item));
+  RecordAppMovingTypeMetrics(move_type);
+  return true;
 }
 
 void AppsGridView::ReparentItemForReorder(AppListItem* item,
@@ -2038,39 +2047,6 @@
   }
 }
 
-bool AppsGridView::ReparentItemToAnotherFolder(AppListItem* item,
-                                               const GridIndex& target) {
-  DCHECK(IsDraggingForReparentInRootLevelGridView());
-
-  AppListItemView* target_view =
-      GetViewDisplayedAtSlotOnCurrentPage(target.slot);
-  if (!target_view)
-    return false;
-
-  CHECK(item->IsInFolder());
-  const std::string source_folder_id = item->folder_id();
-
-  AppListItem* target_item = target_view->item();
-
-  // An app is being reparented to its original folder. Just cancel the
-  // reparent.
-  if (target_item->id() == item->folder_id())
-    return false;
-
-  {
-    ScopedModelUpdate update(this);
-    const std::string target_id_after_merge =
-        model_->MergeItems(target_item->id(), item->id());
-    if (target_id_after_merge.empty()) {
-      LOG(ERROR) << "Unable to reparent to item id: " << target_item->id();
-      return false;
-    }
-  }
-
-  RecordAppMovingTypeMetrics(kMoveIntoAnotherFolder);
-  return true;
-}
-
 void AppsGridView::CancelContextMenusOnCurrentPage() {
   GridIndex start_index(GetSelectedPage(), 0);
   if (!IsValidIndex(start_index))
diff --git a/ash/app_list/views/apps_grid_view.h b/ash/app_list/views/apps_grid_view.h
index 967b0d6..2db75be 100644
--- a/ash/app_list/views/apps_grid_view.h
+++ b/ash/app_list/views/apps_grid_view.h
@@ -204,6 +204,10 @@
   // Returns true if a touch or click lies between two occupied tiles.
   bool EventIsBetweenOccupiedTiles(const ui::LocatedEvent* event);
 
+  // Returns the item view of the item with the provided item ID.
+  // Returns nullptr if there is no such item.
+  AppListItemView* GetItemViewForItem(const std::string& item_id);
+
   // Returns the item view of the item at |index|, or nullptr if there is no
   // view at |index|.
   AppListItemView* GetItemViewAt(int index) const;
@@ -610,22 +614,20 @@
   void MoveItemInModel(AppListItem* item, const GridIndex& target);
 
   // Updates `model_` to move `item` into a folder containing item located at
-  // `target` slot. Returns the preexisting or created folder view as a result
-  // of the move, or nullptr if the move fails.
-  AppListItemView* MoveItemToFolder(AppListItem* item, const GridIndex& target);
+  // `target` slot. Returns whether the move operation succeeded.
+  // On success, `folder_id` will be set to the ID of the folder to which the
+  // item was moved. This may be a folder that was created by the move, or a
+  // preexisting folder.
+  bool MoveItemToFolder(AppListItem* item,
+                        const GridIndex& target,
+                        AppListAppMovingType move_type,
+                        std::string* folder_id);
 
   // Updates data model for re-parenting a folder item to a new position in top
   // level item list. The view model is will get updated in response to the data
   // model changes.
   void ReparentItemForReorder(AppListItem* item, const GridIndex& target);
 
-  // Updates both data model for re-parenting a folder item
-  // to anther folder target. The view model will get updated in response to the
-  // data model changes.
-  // Returns whether the reparent succeeded.
-  bool ReparentItemToAnotherFolder(AppListItem* item_view,
-                                   const GridIndex& target);
-
   // Removes the AppListItemView at |index| in |view_model_|, removes it from
   // view structure as well and deletes it.
   void DeleteItemViewAtIndex(int index);
@@ -651,14 +653,11 @@
   // Animates `drag_icon_proxy_` to drop it into appropriate target bounds in
   // the apps grid when the item drag ends. Expects `drag_icon_proxy_` to be
   // set.
-  // `dropping_into_folder` - Whether the drag item icon should be dropped
-  // into a folder view.
   // `drag_item` - The dragged item.
-  // `target_folder_view` - If the item needs to be dropped into a folder, the
-  // target folder view.
-  void AnimateDragIconToTargetPosition(bool dropping_into_folder,
-                                       AppListItem* drag_item,
-                                       AppListItemView* target_folder_view);
+  // `target_folder_id` - If the item needs to be dropped into a folder, the
+  // target folder ID.
+  void AnimateDragIconToTargetPosition(AppListItem* drag_item,
+                                       const std::string& target_folder_id);
 
   // Called when the `drag_icon_proxy_` animation started by
   // `AnimateDragIconToTargetPosition()` finishes. It resets `drag_icon_proxy_`
diff --git a/ash/app_list/views/apps_grid_view_test_api.cc b/ash/app_list/views/apps_grid_view_test_api.cc
index dc1ac92..4454983 100644
--- a/ash/app_list/views/apps_grid_view_test_api.cc
+++ b/ash/app_list/views/apps_grid_view_test_api.cc
@@ -154,5 +154,11 @@
   return gfx::Rect(icon_origin, icon_bounds_in_screen.size());
 }
 
+ui::Layer* AppsGridViewTestApi::GetDragIconLayer() {
+  if (!view_->drag_icon_proxy_)
+    return nullptr;
+  return view_->drag_icon_proxy_->GetImageLayerForTesting();
+}
+
 }  // namespace test
 }  // namespace ash
diff --git a/ash/app_list/views/apps_grid_view_test_api.h b/ash/app_list/views/apps_grid_view_test_api.h
index bdd5aa6..333a925 100644
--- a/ash/app_list/views/apps_grid_view_test_api.h
+++ b/ash/app_list/views/apps_grid_view_test_api.h
@@ -13,6 +13,10 @@
 class Rect;
 }
 
+namespace ui {
+class Layer;
+}
+
 namespace views {
 class View;
 }
@@ -75,6 +79,9 @@
   // Returns empty bounds if the icon proxy has not been created.
   gfx::Rect GetDragIconBoundsInAppsGridView();
 
+  // Returns the layer used by the app drag icon proxy.
+  ui::Layer* GetDragIconLayer();
+
   AppListItemList* GetItemList() { return view_->item_list_; }
 
   PagedViewStructure* GetPagedViewStructure() {
diff --git a/ash/app_list/views/apps_grid_view_unittest.cc b/ash/app_list/views/apps_grid_view_unittest.cc
index 2d12141..8b40065 100644
--- a/ash/app_list/views/apps_grid_view_unittest.cc
+++ b/ash/app_list/views/apps_grid_view_unittest.cc
@@ -1547,6 +1547,27 @@
   EXPECT_EQ(folder_item->id(), item_2->folder_id());
 }
 
+TEST_P(AppsGridViewDragTest, DragIconAnimatesAfterDragToFolder) {
+  model_->CreateAndPopulateFolderWithApps(2);
+  model_->PopulateApps(1);
+  UpdateLayout();
+
+  ui::ScopedAnimationDurationScaleMode non_zero_duration_mode(
+      ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
+
+  InitiateDragForItemAtCurrentPageAt(AppsGridView::MOUSE, 0, 1,
+                                     apps_grid_view_);
+
+  // Dragging item_2 to the folder adds Item_2 to the folder.
+  gfx::Point to = GetItemRectOnCurrentPageAt(0, 0).CenterPoint();
+  UpdateDrag(AppsGridView::MOUSE, to, apps_grid_view_, 10 /*steps*/);
+  EndDrag(apps_grid_view_, false /*cancel*/);
+
+  ui::Layer* drag_icon_layer = test_api_->GetDragIconLayer();
+  ASSERT_TRUE(drag_icon_layer);
+  EXPECT_TRUE(drag_icon_layer->GetAnimator()->is_animating());
+}
+
 TEST_P(AppsGridViewClamshellTest, CheckFolderWithMultiplePagesContents) {
   // Creates a folder item.
   const size_t kTotalItems = kMaxItemsPerFolderPage;
@@ -1611,6 +1632,132 @@
   EXPECT_EQ(kTotalItems - 1, folder_item->ChildItemCount());
 }
 
+TEST_P(AppsGridViewDragTest, DragIconAnimatesAfterDragOutOfFolder) {
+  model_->CreateAndPopulateFolderWithApps(5);
+  test_api_->Update();
+  test_api_->PressItemAt(0);
+
+  ui::ScopedAnimationDurationScaleMode non_zero_duration_mode(
+      ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
+
+  // Drag the first folder child out of the folder.
+  AppListItemView* drag_view = InitiateDragForItemAtCurrentPageAt(
+      AppsGridView::MOUSE, 0, 0, folder_apps_grid_view());
+  gfx::Point empty_space =
+      app_list_folder_view()->GetLocalBounds().bottom_center() +
+      gfx::Vector2d(0, drag_view->height()
+                    /*padding to completely exit folder view*/);
+  UpdateDrag(AppsGridView::MOUSE, empty_space, folder_apps_grid_view(),
+             10 /*steps*/);
+  // Fire the reparent timer that should be started when an item is dragged out
+  // of folder bounds.
+  ASSERT_TRUE(folder_apps_grid_view()->FireFolderItemReparentTimerForTest());
+
+  // Calculate the coordinates for the drop point. Note that we we are dropping
+  // into the app list view not the folder view. The (0,1) spot is empty.
+  gfx::Point drop_point = GetItemRectOnCurrentPageAt(0, 1).CenterPoint();
+  views::View::ConvertPointToTarget(apps_grid_view_, folder_apps_grid_view(),
+                                    &drop_point);
+  UpdateDrag(AppsGridView::MOUSE, drop_point, folder_apps_grid_view(),
+             5 /*steps*/);
+  EndDrag(folder_apps_grid_view(), false /*cancel*/);
+
+  ui::Layer* drag_icon_layer = test_api_->GetDragIconLayer();
+  ASSERT_TRUE(drag_icon_layer);
+  EXPECT_TRUE(drag_icon_layer->GetAnimator()->is_animating());
+}
+
+TEST_P(AppsGridViewDragTest, DragIconAnimatesAfterDragToAnotherFolder) {
+  model_->CreateAndPopulateFolderWithApps(5);
+  model_->CreateAndPopulateFolderWithApps(5);
+  test_api_->Update();
+  test_api_->PressItemAt(0);
+
+  ui::ScopedAnimationDurationScaleMode non_zero_duration_mode(
+      ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
+
+  // Drag the first folder child out of the folder.
+  AppListItemView* drag_view = InitiateDragForItemAtCurrentPageAt(
+      AppsGridView::MOUSE, 0, 0, folder_apps_grid_view());
+  gfx::Point empty_space =
+      app_list_folder_view()->GetLocalBounds().bottom_center() +
+      gfx::Vector2d(0, drag_view->height()
+                    /*padding to completely exit folder view*/);
+  UpdateDrag(AppsGridView::MOUSE, empty_space, folder_apps_grid_view(),
+             10 /*steps*/);
+  // Fire the reparent timer that should be started when an item is dragged out
+  // of folder bounds.
+  ASSERT_TRUE(folder_apps_grid_view()->FireFolderItemReparentTimerForTest());
+
+  // Calculate the coordinates for the drop point.
+  gfx::Point drop_point = GetItemRectOnCurrentPageAt(0, 1).CenterPoint();
+  views::View::ConvertPointToTarget(apps_grid_view_, folder_apps_grid_view(),
+                                    &drop_point);
+  UpdateDrag(AppsGridView::MOUSE, drop_point, folder_apps_grid_view(),
+             5 /*steps*/);
+  EndDrag(folder_apps_grid_view(), false /*cancel*/);
+
+  ui::Layer* drag_icon_layer = test_api_->GetDragIconLayer();
+  ASSERT_TRUE(drag_icon_layer);
+  EXPECT_TRUE(drag_icon_layer->GetAnimator()->is_animating());
+}
+
+TEST_P(AppsGridViewDragTest,
+       DragIconAnimatesAfterDragThatDeletesOriginalFolder) {
+  model_->PopulateApps(2);
+  model_->CreateSingleItemFolder("folder_id", "item_id");
+  test_api_->Update();
+  test_api_->PressItemAt(2);
+
+  ui::ScopedAnimationDurationScaleMode non_zero_duration_mode(
+      ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
+
+  // Drag the only folder child out of the folder.
+  AppListItemView* drag_view = InitiateDragForItemAtCurrentPageAt(
+      AppsGridView::MOUSE, 0, 0, folder_apps_grid_view());
+  gfx::Point empty_space =
+      app_list_folder_view()->GetLocalBounds().bottom_center() +
+      gfx::Vector2d(0, drag_view->height()
+                    /*padding to completely exit folder view*/);
+  UpdateDrag(AppsGridView::MOUSE, empty_space, folder_apps_grid_view(),
+             10 /*steps*/);
+  // Fire the reparent timer that should be started when an item is dragged out
+  // of folder bounds.
+  ASSERT_TRUE(folder_apps_grid_view()->FireFolderItemReparentTimerForTest());
+
+  // Calculate the coordinates for the drop point. Note that we we are dropping
+  // into the app list view not the folder view. The (0,3) spot is empty.
+  gfx::Point drop_point = GetItemRectOnCurrentPageAt(0, 3).CenterPoint();
+  views::View::ConvertPointToTarget(apps_grid_view_, folder_apps_grid_view(),
+                                    &drop_point);
+  UpdateDrag(AppsGridView::MOUSE, drop_point, folder_apps_grid_view(),
+             5 /*steps*/);
+  EndDrag(folder_apps_grid_view(), false /*cancel*/);
+
+  ui::Layer* drag_icon_layer = test_api_->GetDragIconLayer();
+  ASSERT_TRUE(drag_icon_layer);
+  EXPECT_TRUE(drag_icon_layer->GetAnimator()->is_animating());
+}
+
+TEST_P(AppsGridViewDragTest, DragIconAnimatesAfterReorderDrag) {
+  model_->PopulateApps(3);
+  test_api_->Update();
+
+  ui::ScopedAnimationDurationScaleMode non_zero_duration_mode(
+      ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
+
+  // Drag the first item to an empty slot in the grid.
+  InitiateDragForItemAtCurrentPageAt(AppsGridView::MOUSE, 0, 0,
+                                     apps_grid_view_);
+  gfx::Point drop_point = GetItemRectOnCurrentPageAt(0, 3).CenterPoint();
+  UpdateDrag(AppsGridView::MOUSE, drop_point, apps_grid_view_, 5 /*steps*/);
+  EndDrag(apps_grid_view_, false /*cancel*/);
+
+  ui::Layer* drag_icon_layer = test_api_->GetDragIconLayer();
+  ASSERT_TRUE(drag_icon_layer);
+  EXPECT_TRUE(drag_icon_layer->GetAnimator()->is_animating());
+}
+
 TEST_F(AppsGridViewNonBubbleTest, SwitchPageFolderItem) {
   // ProductivityLauncher does not use paged folders.
   ASSERT_FALSE(features::IsProductivityLauncherEnabled());
@@ -1640,7 +1787,6 @@
       model_->CreateAndPopulateFolderWithApps(kTotalItems);
   test_api_->Update();
   test_api_->PressItemAt(0);
-  AppsGridViewTestApi folder_grid_test_api(folder_apps_grid_view());
   // Switch to second page.
   AnimateFolderViewPageFlip(1);
   // Drag the first folder child on the second page out of the folder.
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 5c39282..d251de48e 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -4030,9 +4030,6 @@
       <message name="IDS_ASH_SCREEN_CAPTURE_TOOLTIP_SETTINGS" desc="Tooltip of the settings button.">
         Settings
       </message>
-      <message name="IDS_ASH_SCREEN_CAPTURE_LABEL_MICROPHONE" desc="The capture label message for toggling microphone recording, found in the settings menu.">
-        Record microphone
-      </message>
       <message name="IDS_ASH_SCREEN_CAPTURE_AUDIO_INPUT" desc="The label of the audio input menu group header in capture mode settings.">
         Audio input
       </message>
diff --git a/ash/ash_strings_grd/IDS_ASH_SCREEN_CAPTURE_LABEL_MICROPHONE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_SCREEN_CAPTURE_LABEL_MICROPHONE.png.sha1
deleted file mode 100644
index b7ec452..0000000
--- a/ash/ash_strings_grd/IDS_ASH_SCREEN_CAPTURE_LABEL_MICROPHONE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-9044c8c2ccb94b90adc0db97b3305dc3e87ccbc3
\ No newline at end of file
diff --git a/ash/capture_mode/capture_mode_advanced_settings_test_api.cc b/ash/capture_mode/capture_mode_advanced_settings_test_api.cc
deleted file mode 100644
index 5616b22..0000000
--- a/ash/capture_mode/capture_mode_advanced_settings_test_api.cc
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/capture_mode/capture_mode_advanced_settings_test_api.h"
-
-#include "ash/capture_mode/capture_mode_advanced_settings_view.h"
-#include "ash/capture_mode/capture_mode_controller.h"
-#include "ash/capture_mode/capture_mode_session.h"
-#include "ash/constants/ash_features.h"
-#include "base/check.h"
-
-namespace ash {
-
-namespace {
-
-CaptureModeSession* GetCaptureModeSession() {
-  DCHECK(features::AreImprovedScreenCaptureSettingsEnabled());
-  auto* controller = CaptureModeController::Get();
-  DCHECK(controller->IsActive());
-  CaptureModeSession* session = controller->capture_mode_session();
-  DCHECK(session->capture_mode_settings_widget());
-  return session;
-}
-
-}  // namespace
-
-CaptureModeAdvancedSettingsTestApi::CaptureModeAdvancedSettingsTestApi()
-    : settings_view_(
-          GetCaptureModeSession()->capture_mode_advanced_settings_view_) {}
-
-CaptureModeAdvancedSettingsView*
-CaptureModeAdvancedSettingsTestApi::GetAdvancedSettingsView() {
-  return settings_view_;
-}
-
-CaptureModeMenuGroup*
-CaptureModeAdvancedSettingsTestApi::GetAudioInputMenuGroup() {
-  return settings_view_->audio_input_menu_group_;
-}
-
-views::View* CaptureModeAdvancedSettingsTestApi::GetMicrophoneOption() {
-  return GetAudioInputMenuGroup()->GetOptionForTesting(kAudioMicrophone);
-}
-
-views::View* CaptureModeAdvancedSettingsTestApi::GetAudioOffOption() {
-  return GetAudioInputMenuGroup()->GetOptionForTesting(kAudioOff);
-}
-
-CaptureModeMenuGroup* CaptureModeAdvancedSettingsTestApi::GetSaveToMenuGroup() {
-  return settings_view_->save_to_menu_group_;
-}
-
-views::View* CaptureModeAdvancedSettingsTestApi::GetDefaultDownloadsOption() {
-  return GetSaveToMenuGroup()->GetOptionForTesting(kDownloadsFolder);
-}
-
-views::View* CaptureModeAdvancedSettingsTestApi::GetCustomFolderOptionIfAny() {
-  return GetSaveToMenuGroup()->GetOptionForTesting(kCustomFolder);
-}
-
-views::View* CaptureModeAdvancedSettingsTestApi::GetSelectFolderMenuItem() {
-  return GetSaveToMenuGroup()->GetSelectFolderMenuItemForTesting();
-}
-
-void CaptureModeAdvancedSettingsTestApi::SetOnSettingsMenuRefreshedCallback(
-    base::OnceClosure callback) {
-  settings_view_->on_settings_menu_refreshed_callback_for_test_ =
-      std::move(callback);
-}
-
-}  // namespace ash
diff --git a/ash/capture_mode/capture_mode_advanced_settings_test_api.h b/ash/capture_mode/capture_mode_advanced_settings_test_api.h
deleted file mode 100644
index bf2992e..0000000
--- a/ash/capture_mode/capture_mode_advanced_settings_test_api.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_CAPTURE_MODE_CAPTURE_MODE_ADVANCED_SETTINGS_TEST_API_H_
-#define ASH_CAPTURE_MODE_CAPTURE_MODE_ADVANCED_SETTINGS_TEST_API_H_
-
-#include "base/callback_forward.h"
-
-namespace views {
-class View;
-}  // namespace views
-
-namespace ash {
-
-class CaptureModeAdvancedSettingsView;
-class CaptureModeMenuGroup;
-
-// Test APIs to test the UI of the advanced settings menu. Can only be created
-// while a capture mode session is active, and the settings menu is shown.
-class CaptureModeAdvancedSettingsTestApi {
- public:
-  CaptureModeAdvancedSettingsTestApi();
-  CaptureModeAdvancedSettingsTestApi(
-      const CaptureModeAdvancedSettingsTestApi&) = delete;
-  CaptureModeAdvancedSettingsTestApi& operator=(
-      const CaptureModeAdvancedSettingsTestApi&) = delete;
-  ~CaptureModeAdvancedSettingsTestApi() = default;
-
-  // Returns the content view of the advanced settings widget.
-  CaptureModeAdvancedSettingsView* GetAdvancedSettingsView();
-
-  // Returns the audio settings menu group and the views for its options.
-  CaptureModeMenuGroup* GetAudioInputMenuGroup();
-  views::View* GetMicrophoneOption();
-  views::View* GetAudioOffOption();
-
-  // Returns the save-to settings menu group and the views for its options.
-  CaptureModeMenuGroup* GetSaveToMenuGroup();
-  views::View* GetDefaultDownloadsOption();
-  views::View* GetCustomFolderOptionIfAny();
-
-  // Returns the view for the "Select folder" menu item which when pressed would
-  // open the folder selection dialog.
-  views::View* GetSelectFolderMenuItem();
-
-  // Sets a callback that will be triggered once the settings menu is refreshed.
-  void SetOnSettingsMenuRefreshedCallback(base::OnceClosure callback);
-
- private:
-  // Valid only while the settings menu is shown.
-  CaptureModeAdvancedSettingsView* const settings_view_;
-};
-
-}  // namespace ash
-
-#endif  // ASH_CAPTURE_MODE_CAPTURE_MODE_ADVANCED_SETTINGS_TEST_API_H_
diff --git a/ash/capture_mode/capture_mode_advanced_settings_view.cc b/ash/capture_mode/capture_mode_advanced_settings_view.cc
deleted file mode 100644
index 699fb7c2..0000000
--- a/ash/capture_mode/capture_mode_advanced_settings_view.cc
+++ /dev/null
@@ -1,252 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/capture_mode/capture_mode_advanced_settings_view.h"
-
-#include <memory>
-#include <string>
-
-#include "ash/capture_mode/capture_mode_bar_view.h"
-#include "ash/capture_mode/capture_mode_constants.h"
-#include "ash/capture_mode/capture_mode_controller.h"
-#include "ash/capture_mode/capture_mode_metrics.h"
-#include "ash/capture_mode/capture_mode_session.h"
-#include "ash/capture_mode/capture_mode_toggle_button.h"
-#include "ash/resources/vector_icons/vector_icons.h"
-#include "ash/strings/grit/ash_strings.h"
-#include "ash/style/ash_color_provider.h"
-#include "base/bind.h"
-#include "base/files/file_path.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/metadata/metadata_impl_macros.h"
-#include "ui/compositor/layer.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/views/background.h"
-#include "ui/views/controls/separator.h"
-#include "ui/views/layout/box_layout.h"
-
-namespace ash {
-
-namespace {
-
-constexpr gfx::Size kSettingsSize{256, 248};
-
-constexpr gfx::RoundedCornersF kBorderRadius{10.f};
-
-// Returns the bounds of the settings widget in screen coordinates relative to
-// the bounds of the |capture_mode_bar_view| based on its given preferred
-// |settings_view_size|.
-gfx::Rect GetWidgetBounds(CaptureModeBarView* capture_mode_bar_view,
-                          const gfx::Size& settings_view_size) {
-  DCHECK(capture_mode_bar_view);
-
-  return gfx::Rect(
-      capture_mode_bar_view->settings_button()->GetBoundsInScreen().right() -
-          kSettingsSize.width(),
-      capture_mode_bar_view->GetBoundsInScreen().y() -
-          capture_mode::kSpaceBetweenCaptureBarAndSettingsMenu -
-          settings_view_size.height(),
-      kSettingsSize.width(), settings_view_size.height());
-}
-
-CaptureModeController::CaptureFolder GetCurrentCaptureFolder() {
-  return CaptureModeController::Get()->GetCurrentCaptureFolder();
-}
-
-}  // namespace
-
-CaptureModeAdvancedSettingsView::CaptureModeAdvancedSettingsView(
-    CaptureModeSession* session,
-    bool is_in_projector_mode)
-    : capture_mode_session_(session),
-      audio_input_menu_group_(
-          AddChildView(std::make_unique<CaptureModeMenuGroup>(
-              this,
-              kCaptureModeMicIcon,
-              l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_AUDIO_INPUT)))) {
-  if (!is_in_projector_mode) {
-    audio_input_menu_group_->AddOption(
-        l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_AUDIO_INPUT_OFF),
-        kAudioOff);
-  }
-  audio_input_menu_group_->AddOption(
-      l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_AUDIO_INPUT_MICROPHONE),
-      kAudioMicrophone);
-
-  auto* color_provider = AshColorProvider::Get();
-  if (!is_in_projector_mode) {
-    separator_ = AddChildView(std::make_unique<views::Separator>());
-
-    save_to_menu_group_ = AddChildView(std::make_unique<CaptureModeMenuGroup>(
-        this, kCaptureModeFolderIcon,
-        l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_SAVE_TO)));
-    save_to_menu_group_->AddOption(
-        l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_SAVE_TO_DOWNLOADS),
-        kDownloadsFolder);
-    save_to_menu_group_->AddMenuItem(
-        base::BindRepeating(
-            &CaptureModeAdvancedSettingsView::OnSelectFolderMenuItemPressed,
-            base::Unretained(this)),
-        l10n_util::GetStringUTF16(
-            IDS_ASH_SCREEN_CAPTURE_SAVE_TO_SELECT_FOLDER));
-
-    const SkColor separator_color = color_provider->GetContentLayerColor(
-        AshColorProvider::ContentLayerType::kSeparatorColor);
-    separator_->SetColor(separator_color);
-  }
-
-  SetPaintToLayer();
-  SetBackground(views::CreateSolidBackground(color_provider->GetBaseLayerColor(
-      AshColorProvider::BaseLayerType::kTransparent80)));
-  layer()->SetFillsBoundsOpaquely(false);
-  layer()->SetRoundedCornerRadius(kBorderRadius);
-  layer()->SetBackgroundBlur(ColorProvider::kBackgroundBlurSigma);
-  layer()->SetBackdropFilterQuality(ColorProvider::kBackgroundBlurQuality);
-
-  SetLayoutManager(std::make_unique<views::BoxLayout>(
-      views::BoxLayout::Orientation::kVertical));
-}
-
-CaptureModeAdvancedSettingsView::~CaptureModeAdvancedSettingsView() = default;
-
-gfx::Rect CaptureModeAdvancedSettingsView::GetBounds(
-    CaptureModeBarView* capture_mode_bar_view,
-    CaptureModeAdvancedSettingsView* content_view) {
-  DCHECK(capture_mode_bar_view);
-
-  const gfx::Size settings_size =
-      content_view ? content_view->GetPreferredSize() : kSettingsSize;
-  return GetWidgetBounds(capture_mode_bar_view, settings_size);
-}
-
-void CaptureModeAdvancedSettingsView::OnCaptureFolderMayHaveChanged() {
-  if (!save_to_menu_group_)
-    return;
-  auto* controller = CaptureModeController::Get();
-  const auto custom_path = controller->GetCustomCaptureFolder();
-  if (custom_path.empty()) {
-    is_custom_folder_available_.reset();
-    save_to_menu_group_->RemoveOptionIfAny(kCustomFolder);
-    save_to_menu_group_->RefreshOptionsSelections();
-    return;
-  }
-
-  std::u16string folder_name = custom_path.BaseName().AsUTF16Unsafe();
-  // We explicitly name the folders of Google Drive and Play files, since those
-  // folders internally may have user-unfriendly names.
-  if (controller->IsRootDriveFsPath(custom_path)) {
-    folder_name =
-        l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_SAVE_TO_GOOGLE_DRIVE);
-  } else if (controller->IsAndroidFilesPath(custom_path)) {
-    folder_name =
-        l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_SAVE_TO_ANDROID_FILES);
-  }
-
-  save_to_menu_group_->AddOrUpdateExistingOption(folder_name, kCustomFolder);
-
-  controller->CheckFolderAvailability(
-      custom_path,
-      base::BindOnce(
-          &CaptureModeAdvancedSettingsView::OnCustomFolderAvailabilityChecked,
-          weak_ptr_factory_.GetWeakPtr()));
-}
-
-void CaptureModeAdvancedSettingsView::OnDefaultCaptureFolderSelectionChanged() {
-  if (save_to_menu_group_)
-    save_to_menu_group_->RefreshOptionsSelections();
-}
-
-std::vector<CaptureModeSessionFocusCycler::HighlightableView*>
-CaptureModeAdvancedSettingsView::GetHighlightableItems() {
-  std::vector<CaptureModeSessionFocusCycler::HighlightableView*>
-      highlightable_items;
-  DCHECK(audio_input_menu_group_);
-  audio_input_menu_group_->AppendHighlightableItems(highlightable_items);
-  if (save_to_menu_group_)
-    save_to_menu_group_->AppendHighlightableItems(highlightable_items);
-  return highlightable_items;
-}
-
-void CaptureModeAdvancedSettingsView::OnOptionSelected(int option_id) const {
-  auto* controller = CaptureModeController::Get();
-  switch (option_id) {
-    case kAudioOff:
-      controller->EnableAudioRecording(false);
-      break;
-    case kAudioMicrophone:
-      controller->EnableAudioRecording(true);
-      break;
-    case kDownloadsFolder:
-      controller->SetUsesDefaultCaptureFolder(true);
-      RecordSwitchToDefaultFolderReason(
-          CaptureModeSwitchToDefaultReason::kUserSelectedFromSettingsMenu);
-      break;
-    case kCustomFolder:
-      controller->SetUsesDefaultCaptureFolder(false);
-      break;
-    default:
-      return;
-  }
-}
-
-bool CaptureModeAdvancedSettingsView::IsOptionChecked(int option_id) const {
-  switch (option_id) {
-    case kAudioOff:
-      return !CaptureModeController::Get()->enable_audio_recording();
-    case kAudioMicrophone:
-      return CaptureModeController::Get()->enable_audio_recording();
-    case kDownloadsFolder:
-      return GetCurrentCaptureFolder().is_default_downloads_folder ||
-             !is_custom_folder_available_.value_or(false);
-    case kCustomFolder:
-      return !GetCurrentCaptureFolder().is_default_downloads_folder &&
-             is_custom_folder_available_.value_or(false);
-    default:
-      return false;
-  }
-}
-
-bool CaptureModeAdvancedSettingsView::IsOptionEnabled(int option_id) const {
-  switch (option_id) {
-    case kAudioOff:
-      return !capture_mode_session_->is_in_projector_mode();
-    case kCustomFolder:
-      return is_custom_folder_available_.value_or(false);
-    case kAudioMicrophone:
-    case kDownloadsFolder:
-    default:
-      return true;
-  }
-}
-
-views::View* CaptureModeAdvancedSettingsView::GetMicrophoneOptionForTesting() {
-  return audio_input_menu_group_->GetOptionForTesting(  // IN-TEST
-      kAudioMicrophone);                                // IN-TEST
-}
-
-views::View* CaptureModeAdvancedSettingsView::GetOffOptionForTesting() {
-  return audio_input_menu_group_->GetOptionForTesting(kAudioOff);  // IN-TEST
-}
-
-void CaptureModeAdvancedSettingsView::OnSelectFolderMenuItemPressed() {
-  capture_mode_session_->OpenFolderSelectionDialog();
-}
-
-void CaptureModeAdvancedSettingsView::OnCustomFolderAvailabilityChecked(
-    bool available) {
-  DCHECK(save_to_menu_group_);
-  is_custom_folder_available_ = available;
-  save_to_menu_group_->RefreshOptionsSelections();
-  if (!is_custom_folder_available_.value_or(false)) {
-    RecordSwitchToDefaultFolderReason(
-        CaptureModeSwitchToDefaultReason::kFolderUnavailable);
-  }
-  if (on_settings_menu_refreshed_callback_for_test_)
-    std::move(on_settings_menu_refreshed_callback_for_test_).Run();
-}
-
-BEGIN_METADATA(CaptureModeAdvancedSettingsView, views::View)
-END_METADATA
-
-}  // namespace ash
diff --git a/ash/capture_mode/capture_mode_advanced_settings_view.h b/ash/capture_mode/capture_mode_advanced_settings_view.h
deleted file mode 100644
index b052ae3..0000000
--- a/ash/capture_mode/capture_mode_advanced_settings_view.h
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_CAPTURE_MODE_CAPTURE_MODE_ADVANCED_SETTINGS_VIEW_H_
-#define ASH_CAPTURE_MODE_CAPTURE_MODE_ADVANCED_SETTINGS_VIEW_H_
-
-#include "ash/ash_export.h"
-#include "ash/capture_mode/capture_mode_menu_group.h"
-#include "ash/capture_mode/capture_mode_session_focus_cycler.h"
-#include "base/callback_forward.h"
-#include "ui/base/metadata/metadata_header_macros.h"
-#include "ui/views/view.h"
-
-namespace views {
-class Separator;
-}  // namespace views
-
-namespace ash {
-
-class CaptureModeBarView;
-class CaptureModeMenuGroup;
-class CaptureModeSession;
-
-// All the options in the CaptureMode settings view.
-enum CaptureSettingsOption {
-  kAudioOff = 0,
-  kAudioMicrophone,
-  kDownloadsFolder,
-  kCustomFolder,
-};
-
-// TODO(conniekxu): This will replace CaptureModeSettingsView once
-// feature 'ImprovedScreenCaptureSettings' is fully launched.
-// A view that acts as the content view of the capture mode settings menu
-// widget. It is the content view of settings widget and it contains
-// `CaptureModeMenuGroup` for each setting, save to, audio input etc.
-class ASH_EXPORT CaptureModeAdvancedSettingsView
-    : public views::View,
-      public CaptureModeMenuGroup::Delegate {
- public:
-  METADATA_HEADER(CaptureModeAdvancedSettingsView);
-
-  CaptureModeAdvancedSettingsView(CaptureModeSession* session,
-                                  bool is_in_projector_mode);
-  CaptureModeAdvancedSettingsView(const CaptureModeAdvancedSettingsView&) =
-      delete;
-  CaptureModeAdvancedSettingsView& operator=(
-      const CaptureModeAdvancedSettingsView&) = delete;
-  ~CaptureModeAdvancedSettingsView() override;
-
-  // Gets the ideal bounds in screen coordinates of the settings widget on
-  // the given |capture_mode_bar_view|. If |content_view| is not null, it will
-  // be used to get the preferred size to calculate the final bounds. Otherwise,
-  // a default size will be used.
-  static gfx::Rect GetBounds(
-      CaptureModeBarView* capture_mode_bar_view,
-      CaptureModeAdvancedSettingsView* content_view = nullptr);
-
-  // Called when the folder, in which the captured files will be saved, may have
-  // changed. This may result in adding or removing a menu option for the folder
-  // that was added or removed. This means that the preferred size of this view
-  // can possibly change, and therefore it's the responsibility of the caller to
-  // to set the proper bounds on the widget.
-  void OnCaptureFolderMayHaveChanged();
-
-  // Called when we change the setting to force-use the default downloads folder
-  // as the save folder. This results in updating which folder menu option is
-  // currently selected.
-  void OnDefaultCaptureFolderSelectionChanged();
-
-  // Gets the highlightable `CaptureModeOption` and `CaptureModeMenuItem` inside
-  // this view.
-  std::vector<CaptureModeSessionFocusCycler::HighlightableView*>
-  GetHighlightableItems();
-
-  // CaptureModeMenuGroup::Delegate:
-  void OnOptionSelected(int option_id) const override;
-  bool IsOptionChecked(int option_id) const override;
-  bool IsOptionEnabled(int option_id) const override;
-
-  // For tests only:
-  CaptureModeMenuGroup* GetAudioInputMenuGroupForTesting() {
-    return audio_input_menu_group_;
-  }
-  views::View* GetMicrophoneOptionForTesting();
-  views::View* GetOffOptionForTesting();
-
- private:
-  friend class CaptureModeAdvancedSettingsTestApi;
-
-  // Called when the "Select folder" menu item in the |save_to_menu_group_| is
-  // pressed. It opens the folder selection dialog so that user can pick a
-  // location in which captured files will be saved.
-  void OnSelectFolderMenuItemPressed();
-
-  // Called back when the check for custom folder's availability is done, with
-  // `available` indicating whether the custom folder is available or not. We
-  // will check the custom folder's availability every time when
-  // `OnCaptureFolderMayHaveChanged` is triggered and custom folder is not
-  // empty.
-  void OnCustomFolderAvailabilityChecked(bool available);
-
-  // A reference to the session that owns this view indirectly by owning its
-  // containing widget.
-  CaptureModeSession* const capture_mode_session_;  // Not null;
-
-  // "Audio input" menu group that users can select an audio input from for
-  // screen capture recording. It has "Off" and "Microphone" options for now.
-  // "Off" is the default one which means no audio input selected.
-  CaptureModeMenuGroup* audio_input_menu_group_;
-
-  // Can be null when in Projector mode, since then it's not needed as the
-  // "Save-to" menu group will not be added at all.
-  views::Separator* separator_ = nullptr;
-
-  // "Save to" menu group that users can select a folder to save the captured
-  // files to. It will include the "Downloads" folder as the default one and
-  // one more folder selected by users.
-  // This menu group is not added when in Projector mode, since the folder
-  // selection here doesn't affect where Projector saves the videos, and hence
-  // it doesn't make sense to show this option. In this case, it remains null.
-  CaptureModeMenuGroup* save_to_menu_group_ = nullptr;
-
-  // If not set, custom folder is not set. If true, customer folder is set and
-  // available. If false, customer folder is set but unavailable.
-  absl::optional<bool> is_custom_folder_available_;
-
-  // If set, it will be called when the settings menu is refreshed.
-  base::OnceClosure on_settings_menu_refreshed_callback_for_test_;
-
-  base::WeakPtrFactory<CaptureModeAdvancedSettingsView> weak_ptr_factory_{this};
-};
-
-}  // namespace ash
-
-#endif  // ASH_CAPTURE_MODE_CAPTURE_MODE_ADVANCED_SETTINGS_VIEW_H_
diff --git a/ash/capture_mode/capture_mode_controller.cc b/ash/capture_mode/capture_mode_controller.cc
index 51ce4df3..f2aaa30 100644
--- a/ash/capture_mode/capture_mode_controller.cc
+++ b/ash/capture_mode/capture_mode_controller.cc
@@ -482,15 +482,6 @@
     return;
 
   enable_audio_recording_ = enable_audio_recording;
-
-  // TODO(conniekxu): remove all code below for this function once feature
-  // 'ImprovedScreenCaptureSettings' is fully launched.
-  // Return directly if |kImprovedScreenCaptureSettings| is enabled because for
-  // the new CaptureMode settings we don't have microphone toggle button.
-  if (features::AreImprovedScreenCaptureSettingsEnabled())
-    return;
-  DCHECK(capture_mode_session_);
-  capture_mode_session_->OnMicrophoneChanged(enable_audio_recording_);
 }
 
 void CaptureModeController::Start(CaptureModeEntryType entry_type) {
diff --git a/ash/capture_mode/capture_mode_menu_group.h b/ash/capture_mode/capture_mode_menu_group.h
index a65495af..e26edc3 100644
--- a/ash/capture_mode/capture_mode_menu_group.h
+++ b/ash/capture_mode/capture_mode_menu_group.h
@@ -94,7 +94,7 @@
   std::u16string GetOptionLabelForTesting(int option_id) const;
 
  private:
-  friend class CaptureModeAdvancedSettingsTestApi;
+  friend class CaptureModeSettingsTestApi;
 
   // Returns the option whose ID is |option_id|, and nullptr if no such option
   // exists.
@@ -104,7 +104,7 @@
   // clicked/pressed button, and unselect any previously selected button.
   void HandleOptionClick(int option_id);
 
-  // CaptureModeAdvancedSettingsView is the |delegate_| here. It's owned by
+  // CaptureModeSettingsView is the |delegate_| here. It's owned by
   // its views hierarchy.
   const Delegate* const delegate_;
 
diff --git a/ash/capture_mode/capture_mode_session.cc b/ash/capture_mode/capture_mode_session.cc
index 0cb97e8..3eacbe7 100644
--- a/ash/capture_mode/capture_mode_session.cc
+++ b/ash/capture_mode/capture_mode_session.cc
@@ -7,7 +7,6 @@
 #include "ash/accessibility/accessibility_controller_impl.h"
 #include "ash/accessibility/magnifier/magnifier_glass.h"
 #include "ash/capture_mode/capture_label_view.h"
-#include "ash/capture_mode/capture_mode_advanced_settings_view.h"
 #include "ash/capture_mode/capture_mode_bar_view.h"
 #include "ash/capture_mode/capture_mode_constants.h"
 #include "ash/capture_mode/capture_mode_controller.h"
@@ -672,7 +671,6 @@
 
   if (!shown) {
     capture_mode_settings_widget_.reset();
-    capture_mode_advanced_settings_view_ = nullptr;
     capture_mode_settings_view_ = nullptr;
     // After closing CaptureMode settings view, show CaptureLabel view if it has
     // been hidden.
@@ -684,26 +682,17 @@
   if (!capture_mode_settings_widget_) {
     auto* parent = GetParentContainer(current_root_);
     capture_mode_settings_widget_ = std::make_unique<views::Widget>();
-    if (features::AreImprovedScreenCaptureSettingsEnabled()) {
-      MaybeDismissUserNudgeForever();
+    MaybeDismissUserNudgeForever();
 
-      capture_mode_settings_widget_->Init(CreateWidgetParams(
-          parent,
-          CaptureModeAdvancedSettingsView::GetBounds(capture_mode_bar_view_),
-          "CaptureModeSettingsWidget"));
-      capture_mode_advanced_settings_view_ =
-          capture_mode_settings_widget_->SetContentsView(
-              std::make_unique<CaptureModeAdvancedSettingsView>(
-                  this, is_in_projector_mode_));
-      OnCaptureFolderMayHaveChanged();
-    } else {
-      capture_mode_settings_widget_->Init(CreateWidgetParams(
-          parent, CaptureModeSettingsView::GetBounds(capture_mode_bar_view_),
-          "CaptureModeSettingsWidget"));
-      capture_mode_settings_view_ =
-          capture_mode_settings_widget_->SetContentsView(
-              std::make_unique<CaptureModeSettingsView>(is_in_projector_mode_));
-    }
+    capture_mode_settings_widget_->Init(CreateWidgetParams(
+        parent, CaptureModeSettingsView::GetBounds(capture_mode_bar_view_),
+        "CaptureModeSettingsWidget"));
+    capture_mode_settings_view_ =
+        capture_mode_settings_widget_->SetContentsView(
+            std::make_unique<CaptureModeSettingsView>(this,
+                                                      is_in_projector_mode_));
+    OnCaptureFolderMayHaveChanged();
+
     parent->layer()->StackAtTop(capture_mode_settings_widget_->GetLayer());
     focus_cycler_->OnSettingsMenuWidgetCreated();
 
@@ -720,11 +709,6 @@
   }
 }
 
-void CaptureModeSession::OnMicrophoneChanged(bool microphone_enabled) {
-  DCHECK(capture_mode_settings_view_);
-  capture_mode_settings_view_->OnMicrophoneChanged(microphone_enabled);
-}
-
 void CaptureModeSession::ReportSessionHistograms() {
   if (controller_->source() == CaptureModeSource::kRegion) {
     RecordNumberOfCaptureRegionAdjustments(num_capture_region_adjusted_,
@@ -794,20 +778,18 @@
   if (!capture_mode_settings_widget_)
     return;
 
-  DCHECK(capture_mode_advanced_settings_view_);
-  capture_mode_advanced_settings_view_->OnCaptureFolderMayHaveChanged();
-  capture_mode_settings_widget_->SetBounds(
-      CaptureModeAdvancedSettingsView::GetBounds(
-          capture_mode_bar_view_, capture_mode_advanced_settings_view_));
+  DCHECK(capture_mode_settings_view_);
+  capture_mode_settings_view_->OnCaptureFolderMayHaveChanged();
+  capture_mode_settings_widget_->SetBounds(CaptureModeSettingsView::GetBounds(
+      capture_mode_bar_view_, capture_mode_settings_view_));
 }
 
 void CaptureModeSession::OnDefaultCaptureFolderSelectionChanged() {
   if (!capture_mode_settings_widget_)
     return;
 
-  DCHECK(capture_mode_advanced_settings_view_);
-  capture_mode_advanced_settings_view_
-      ->OnDefaultCaptureFolderSelectionChanged();
+  DCHECK(capture_mode_settings_view_);
+  capture_mode_settings_view_->OnDefaultCaptureFolderSelectionChanged();
 }
 
 void CaptureModeSession::OnPaintLayer(const ui::PaintContext& context) {
@@ -1167,9 +1149,6 @@
 void CaptureModeSession::MaybeCreateUserNudge() {
   user_nudge_controller_.reset();
 
-  if (!features::AreImprovedScreenCaptureSettingsEnabled())
-    return;
-
   if (is_in_projector_mode_)
     return;
 
diff --git a/ash/capture_mode/capture_mode_session.h b/ash/capture_mode/capture_mode_session.h
index c2db03c..fa7d18dc 100644
--- a/ash/capture_mode/capture_mode_session.h
+++ b/ash/capture_mode/capture_mode_session.h
@@ -32,7 +32,6 @@
 
 namespace ash {
 
-class CaptureModeAdvancedSettingsView;
 class CaptureModeBarView;
 class CaptureModeController;
 class CaptureModeSessionFocusCycler;
@@ -123,9 +122,6 @@
   // Called when the settings menu is toggled.
   void SetSettingsMenuShown(bool shown);
 
-  // Called when the record microphone setting is toggled.
-  void OnMicrophoneChanged(bool microphone_enabled);
-
   // Called when the user performs a capture. Records histograms related to this
   // session.
   void ReportSessionHistograms();
@@ -186,7 +182,7 @@
   void HighlightWindowForTab(aura::Window* window);
 
  private:
-  friend class CaptureModeAdvancedSettingsTestApi;
+  friend class CaptureModeSettingsTestApi;
   friend class CaptureModeSessionFocusCycler;
   friend class CaptureModeSessionTestApi;
   friend class CaptureModeTestApi;
@@ -474,12 +470,6 @@
   // The object which handles tab focus while in a capture session.
   std::unique_ptr<CaptureModeSessionFocusCycler> focus_cycler_;
 
-  // This is guarded by the |ImprovedScreenCaptureSettings| feature flag.
-  // TODO(conniekxu): remove it when the work of capture mode new settings
-  // is done.
-  CaptureModeAdvancedSettingsView* capture_mode_advanced_settings_view_ =
-      nullptr;
-
   // This helps indicating whether located events should be handled by the
   // capture mode settings menu view or the capture mode Pre-EventHandler. When
   // it's true, settings menu view should handle the event. Set it to true when
diff --git a/ash/capture_mode/capture_mode_session_focus_cycler.cc b/ash/capture_mode/capture_mode_session_focus_cycler.cc
index 2957b9f..fc683dee 100644
--- a/ash/capture_mode/capture_mode_session_focus_cycler.cc
+++ b/ash/capture_mode/capture_mode_session_focus_cycler.cc
@@ -9,12 +9,10 @@
 #include "ash/accessibility/accessibility_controller_impl.h"
 #include "ash/accessibility/magnifier/magnifier_utils.h"
 #include "ash/capture_mode/capture_label_view.h"
-#include "ash/capture_mode/capture_mode_advanced_settings_view.h"
 #include "ash/capture_mode/capture_mode_bar_view.h"
 #include "ash/capture_mode/capture_mode_button.h"
 #include "ash/capture_mode/capture_mode_controller.h"
 #include "ash/capture_mode/capture_mode_session.h"
-#include "ash/capture_mode/capture_mode_settings_entry_view.h"
 #include "ash/capture_mode/capture_mode_settings_view.h"
 #include "ash/capture_mode/capture_mode_source_view.h"
 #include "ash/capture_mode/capture_mode_toggle_button.h"
@@ -464,17 +462,10 @@
       break;
     }
     case FocusGroup::kSettingsMenu: {
-      if (features::AreImprovedScreenCaptureSettingsEnabled()) {
-        CaptureModeAdvancedSettingsView* advanced_settings_view =
-            session_->capture_mode_advanced_settings_view_;
-        DCHECK(advanced_settings_view);
-        items = advanced_settings_view->GetHighlightableItems();
-      } else {
-        CaptureModeSettingsView* settings_view =
-            session_->capture_mode_settings_view_;
-        DCHECK(settings_view);
-        items = {settings_view->microphone_view()};
-      }
+      CaptureModeSettingsView* settings_view =
+          session_->capture_mode_settings_view_;
+      DCHECK(settings_view);
+      items = settings_view->GetHighlightableItems();
       break;
     }
   }
diff --git a/ash/capture_mode/capture_mode_settings_entry_view.cc b/ash/capture_mode/capture_mode_settings_entry_view.cc
deleted file mode 100644
index 726048d..0000000
--- a/ash/capture_mode/capture_mode_settings_entry_view.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/capture_mode/capture_mode_settings_entry_view.h"
-
-#include "ash/capture_mode/capture_mode_constants.h"
-#include "ash/style/ash_color_provider.h"
-#include "base/bind.h"
-#include "base/strings/utf_string_conversions.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/metadata/metadata_impl_macros.h"
-#include "ui/gfx/paint_vector_icon.h"
-#include "ui/views/controls/button/toggle_button.h"
-#include "ui/views/controls/image_view.h"
-#include "ui/views/controls/label.h"
-#include "ui/views/layout/box_layout.h"
-
-namespace ash {
-
-namespace {
-
-constexpr gfx::Size kIconSize{20, 20};
-
-}  // namespace
-
-CaptureModeSettingsEntryView::CaptureModeSettingsEntryView(
-    views::Button::PressedCallback callback,
-    const gfx::VectorIcon& icon,
-    int string_id)
-    : icon_view_(AddChildView(std::make_unique<views::ImageView>())),
-      text_view_(AddChildView(std::make_unique<views::Label>(
-          l10n_util::GetStringUTF16(string_id)))),
-      toggle_button_view_(
-          AddChildView(std::make_unique<views::ToggleButton>(callback))) {
-  icon_view_->SetImageSize(kIconSize);
-  icon_view_->SetPreferredSize(kIconSize);
-  SetIcon(icon);
-
-  auto* color_provider = AshColorProvider::Get();
-  SkColor text_color = color_provider->GetContentLayerColor(
-      AshColorProvider::ContentLayerType::kTextColorPrimary);
-
-  text_view_->SetEnabledColor(text_color);
-  text_view_->SetBackgroundColor(SK_ColorTRANSPARENT);
-  text_view_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-
-  toggle_button_view_->SetTooltipText(l10n_util::GetStringUTF16(string_id));
-  toggle_button_view_->SetThumbOnColor(color_provider->GetContentLayerColor(
-      AshColorProvider::ContentLayerType::kSwitchKnobColorActive));
-  toggle_button_view_->SetThumbOffColor(color_provider->GetContentLayerColor(
-      AshColorProvider::ContentLayerType::kButtonIconColor));
-  toggle_button_view_->SetTrackOnColor(color_provider->GetContentLayerColor(
-      AshColorProvider::ContentLayerType::kSwitchTrackColorActive));
-  toggle_button_view_->SetTrackOffColor(color_provider->GetContentLayerColor(
-      AshColorProvider::ContentLayerType::kSwitchTrackColorInactive));
-
-  auto* box_layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
-      views::BoxLayout::Orientation::kHorizontal, gfx::Insets(),
-      capture_mode::kBetweenChildSpacing));
-  box_layout->set_cross_axis_alignment(
-      views::BoxLayout::CrossAxisAlignment::kCenter);
-  box_layout->SetFlexForView(text_view_, 1);
-}
-
-CaptureModeSettingsEntryView::~CaptureModeSettingsEntryView() = default;
-
-void CaptureModeSettingsEntryView::SetIcon(const gfx::VectorIcon& icon) {
-  icon_view_->SetImage(gfx::CreateVectorIcon(
-      icon, AshColorProvider::Get()->GetContentLayerColor(
-                AshColorProvider::ContentLayerType::kButtonIconColor)));
-}
-
-views::View* CaptureModeSettingsEntryView::GetView() {
-  return toggle_button_view_;
-}
-
-BEGIN_METADATA(CaptureModeSettingsEntryView, views::View)
-END_METADATA
-
-}  // namespace ash
diff --git a/ash/capture_mode/capture_mode_settings_entry_view.h b/ash/capture_mode/capture_mode_settings_entry_view.h
deleted file mode 100644
index 4c5d7dd..0000000
--- a/ash/capture_mode/capture_mode_settings_entry_view.h
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_CAPTURE_MODE_CAPTURE_MODE_SETTINGS_ENTRY_VIEW_H_
-#define ASH_CAPTURE_MODE_CAPTURE_MODE_SETTINGS_ENTRY_VIEW_H_
-
-#include "ash/ash_export.h"
-#include "ash/capture_mode/capture_mode_session_focus_cycler.h"
-#include "ui/base/metadata/metadata_header_macros.h"
-#include "ui/views/controls/button/button.h"
-#include "ui/views/view.h"
-
-namespace gfx {
-struct VectorIcon;
-}  // namespace gfx
-
-namespace views {
-class ImageView;
-class Label;
-class ToggleButton;
-}  // namespace views
-
-namespace ash {
-
-// A view that is part of the Settings Bar view, from which the user can toggle
-// each of the settings on/off.
-class ASH_EXPORT CaptureModeSettingsEntryView
-    : public views::View,
-      public CaptureModeSessionFocusCycler::HighlightableView {
- public:
-  METADATA_HEADER(CaptureModeSettingsEntryView);
-
-  CaptureModeSettingsEntryView(views::Button::PressedCallback callback,
-                               const gfx::VectorIcon& icon,
-                               int string_id);
-  CaptureModeSettingsEntryView(const CaptureModeSettingsEntryView&) = delete;
-  CaptureModeSettingsEntryView& operator=(const CaptureModeSettingsEntryView&) =
-      delete;
-  ~CaptureModeSettingsEntryView() override;
-
-  views::ToggleButton* toggle_button_view() const {
-    return toggle_button_view_;
-  }
-
-  void SetIcon(const gfx::VectorIcon& icon);
-
-  // CaptureModeSessionFocusCycler::HighlightableView:
-  views::View* GetView() override;
-
- private:
-  // Owned by the views hierarchy.
-  views::ImageView* icon_view_ = nullptr;
-  views::Label* text_view_ = nullptr;
-  views::ToggleButton* toggle_button_view_ = nullptr;
-};
-
-}  // namespace ash
-
-#endif  // ASH_CAPTURE_MODE_CAPTURE_MODE_SETTINGS_ENTRY_VIEW_H_
diff --git a/ash/capture_mode/capture_mode_settings_test_api.cc b/ash/capture_mode/capture_mode_settings_test_api.cc
new file mode 100644
index 0000000..0677022
--- /dev/null
+++ b/ash/capture_mode/capture_mode_settings_test_api.cc
@@ -0,0 +1,68 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/capture_mode/capture_mode_settings_test_api.h"
+
+#include "ash/capture_mode/capture_mode_controller.h"
+#include "ash/capture_mode/capture_mode_session.h"
+#include "ash/capture_mode/capture_mode_settings_view.h"
+#include "ash/constants/ash_features.h"
+#include "base/check.h"
+
+namespace ash {
+
+namespace {
+
+CaptureModeSession* GetCaptureModeSession() {
+  auto* controller = CaptureModeController::Get();
+  DCHECK(controller->IsActive());
+  CaptureModeSession* session = controller->capture_mode_session();
+  DCHECK(session->capture_mode_settings_widget());
+  return session;
+}
+
+}  // namespace
+
+CaptureModeSettingsTestApi::CaptureModeSettingsTestApi()
+    : settings_view_(GetCaptureModeSession()->capture_mode_settings_view_) {}
+
+CaptureModeSettingsView* CaptureModeSettingsTestApi::GetSettingsView() {
+  return settings_view_;
+}
+
+CaptureModeMenuGroup* CaptureModeSettingsTestApi::GetAudioInputMenuGroup() {
+  return settings_view_->audio_input_menu_group_;
+}
+
+views::View* CaptureModeSettingsTestApi::GetMicrophoneOption() {
+  return GetAudioInputMenuGroup()->GetOptionForTesting(kAudioMicrophone);
+}
+
+views::View* CaptureModeSettingsTestApi::GetAudioOffOption() {
+  return GetAudioInputMenuGroup()->GetOptionForTesting(kAudioOff);
+}
+
+CaptureModeMenuGroup* CaptureModeSettingsTestApi::GetSaveToMenuGroup() {
+  return settings_view_->save_to_menu_group_;
+}
+
+views::View* CaptureModeSettingsTestApi::GetDefaultDownloadsOption() {
+  return GetSaveToMenuGroup()->GetOptionForTesting(kDownloadsFolder);
+}
+
+views::View* CaptureModeSettingsTestApi::GetCustomFolderOptionIfAny() {
+  return GetSaveToMenuGroup()->GetOptionForTesting(kCustomFolder);
+}
+
+views::View* CaptureModeSettingsTestApi::GetSelectFolderMenuItem() {
+  return GetSaveToMenuGroup()->GetSelectFolderMenuItemForTesting();
+}
+
+void CaptureModeSettingsTestApi::SetOnSettingsMenuRefreshedCallback(
+    base::OnceClosure callback) {
+  settings_view_->on_settings_menu_refreshed_callback_for_test_ =
+      std::move(callback);
+}
+
+}  // namespace ash
diff --git a/ash/capture_mode/capture_mode_settings_test_api.h b/ash/capture_mode/capture_mode_settings_test_api.h
new file mode 100644
index 0000000..7c88880
--- /dev/null
+++ b/ash/capture_mode/capture_mode_settings_test_api.h
@@ -0,0 +1,56 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_CAPTURE_MODE_CAPTURE_MODE_SETTINGS_TEST_API_H_
+#define ASH_CAPTURE_MODE_CAPTURE_MODE_SETTINGS_TEST_API_H_
+
+#include "base/callback_forward.h"
+
+namespace views {
+class View;
+}  // namespace views
+
+namespace ash {
+
+class CaptureModeSettingsView;
+class CaptureModeMenuGroup;
+
+// Test APIs to test the UI of the settings menu. Can only be created
+// while a capture mode session is active, and the settings menu is shown.
+class CaptureModeSettingsTestApi {
+ public:
+  CaptureModeSettingsTestApi();
+  CaptureModeSettingsTestApi(const CaptureModeSettingsTestApi&) = delete;
+  CaptureModeSettingsTestApi& operator=(const CaptureModeSettingsTestApi&) =
+      delete;
+  ~CaptureModeSettingsTestApi() = default;
+
+  // Returns the content view of the settings widget.
+  CaptureModeSettingsView* GetSettingsView();
+
+  // Returns the audio settings menu group and the views for its options.
+  CaptureModeMenuGroup* GetAudioInputMenuGroup();
+  views::View* GetMicrophoneOption();
+  views::View* GetAudioOffOption();
+
+  // Returns the save-to settings menu group and the views for its options.
+  CaptureModeMenuGroup* GetSaveToMenuGroup();
+  views::View* GetDefaultDownloadsOption();
+  views::View* GetCustomFolderOptionIfAny();
+
+  // Returns the view for the "Select folder" menu item which when pressed would
+  // open the folder selection dialog.
+  views::View* GetSelectFolderMenuItem();
+
+  // Sets a callback that will be triggered once the settings menu is refreshed.
+  void SetOnSettingsMenuRefreshedCallback(base::OnceClosure callback);
+
+ private:
+  // Valid only while the settings menu is shown.
+  CaptureModeSettingsView* const settings_view_;
+};
+
+}  // namespace ash
+
+#endif  // ASH_CAPTURE_MODE_CAPTURE_MODE_SETTINGS_TEST_API_H_
diff --git a/ash/capture_mode/capture_mode_settings_view.cc b/ash/capture_mode/capture_mode_settings_view.cc
index f2a305fe..89b6b11 100644
--- a/ash/capture_mode/capture_mode_settings_view.cc
+++ b/ash/capture_mode/capture_mode_settings_view.cc
@@ -4,70 +4,41 @@
 
 #include "ash/capture_mode/capture_mode_settings_view.h"
 
+#include <memory>
+#include <string>
+
 #include "ash/capture_mode/capture_mode_bar_view.h"
 #include "ash/capture_mode/capture_mode_constants.h"
 #include "ash/capture_mode/capture_mode_controller.h"
-#include "ash/capture_mode/capture_mode_settings_entry_view.h"
+#include "ash/capture_mode/capture_mode_metrics.h"
+#include "ash/capture_mode/capture_mode_session.h"
 #include "ash/capture_mode/capture_mode_toggle_button.h"
-#include "ash/public/cpp/style/color_provider.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/ash_color_provider.h"
 #include "base/bind.h"
-#include "ui/accessibility/ax_enums.mojom.h"
+#include "base/files/file_path.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/compositor/layer.h"
+#include "ui/gfx/geometry/rect.h"
 #include "ui/views/background.h"
-#include "ui/views/controls/button/toggle_button.h"
+#include "ui/views/controls/separator.h"
 #include "ui/views/layout/box_layout.h"
-#include "ui/views/style/platform_style.h"
 
 namespace ash {
 
 namespace {
 
-constexpr gfx::Size kSettingsSize{256, 52};
-
-constexpr gfx::Insets kSettingsPadding{/*vertical=*/16, /*horizontal=*/16};
+constexpr gfx::Size kSettingsSize{256, 248};
 
 constexpr gfx::RoundedCornersF kBorderRadius{10.f};
 
-}  // namespace
-
-CaptureModeSettingsView::CaptureModeSettingsView(bool projector_mode)
-    : microphone_view_(
-          AddChildView(std::make_unique<CaptureModeSettingsEntryView>(
-              base::BindRepeating(&CaptureModeSettingsView::OnMicrophoneToggled,
-                                  base::Unretained(this)),
-              kCaptureModeMicOffIcon,
-              IDS_ASH_SCREEN_CAPTURE_LABEL_MICROPHONE))) {
-  // Users are not allowed to disable audio recording when in a projector mode
-  // session.
-  microphone_view_->toggle_button_view()->SetEnabled(!projector_mode);
-
-  SetPaintToLayer();
-  auto* color_provider = AshColorProvider::Get();
-  SkColor background_color = color_provider->GetBaseLayerColor(
-      AshColorProvider::BaseLayerType::kTransparent80);
-  SetBackground(views::CreateSolidBackground(background_color));
-  layer()->SetFillsBoundsOpaquely(false);
-  layer()->SetRoundedCornerRadius(kBorderRadius);
-  layer()->SetBackgroundBlur(ColorProvider::kBackgroundBlurSigma);
-  layer()->SetBackdropFilterQuality(ColorProvider::kBackgroundBlurQuality);
-
-  SetLayoutManager(std::make_unique<views::BoxLayout>(
-      views::BoxLayout::Orientation::kVertical, kSettingsPadding,
-      capture_mode::kBetweenChildSpacing));
-
-  OnMicrophoneChanged(CaptureModeController::Get()->enable_audio_recording());
-}
-
-CaptureModeSettingsView::~CaptureModeSettingsView() = default;
-
-// static
-gfx::Rect CaptureModeSettingsView::GetBounds(
-    CaptureModeBarView* capture_mode_bar_view) {
+// Returns the bounds of the settings widget in screen coordinates relative to
+// the bounds of the |capture_mode_bar_view| based on its given preferred
+// |settings_view_size|.
+gfx::Rect GetWidgetBounds(CaptureModeBarView* capture_mode_bar_view,
+                          const gfx::Size& settings_view_size) {
   DCHECK(capture_mode_bar_view);
 
   return gfx::Rect(
@@ -75,27 +46,206 @@
           kSettingsSize.width(),
       capture_mode_bar_view->GetBoundsInScreen().y() -
           capture_mode::kSpaceBetweenCaptureBarAndSettingsMenu -
-          kSettingsSize.height(),
-      kSettingsSize.width(), kSettingsSize.height());
+          settings_view_size.height(),
+      kSettingsSize.width(), settings_view_size.height());
 }
 
-void CaptureModeSettingsView::OnMicrophoneChanged(bool microphone_enabled) {
-  microphone_view_->toggle_button_view()->SetIsOn(microphone_enabled);
-  microphone_view_->SetIcon(microphone_enabled ? kCaptureModeMicIcon
-                                               : kCaptureModeMicOffIcon);
-
-  // This view's widget is not activatable, so `this` will not get true focus.
-  // For spoken feedback to say the correct thing, we need to manually notify.
-  microphone_view_->toggle_button_view()->NotifyAccessibilityEvent(
-      ax::mojom::Event::kCheckedStateChanged, true);
+CaptureModeController::CaptureFolder GetCurrentCaptureFolder() {
+  return CaptureModeController::Get()->GetCurrentCaptureFolder();
 }
 
-void CaptureModeSettingsView::OnMicrophoneToggled() {
-  CaptureModeController::Get()->EnableAudioRecording(
-      microphone_view_->toggle_button_view()->GetIsOn());
+}  // namespace
+
+CaptureModeSettingsView::CaptureModeSettingsView(CaptureModeSession* session,
+                                                 bool is_in_projector_mode)
+    : capture_mode_session_(session),
+      audio_input_menu_group_(
+          AddChildView(std::make_unique<CaptureModeMenuGroup>(
+              this,
+              kCaptureModeMicIcon,
+              l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_AUDIO_INPUT)))) {
+  if (!is_in_projector_mode) {
+    audio_input_menu_group_->AddOption(
+        l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_AUDIO_INPUT_OFF),
+        kAudioOff);
+  }
+  audio_input_menu_group_->AddOption(
+      l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_AUDIO_INPUT_MICROPHONE),
+      kAudioMicrophone);
+
+  auto* color_provider = AshColorProvider::Get();
+  if (!is_in_projector_mode) {
+    separator_ = AddChildView(std::make_unique<views::Separator>());
+
+    save_to_menu_group_ = AddChildView(std::make_unique<CaptureModeMenuGroup>(
+        this, kCaptureModeFolderIcon,
+        l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_SAVE_TO)));
+    save_to_menu_group_->AddOption(
+        l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_SAVE_TO_DOWNLOADS),
+        kDownloadsFolder);
+    save_to_menu_group_->AddMenuItem(
+        base::BindRepeating(
+            &CaptureModeSettingsView::OnSelectFolderMenuItemPressed,
+            base::Unretained(this)),
+        l10n_util::GetStringUTF16(
+            IDS_ASH_SCREEN_CAPTURE_SAVE_TO_SELECT_FOLDER));
+
+    const SkColor separator_color = color_provider->GetContentLayerColor(
+        AshColorProvider::ContentLayerType::kSeparatorColor);
+    separator_->SetColor(separator_color);
+  }
+
+  SetPaintToLayer();
+  SetBackground(views::CreateSolidBackground(color_provider->GetBaseLayerColor(
+      AshColorProvider::BaseLayerType::kTransparent80)));
+  layer()->SetFillsBoundsOpaquely(false);
+  layer()->SetRoundedCornerRadius(kBorderRadius);
+  layer()->SetBackgroundBlur(ColorProvider::kBackgroundBlurSigma);
+  layer()->SetBackdropFilterQuality(ColorProvider::kBackgroundBlurQuality);
+
+  SetLayoutManager(std::make_unique<views::BoxLayout>(
+      views::BoxLayout::Orientation::kVertical));
+}
+
+CaptureModeSettingsView::~CaptureModeSettingsView() = default;
+
+gfx::Rect CaptureModeSettingsView::GetBounds(
+    CaptureModeBarView* capture_mode_bar_view,
+    CaptureModeSettingsView* content_view) {
+  DCHECK(capture_mode_bar_view);
+
+  const gfx::Size settings_size =
+      content_view ? content_view->GetPreferredSize() : kSettingsSize;
+  return GetWidgetBounds(capture_mode_bar_view, settings_size);
+}
+
+void CaptureModeSettingsView::OnCaptureFolderMayHaveChanged() {
+  if (!save_to_menu_group_)
+    return;
+  auto* controller = CaptureModeController::Get();
+  const auto custom_path = controller->GetCustomCaptureFolder();
+  if (custom_path.empty()) {
+    is_custom_folder_available_.reset();
+    save_to_menu_group_->RemoveOptionIfAny(kCustomFolder);
+    save_to_menu_group_->RefreshOptionsSelections();
+    return;
+  }
+
+  std::u16string folder_name = custom_path.BaseName().AsUTF16Unsafe();
+  // We explicitly name the folders of Google Drive and Play files, since those
+  // folders internally may have user-unfriendly names.
+  if (controller->IsRootDriveFsPath(custom_path)) {
+    folder_name =
+        l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_SAVE_TO_GOOGLE_DRIVE);
+  } else if (controller->IsAndroidFilesPath(custom_path)) {
+    folder_name =
+        l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_SAVE_TO_ANDROID_FILES);
+  }
+
+  save_to_menu_group_->AddOrUpdateExistingOption(folder_name, kCustomFolder);
+
+  controller->CheckFolderAvailability(
+      custom_path,
+      base::BindOnce(
+          &CaptureModeSettingsView::OnCustomFolderAvailabilityChecked,
+          weak_ptr_factory_.GetWeakPtr()));
+}
+
+void CaptureModeSettingsView::OnDefaultCaptureFolderSelectionChanged() {
+  if (save_to_menu_group_)
+    save_to_menu_group_->RefreshOptionsSelections();
+}
+
+std::vector<CaptureModeSessionFocusCycler::HighlightableView*>
+CaptureModeSettingsView::GetHighlightableItems() {
+  std::vector<CaptureModeSessionFocusCycler::HighlightableView*>
+      highlightable_items;
+  DCHECK(audio_input_menu_group_);
+  audio_input_menu_group_->AppendHighlightableItems(highlightable_items);
+  if (save_to_menu_group_)
+    save_to_menu_group_->AppendHighlightableItems(highlightable_items);
+  return highlightable_items;
+}
+
+void CaptureModeSettingsView::OnOptionSelected(int option_id) const {
+  auto* controller = CaptureModeController::Get();
+  switch (option_id) {
+    case kAudioOff:
+      controller->EnableAudioRecording(false);
+      break;
+    case kAudioMicrophone:
+      controller->EnableAudioRecording(true);
+      break;
+    case kDownloadsFolder:
+      controller->SetUsesDefaultCaptureFolder(true);
+      RecordSwitchToDefaultFolderReason(
+          CaptureModeSwitchToDefaultReason::kUserSelectedFromSettingsMenu);
+      break;
+    case kCustomFolder:
+      controller->SetUsesDefaultCaptureFolder(false);
+      break;
+    default:
+      return;
+  }
+}
+
+bool CaptureModeSettingsView::IsOptionChecked(int option_id) const {
+  switch (option_id) {
+    case kAudioOff:
+      return !CaptureModeController::Get()->enable_audio_recording();
+    case kAudioMicrophone:
+      return CaptureModeController::Get()->enable_audio_recording();
+    case kDownloadsFolder:
+      return GetCurrentCaptureFolder().is_default_downloads_folder ||
+             !is_custom_folder_available_.value_or(false);
+    case kCustomFolder:
+      return !GetCurrentCaptureFolder().is_default_downloads_folder &&
+             is_custom_folder_available_.value_or(false);
+    default:
+      return false;
+  }
+}
+
+bool CaptureModeSettingsView::IsOptionEnabled(int option_id) const {
+  switch (option_id) {
+    case kAudioOff:
+      return !capture_mode_session_->is_in_projector_mode();
+    case kCustomFolder:
+      return is_custom_folder_available_.value_or(false);
+    case kAudioMicrophone:
+    case kDownloadsFolder:
+    default:
+      return true;
+  }
+}
+
+views::View* CaptureModeSettingsView::GetMicrophoneOptionForTesting() {
+  return audio_input_menu_group_->GetOptionForTesting(  // IN-TEST
+      kAudioMicrophone);                                // IN-TEST
+}
+
+views::View* CaptureModeSettingsView::GetOffOptionForTesting() {
+  return audio_input_menu_group_->GetOptionForTesting(kAudioOff);  // IN-TEST
+}
+
+void CaptureModeSettingsView::OnSelectFolderMenuItemPressed() {
+  capture_mode_session_->OpenFolderSelectionDialog();
+}
+
+void CaptureModeSettingsView::OnCustomFolderAvailabilityChecked(
+    bool available) {
+  DCHECK(save_to_menu_group_);
+  is_custom_folder_available_ = available;
+  save_to_menu_group_->RefreshOptionsSelections();
+  if (!is_custom_folder_available_.value_or(false)) {
+    RecordSwitchToDefaultFolderReason(
+        CaptureModeSwitchToDefaultReason::kFolderUnavailable);
+  }
+  if (on_settings_menu_refreshed_callback_for_test_)
+    std::move(on_settings_menu_refreshed_callback_for_test_).Run();
 }
 
 BEGIN_METADATA(CaptureModeSettingsView, views::View)
 END_METADATA
 
-}  // namespace ash
+}  // namespace ash
\ No newline at end of file
diff --git a/ash/capture_mode/capture_mode_settings_view.h b/ash/capture_mode/capture_mode_settings_view.h
index f8779e4..7b23856 100644
--- a/ash/capture_mode/capture_mode_settings_view.h
+++ b/ash/capture_mode/capture_mode_settings_view.h
@@ -6,59 +6,125 @@
 #define ASH_CAPTURE_MODE_CAPTURE_MODE_SETTINGS_VIEW_H_
 
 #include "ash/ash_export.h"
+#include "ash/capture_mode/capture_mode_menu_group.h"
+#include "ash/capture_mode/capture_mode_session_focus_cycler.h"
+#include "base/callback_forward.h"
 #include "ui/base/metadata/metadata_header_macros.h"
-#include "ui/views/controls/button/toggle_button.h"
-#include "ui/views/controls/image_view.h"
 #include "ui/views/view.h"
 
+namespace views {
+class Separator;
+}  // namespace views
+
 namespace ash {
 
 class CaptureModeBarView;
-class CaptureModeSettingsEntryView;
+class CaptureModeMenuGroup;
+class CaptureModeSession;
+
+// All the options in the CaptureMode settings view.
+enum CaptureSettingsOption {
+  kAudioOff = 0,
+  kAudioMicrophone,
+  kDownloadsFolder,
+  kCustomFolder,
+};
 
 // A view that acts as the content view of the capture mode settings menu
-// widget. It has settings entries, starting with a microphone toggle. The
-// structure looks like this:
-//
-//   +-----------------------------------------------------------+
-//   |  +-----------------------------------------------------+  |
-//   |  |  +---+  +------------------------------+  +------+  |  |
-//   |  |  |   |  |                              |  |      |  |  |
-//   |  |  +---+  +------------------------------+  +------+  |  |
-//   |  +-----------------------------------------------------+  |
-//   +--^--------------------------------------------------------+
-//   ^  |
-//   |  CaptureModeSettingsEntryView
-//   |
-//   CaptureModeSettingsView
-//
-class ASH_EXPORT CaptureModeSettingsView : public views::View {
+// widget. It is the content view of settings widget and it contains
+// `CaptureModeMenuGroup` for each setting, save to, audio input etc.
+class ASH_EXPORT CaptureModeSettingsView
+    : public views::View,
+      public CaptureModeMenuGroup::Delegate {
  public:
   METADATA_HEADER(CaptureModeSettingsView);
 
-  // |projector_mode| specifies whether the current capture mode session was
-  // started for the projector workflow. In this mode, only a limited set of
-  // capture mode settings are exposed to the user.
-  explicit CaptureModeSettingsView(bool projector_mode);
+  CaptureModeSettingsView(CaptureModeSession* session,
+                          bool is_in_projector_mode);
   CaptureModeSettingsView(const CaptureModeSettingsView&) = delete;
   CaptureModeSettingsView& operator=(const CaptureModeSettingsView&) = delete;
   ~CaptureModeSettingsView() override;
 
-  CaptureModeSettingsEntryView* microphone_view() const {
-    return microphone_view_;
-  }
-
   // Gets the ideal bounds in screen coordinates of the settings widget on
-  // the given |capture_mode_bar_view|.
-  static gfx::Rect GetBounds(CaptureModeBarView* capture_mode_bar_view);
+  // the given |capture_mode_bar_view|. If |content_view| is not null, it will
+  // be used to get the preferred size to calculate the final bounds. Otherwise,
+  // a default size will be used.
+  static gfx::Rect GetBounds(CaptureModeBarView* capture_mode_bar_view,
+                             CaptureModeSettingsView* content_view = nullptr);
 
-  // Called when the settings change.
-  void OnMicrophoneChanged(bool microphone_enabled);
+  // Called when the folder, in which the captured files will be saved, may have
+  // changed. This may result in adding or removing a menu option for the folder
+  // that was added or removed. This means that the preferred size of this view
+  // can possibly change, and therefore it's the responsibility of the caller to
+  // to set the proper bounds on the widget.
+  void OnCaptureFolderMayHaveChanged();
+
+  // Called when we change the setting to force-use the default downloads folder
+  // as the save folder. This results in updating which folder menu option is
+  // currently selected.
+  void OnDefaultCaptureFolderSelectionChanged();
+
+  // Gets the highlightable `CaptureModeOption` and `CaptureModeMenuItem` inside
+  // this view.
+  std::vector<CaptureModeSessionFocusCycler::HighlightableView*>
+  GetHighlightableItems();
+
+  // CaptureModeMenuGroup::Delegate:
+  void OnOptionSelected(int option_id) const override;
+  bool IsOptionChecked(int option_id) const override;
+  bool IsOptionEnabled(int option_id) const override;
+
+  // For tests only:
+  CaptureModeMenuGroup* GetAudioInputMenuGroupForTesting() {
+    return audio_input_menu_group_;
+  }
+  views::View* GetMicrophoneOptionForTesting();
+  views::View* GetOffOptionForTesting();
 
  private:
-  void OnMicrophoneToggled();
+  friend class CaptureModeSettingsTestApi;
 
-  CaptureModeSettingsEntryView* microphone_view_;
+  // Called when the "Select folder" menu item in the |save_to_menu_group_| is
+  // pressed. It opens the folder selection dialog so that user can pick a
+  // location in which captured files will be saved.
+  void OnSelectFolderMenuItemPressed();
+
+  // Called back when the check for custom folder's availability is done, with
+  // `available` indicating whether the custom folder is available or not. We
+  // will check the custom folder's availability every time when
+  // `OnCaptureFolderMayHaveChanged` is triggered and custom folder is not
+  // empty.
+  void OnCustomFolderAvailabilityChecked(bool available);
+
+  // A reference to the session that owns this view indirectly by owning its
+  // containing widget.
+  CaptureModeSession* const capture_mode_session_;  // Not null;
+
+  // "Audio input" menu group that users can select an audio input from for
+  // screen capture recording. It has "Off" and "Microphone" options for now.
+  // "Off" is the default one which means no audio input selected.
+  CaptureModeMenuGroup* audio_input_menu_group_;
+
+  // Can be null when in Projector mode, since then it's not needed as the
+  // "Save-to" menu group will not be added at all.
+  views::Separator* separator_ = nullptr;
+
+  // "Save to" menu group that users can select a folder to save the captured
+  // files to. It will include the "Downloads" folder as the default one and
+  // one more folder selected by users.
+  // This menu group is not added when in Projector mode, since the folder
+  // selection here doesn't affect where Projector saves the videos, and hence
+  // it doesn't make sense to show this option. In this case, it remains null.
+  CaptureModeMenuGroup* save_to_menu_group_ = nullptr;
+
+  // If not set, custom folder is not set. If true, customer folder is set and
+  // available. If false, customer folder is set but unavailable.
+  absl::optional<bool> is_custom_folder_available_;
+
+  // If set, it will be called when the settings menu is refreshed.
+  base::OnceClosure on_settings_menu_refreshed_callback_for_test_;
+
+  base::WeakPtrFactory<CaptureModeSettingsView> weak_ptr_factory_{this};
 };
 
 }  // namespace ash
diff --git a/ash/capture_mode/capture_mode_unittests.cc b/ash/capture_mode/capture_mode_unittests.cc
index c23087b..b809cd9 100644
--- a/ash/capture_mode/capture_mode_unittests.cc
+++ b/ash/capture_mode/capture_mode_unittests.cc
@@ -10,8 +10,6 @@
 #include "ash/accessibility/magnifier/magnifier_glass.h"
 #include "ash/app_list/app_list_controller_impl.h"
 #include "ash/capture_mode/capture_label_view.h"
-#include "ash/capture_mode/capture_mode_advanced_settings_test_api.h"
-#include "ash/capture_mode/capture_mode_advanced_settings_view.h"
 #include "ash/capture_mode/capture_mode_bar_view.h"
 #include "ash/capture_mode/capture_mode_button.h"
 #include "ash/capture_mode/capture_mode_constants.h"
@@ -19,7 +17,7 @@
 #include "ash/capture_mode/capture_mode_menu_group.h"
 #include "ash/capture_mode/capture_mode_metrics.h"
 #include "ash/capture_mode/capture_mode_session.h"
-#include "ash/capture_mode/capture_mode_settings_entry_view.h"
+#include "ash/capture_mode/capture_mode_settings_test_api.h"
 #include "ash/capture_mode/capture_mode_settings_view.h"
 #include "ash/capture_mode/capture_mode_source_view.h"
 #include "ash/capture_mode/capture_mode_toggle_button.h"
@@ -301,11 +299,6 @@
     return session_->capture_mode_settings_view_;
   }
 
-  CaptureModeAdvancedSettingsView* capture_mode_advanced_settings_view() const {
-    EXPECT_TRUE(features::AreImprovedScreenCaptureSettingsEnabled());
-    return session_->capture_mode_advanced_settings_view_;
-  }
-
   views::Widget* capture_mode_settings_widget() const {
     return session_->capture_mode_settings_widget_.get();
   }
@@ -455,15 +448,6 @@
     return GetCaptureModeBarView()->close_button();
   }
 
-  views::ToggleButton* GetMicrophoneToggle() const {
-    auto* controller = CaptureModeController::Get();
-    DCHECK(controller->IsActive());
-    DCHECK(GetCaptureModeSettingsView());
-    return GetCaptureModeSettingsView()
-        ->microphone_view()
-        ->toggle_button_view();
-  }
-
   aura::Window* GetDimensionsLabelWindow() const {
     auto* controller = CaptureModeController::Get();
     DCHECK(controller->IsActive());
@@ -1784,14 +1768,15 @@
   // Use image capture icon as the mouse cursor icon in image capture mode.
   const ui::Cursor landscape_cursor = cursor_manager->GetCursor();
   EXPECT_EQ(CursorType::kCustom, landscape_cursor.type());
-  CaptureModeSessionTestApi test_api(controller->capture_mode_session());
-  EXPECT_TRUE(test_api.IsUsingCustomCursor(CaptureModeType::kImage));
+  CaptureModeSessionTestApi session_test_api(
+      controller->capture_mode_session());
+  EXPECT_TRUE(session_test_api.IsUsingCustomCursor(CaptureModeType::kImage));
 
   // Rotate the screen.
   orientation_test_api.SetDisplayRotation(
       display::Display::ROTATE_270, display::Display::RotationSource::ACTIVE);
   const ui::Cursor portrait_cursor = cursor_manager->GetCursor();
-  EXPECT_TRUE(test_api.IsUsingCustomCursor(CaptureModeType::kImage));
+  EXPECT_TRUE(session_test_api.IsUsingCustomCursor(CaptureModeType::kImage));
   EXPECT_NE(landscape_cursor, portrait_cursor);
 }
 
@@ -3686,59 +3671,6 @@
   EXPECT_FALSE(controller->IsActive());
 }
 
-TEST_F(CaptureModeTest, KeyboardNavigationSettingsMenuBehavior) {
-  // This test is specific to the old settings view.
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndDisableFeature(
-      features::kImprovedScreenCaptureSettings);
-
-  using FocusGroup = CaptureModeSessionFocusCycler::FocusGroup;
-
-  // Use window capture mode to avoid having to tab through the selection
-  // region.
-  auto* controller =
-      StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kImage);
-  auto* event_generator = GetEventGenerator();
-
-  // Tests that pressing tab closes the settings menu if it was opened with a
-  // button click.
-  ClickOnView(GetSettingsButton(), event_generator);
-  ASSERT_TRUE(GetCaptureModeSettingsWidget());
-  SendKey(ui::VKEY_TAB, event_generator);
-  EXPECT_FALSE(GetCaptureModeSettingsWidget());
-
-  // Tab until we reach the settings button and press space to open the settings
-  // menu.
-  SendKey(ui::VKEY_TAB, event_generator, /*shift_down=*/false, 6);
-  CaptureModeSessionTestApi test_api(controller->capture_mode_session());
-  ASSERT_EQ(FocusGroup::kSettingsClose, test_api.GetCurrentFocusGroup());
-  ASSERT_EQ(0u, test_api.GetCurrentFocusIndex());
-  SendKey(ui::VKEY_SPACE, event_generator);
-  ASSERT_TRUE(GetCaptureModeSettingsWidget());
-
-  // Verify that at this point, the focus cycler is in a pending state.
-  EXPECT_EQ(FocusGroup::kPendingSettings, test_api.GetCurrentFocusGroup());
-  EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
-
-  // The next tab should focus the microphone settings entry. Pressing space
-  // should toggle the setting.
-  SendKey(ui::VKEY_TAB, event_generator);
-  ASSERT_FALSE(controller->enable_audio_recording());
-  SendKey(ui::VKEY_SPACE, event_generator);
-  EXPECT_TRUE(controller->enable_audio_recording());
-
-  // Tests that the next tab will keep the menu open and move focus to the
-  // settings button.
-  SendKey(ui::VKEY_TAB, event_generator);
-  EXPECT_TRUE(GetCaptureModeSettingsWidget());
-  EXPECT_EQ(FocusGroup::kSettingsClose, test_api.GetCurrentFocusGroup());
-  EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
-
-  // Tests that pressing escape will close the menu and clear focus.
-  SendKey(ui::VKEY_ESCAPE, event_generator);
-  EXPECT_FALSE(GetCaptureModeSettingsWidget());
-}
-
 // Tests that functionality to create and adjust a region with keyboard
 // shortcuts works as intended.
 TEST_F(CaptureModeTest, KeyboardNavigationSelectRegion) {
@@ -4159,24 +4091,20 @@
 // the bar/menu, on other buttons) affects whether the settings menu should
 // close or not.
 TEST_F(CaptureModeTest, SettingsMenuVisibilityClicking) {
-  // This test is specific to the old settings view.
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndDisableFeature(
-      features::kImprovedScreenCaptureSettings);
-
   UpdateDisplay("800x700");
 
   auto* event_generator = GetEventGenerator();
   auto* controller = StartImageRegionCapture();
   EXPECT_TRUE(controller->IsActive());
 
-  // Test clicking on the settings menu and toggling settings doesn't close the
+  // Test clicking on the option of settings menu doesn't close the
   // settings menu.
   ClickOnView(GetSettingsButton(), event_generator);
   ClickOnView(GetCaptureModeSettingsView(), event_generator);
   EXPECT_TRUE(GetCaptureModeSettingsWidget());
   EXPECT_TRUE(GetSettingsButton()->GetToggled());
-  ClickOnView(GetMicrophoneToggle(), event_generator);
+  CaptureModeSettingsTestApi test_api;
+  ClickOnView(test_api.GetAudioOffOption(), event_generator);
   EXPECT_TRUE(GetCaptureModeSettingsWidget());
   EXPECT_TRUE(GetSettingsButton()->GetToggled());
 
@@ -4216,11 +4144,6 @@
 
 // Tests the settings menu functionality when in region mode.
 TEST_F(CaptureModeTest, SettingsMenuVisibilityDrawingRegion) {
-  // This test is specific to the old settings view.
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndDisableFeature(
-      features::kImprovedScreenCaptureSettings);
-
   UpdateDisplay("800x700");
 
   auto* event_generator = GetEventGenerator();
@@ -4273,37 +4196,6 @@
   EXPECT_FALSE(GetCaptureModeSettingsWidget());
 }
 
-// Tests that toggling the microphone setting updates the state in the
-// controller, and persists between sessions.
-TEST_F(CaptureModeTest, AudioRecordingSetting) {
-  // This test is specific to the old settings view.
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndDisableFeature(
-      features::kImprovedScreenCaptureSettings);
-
-  auto* controller = StartImageRegionCapture();
-  auto* event_generator = GetEventGenerator();
-
-  // Test that the audio recording preference is defaulted to false, so the
-  // toggle should start in the off position.
-  EXPECT_FALSE(controller->enable_audio_recording());
-
-  // Test that toggling on the micophone updates the preference in the
-  // controller, as well as displaying the toggle as on.
-  ClickOnView(GetSettingsButton(), event_generator);
-  EXPECT_FALSE(GetMicrophoneToggle()->GetIsOn());
-  ClickOnView(GetMicrophoneToggle(), event_generator);
-  EXPECT_TRUE(controller->enable_audio_recording());
-  EXPECT_TRUE(GetMicrophoneToggle()->GetIsOn());
-
-  // Test that the user selected audio preference for audio recording is
-  // remembered between sessions.
-  SendKey(ui::VKEY_ESCAPE, event_generator);
-  EXPECT_TRUE(controller->enable_audio_recording());
-  StartImageRegionCapture();
-  EXPECT_TRUE(controller->enable_audio_recording());
-}
-
 TEST_F(CaptureModeTest, CaptureFolderSetting) {
   auto* controller = CaptureModeController::Get();
   auto* test_delegate = controller->delegate_for_testing();
@@ -4919,19 +4811,15 @@
                                      CaptureModeEntryType::kProjector, 1);
 }
 
-// Tests that when the advanced capture mode settings are enabled, a simplified
-// view of the settings are shown.
-TEST_F(ProjectorCaptureModeIntegrationTests, WithAdvancedSettings) {
-  base::test::ScopedFeatureList scoped_feature_list{
-      features::kImprovedScreenCaptureSettings};
-
+// Tests that the settings view is simplified in projector mode.
+TEST_F(ProjectorCaptureModeIntegrationTests, CaptureModeSettings) {
   auto* controller = CaptureModeController::Get();
   StartProjectorModeSession();
   auto* event_generator = GetEventGenerator();
 
   ClickOnView(GetSettingsButton(), event_generator);
 
-  CaptureModeAdvancedSettingsTestApi test_api;
+  CaptureModeSettingsTestApi test_api;
 
   // The "Save-to" menu group should never be added.
   CaptureModeMenuGroup* save_to_menu_group = test_api.GetSaveToMenuGroup();
@@ -4946,15 +4834,10 @@
   EXPECT_TRUE(controller->enable_audio_recording());
 }
 
-// Tests the keyboard navigation for projector mode with advanced capture mode
-// settings enabled. The `image_toggle_button_` in `CaptureModeTypeView` and the
-// `Off` audio input option in `CaptureModeAdvancedSettingsView` are not
-// available in projector mode.
-TEST_F(ProjectorCaptureModeIntegrationTests,
-       KeyboardNavigationWithAdvancedSettings) {
-  base::test::ScopedFeatureList scoped_feature_list{
-      features::kImprovedScreenCaptureSettings};
-  ASSERT_TRUE(features::AreImprovedScreenCaptureSettingsEnabled());
+// Tests the keyboard navigation for projector mode. The `image_toggle_button_`
+// in `CaptureModeTypeView` and the `Off` audio input option in
+// `CaptureModeSettingsView` are not available in projector mode.
+TEST_F(ProjectorCaptureModeIntegrationTests, KeyboardNavigationBasic) {
   auto* controller = CaptureModeController::Get();
   // Use `kFullscreen` here to minimize the number of tabs to reach the setting
   // button.
@@ -4976,17 +4859,17 @@
   SendKey(ui::VKEY_TAB, event_generator, /*shift_down=*/false, /*count=*/4);
   SendKey(ui::VKEY_SPACE, event_generator);
   EXPECT_EQ(FocusGroup::kPendingSettings, test_api.GetCurrentFocusGroup());
-  CaptureModeAdvancedSettingsView* settings_menu =
-      test_api.capture_mode_advanced_settings_view();
+  CaptureModeSettingsView* settings_menu =
+      test_api.capture_mode_settings_view();
   ASSERT_TRUE(settings_menu);
 
-  CaptureModeAdvancedSettingsTestApi advanced_settings_test_api;
+  CaptureModeSettingsTestApi settings_test_api;
   // The `Off` option should not be visible.
-  EXPECT_FALSE(advanced_settings_test_api.GetAudioOffOption());
+  EXPECT_FALSE(settings_test_api.GetAudioOffOption());
   // Tab twice, the current focused view is the `Microphone` option.
   SendKey(ui::VKEY_TAB, event_generator, /*shift_down=*/false, /*count=*/2);
   EXPECT_EQ(test_api.GetCurrentFocusedView()->GetView(),
-            advanced_settings_test_api.GetMicrophoneOption());
+            settings_test_api.GetMicrophoneOption());
 }
 
 TEST_F(ProjectorCaptureModeIntegrationTests, BarButtonsState) {
@@ -5411,18 +5294,16 @@
                                          CaptureModeSource::kWindow));
 
 // -----------------------------------------------------------------------------
-// CaptureModeAdvancedSettingsTest:
+// CaptureModeSettingsTest:
 
-// Test fixture for CaptureMode advanced settings view.
-class CaptureModeAdvancedSettingsTest : public CaptureModeTest {
+// Test fixture for CaptureMode settings view.
+class CaptureModeSettingsTest : public CaptureModeTest {
  public:
-  CaptureModeAdvancedSettingsTest() = default;
-  ~CaptureModeAdvancedSettingsTest() override = default;
+  CaptureModeSettingsTest() = default;
+  ~CaptureModeSettingsTest() override = default;
 
   // CaptureModeTest:
   void SetUp() override {
-    scoped_feature_list_.InitAndEnableFeature(
-        features::kImprovedScreenCaptureSettings);
     CaptureModeTest::SetUp();
     FakeFolderSelectionDialogFactory::Start();
   }
@@ -5432,11 +5313,10 @@
     CaptureModeTest::TearDown();
   }
 
-  CaptureModeAdvancedSettingsView* GetCaptureModeAdvancedSettingsView() const {
+  CaptureModeSettingsView* GetCaptureModeSettingsView() const {
     auto* session = CaptureModeController::Get()->capture_mode_session();
     DCHECK(session);
-    return CaptureModeSessionTestApi(session)
-        .capture_mode_advanced_settings_view();
+    return CaptureModeSessionTestApi(session).capture_mode_settings_view();
   }
 
   UserNudgeController* GetUserNudgeController() const {
@@ -5447,13 +5327,10 @@
 
   void WaitForSettingsMenuToBeRefreshed() {
     base::RunLoop run_loop;
-    CaptureModeAdvancedSettingsTestApi().SetOnSettingsMenuRefreshedCallback(
+    CaptureModeSettingsTestApi().SetOnSettingsMenuRefreshedCallback(
         run_loop.QuitClosure());
     run_loop.Run();
   }
-
- protected:
-  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 enum class NudgeDismissalCause {
@@ -5466,7 +5343,7 @@
 // Test fixture to test that various causes that lead to the dismissal of the
 // user nudge, they dismiss it forever.
 class CaptureModeNudgeDismissalTest
-    : public CaptureModeAdvancedSettingsTest,
+    : public CaptureModeSettingsTest,
       public ::testing::WithParamInterface<NudgeDismissalCause> {
  public:
   // Starts a session appropriate for the test param.
@@ -5543,7 +5420,7 @@
                     NudgeDismissalCause::kCaptureViaClickOnScreen,
                     NudgeDismissalCause::kCaptureViaLabelButton));
 
-TEST_F(CaptureModeAdvancedSettingsTest, NudgeChangesRootWithBar) {
+TEST_F(CaptureModeSettingsTest, NudgeChangesRootWithBar) {
   UpdateDisplay("800x700,801+0-800x700");
 
   auto* event_generator = GetEventGenerator();
@@ -5565,7 +5442,7 @@
       session->current_root());
 }
 
-TEST_F(CaptureModeAdvancedSettingsTest, NudgeBehaviorWhenSelectingRegion) {
+TEST_F(CaptureModeSettingsTest, NudgeBehaviorWhenSelectingRegion) {
   UpdateDisplay("800x700,801+0-800x700");
 
   auto* event_generator = GetEventGenerator();
@@ -5592,7 +5469,7 @@
       session->current_root());
 }
 
-TEST_F(CaptureModeAdvancedSettingsTest, NudgeDoesNotShowForAllUserTypes) {
+TEST_F(CaptureModeSettingsTest, NudgeDoesNotShowForAllUserTypes) {
   struct {
     std::string trace;
     user_manager::UserType user_type;
@@ -5626,7 +5503,7 @@
 
 // Tests that it's possbile to take a screenshot using the keyboard shortcut at
 // the login screen without any crashes. https://crbug.com/1266728.
-TEST_F(CaptureModeAdvancedSettingsTest, TakeScreenshotAtLoginScreen) {
+TEST_F(CaptureModeSettingsTest, TakeScreenshotAtLoginScreen) {
   ClearLogin();
   PressAndReleaseKey(ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_CONTROL_DOWN);
   WaitForCaptureFileToBeSaved();
@@ -5634,7 +5511,7 @@
 
 // Tests that clicking on audio input buttons updates the state in the
 // controller, and persists between sessions.
-TEST_F(CaptureModeAdvancedSettingsTest, AudioInputSettingsMenu) {
+TEST_F(CaptureModeSettingsTest, AudioInputSettingsMenu) {
   auto* controller = StartImageRegionCapture();
   auto* event_generator = GetEventGenerator();
 
@@ -5642,7 +5519,7 @@
   ClickOnView(GetSettingsButton(), event_generator);
   EXPECT_FALSE(controller->enable_audio_recording());
 
-  CaptureModeAdvancedSettingsTestApi test_api;
+  CaptureModeSettingsTestApi test_api;
   CaptureModeMenuGroup* audio_input_menu_group =
       test_api.GetAudioInputMenuGroup();
   EXPECT_TRUE(audio_input_menu_group->IsOptionChecked(kAudioOff));
@@ -5663,13 +5540,13 @@
   EXPECT_TRUE(controller->enable_audio_recording());
 }
 
-TEST_F(CaptureModeAdvancedSettingsTest, SelectFolderFromDialog) {
+TEST_F(CaptureModeSettingsTest, SelectFolderFromDialog) {
   auto* controller = StartImageRegionCapture();
   auto* event_generator = GetEventGenerator();
   ClickOnView(GetSettingsButton(), event_generator);
 
   // Initially there should only be an option for the default downloads folder.
-  CaptureModeAdvancedSettingsTestApi test_api;
+  CaptureModeSettingsTestApi test_api;
   EXPECT_TRUE(test_api.GetDefaultDownloadsOption());
   EXPECT_FALSE(test_api.GetCustomFolderOptionIfAny());
   CaptureModeMenuGroup* save_to_menu_group = test_api.GetSaveToMenuGroup();
@@ -5707,26 +5584,26 @@
 
 // Tests that folder selection dialog can be opened without crash while in
 // window capture mode.
-TEST_F(CaptureModeAdvancedSettingsTest, SelectFolderInWindowCaptureMode) {
+TEST_F(CaptureModeSettingsTest, SelectFolderInWindowCaptureMode) {
   std::unique_ptr<aura::Window> window1(
       CreateTestWindow(gfx::Rect(0, 0, 200, 300)));
   StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kImage);
   auto* event_generator = GetEventGenerator();
   ClickOnView(GetSettingsButton(), event_generator);
 
-  CaptureModeAdvancedSettingsTestApi test_api;
+  CaptureModeSettingsTestApi test_api;
   ClickOnView(test_api.GetSelectFolderMenuItem(), event_generator);
   EXPECT_TRUE(IsFolderSelectionDialogShown());
 }
 
-TEST_F(CaptureModeAdvancedSettingsTest, DismissDialogWithoutSelection) {
+TEST_F(CaptureModeSettingsTest, DismissDialogWithoutSelection) {
   auto* controller = StartImageRegionCapture();
   const auto old_capture_folder = controller->GetCurrentCaptureFolder();
 
   // Open the settings menu, and click the "Select folder" menu item.
   auto* event_generator = GetEventGenerator();
   ClickOnView(GetSettingsButton(), event_generator);
-  CaptureModeAdvancedSettingsTestApi test_api;
+  CaptureModeSettingsTestApi test_api;
   ClickOnView(test_api.GetSelectFolderMenuItem(), event_generator);
   EXPECT_TRUE(IsFolderSelectionDialogShown());
 
@@ -5745,7 +5622,7 @@
             new_capture_folder.is_default_downloads_folder);
 }
 
-TEST_F(CaptureModeAdvancedSettingsTest, AcceptUpdatedCustomFolderFromDialog) {
+TEST_F(CaptureModeSettingsTest, AcceptUpdatedCustomFolderFromDialog) {
   // Begin a new session with a pre-configured custom folder.
   auto* controller = CaptureModeController::Get();
   const base::FilePath custom_folder(CreateCustomFolder("test"));
@@ -5757,7 +5634,7 @@
   auto* event_generator = GetEventGenerator();
   ClickOnView(GetSettingsButton(), event_generator);
   WaitForSettingsMenuToBeRefreshed();
-  CaptureModeAdvancedSettingsTestApi test_api;
+  CaptureModeSettingsTestApi test_api;
   EXPECT_TRUE(test_api.GetDefaultDownloadsOption());
   auto* custom_folder_view = test_api.GetCustomFolderOptionIfAny();
   EXPECT_TRUE(custom_folder_view);
@@ -5787,7 +5664,7 @@
   EXPECT_FALSE(capture_folder.is_default_downloads_folder);
 }
 
-TEST_F(CaptureModeAdvancedSettingsTest,
+TEST_F(CaptureModeSettingsTest,
        InitializeSettingsViewWithUnavailableCustomFolder) {
   // Begin a new session with a pre-configured unavailable custom folder.
   auto* controller = CaptureModeController::Get();
@@ -5805,7 +5682,7 @@
   ClickOnView(GetSettingsButton(), event_generator);
   WaitForSettingsMenuToBeRefreshed();
 
-  CaptureModeAdvancedSettingsTestApi test_api;
+  CaptureModeSettingsTestApi test_api;
   EXPECT_TRUE(test_api.GetDefaultDownloadsOption());
   auto* custom_folder_view = test_api.GetCustomFolderOptionIfAny();
   EXPECT_TRUE(custom_folder_view);
@@ -5833,7 +5710,7 @@
             save_to_menu_group->GetOptionLabelForTesting(kCustomFolder));
 }
 
-TEST_F(CaptureModeAdvancedSettingsTest, DeleteCustomFolderFromDialog) {
+TEST_F(CaptureModeSettingsTest, DeleteCustomFolderFromDialog) {
   // Begin a new session with a pre-configured custom folder.
   auto* controller = CaptureModeController::Get();
   const base::FilePath custom_folder(CreateCustomFolder("test"));
@@ -5847,7 +5724,7 @@
   ClickOnView(GetSettingsButton(), event_generator);
   WaitForSettingsMenuToBeRefreshed();
 
-  CaptureModeAdvancedSettingsTestApi test_api;
+  CaptureModeSettingsTestApi test_api;
   EXPECT_TRUE(test_api.GetDefaultDownloadsOption());
   auto* custom_folder_view = test_api.GetCustomFolderOptionIfAny();
   EXPECT_TRUE(custom_folder_view);
@@ -5873,8 +5750,7 @@
   EXPECT_TRUE(save_to_menu_group->IsOptionChecked(kDownloadsFolder));
 }
 
-TEST_F(CaptureModeAdvancedSettingsTest,
-       AcceptDefaultDownloadsFolderFromDialog) {
+TEST_F(CaptureModeSettingsTest, AcceptDefaultDownloadsFolderFromDialog) {
   // Begin a new session with a pre-configured custom folder.
   auto* controller = CaptureModeController::Get();
   controller->SetCustomCaptureFolder(
@@ -5884,7 +5760,7 @@
   auto* event_generator = GetEventGenerator();
   ClickOnView(GetSettingsButton(), event_generator);
   WaitForSettingsMenuToBeRefreshed();
-  CaptureModeAdvancedSettingsTestApi test_api;
+  CaptureModeSettingsTestApi test_api;
   ClickOnView(test_api.GetSelectFolderMenuItem(), event_generator);
 
   // Selecting the same folder as the default downloads folder should result in
@@ -5901,7 +5777,7 @@
   EXPECT_TRUE(save_to_menu_group->IsOptionChecked(kDownloadsFolder));
 }
 
-TEST_F(CaptureModeAdvancedSettingsTest, SwitchWhichFolderToUserFromOptions) {
+TEST_F(CaptureModeSettingsTest, SwitchWhichFolderToUserFromOptions) {
   // Begin a new session with a pre-configured custom folder.
   auto* controller = CaptureModeController::Get();
   const base::FilePath custom_path((CreateCustomFolder("test")));
@@ -5913,7 +5789,7 @@
 
   // Clicking the "Downloads" option will set it as the folder of choice, but
   // won't clear the custom folder.
-  CaptureModeAdvancedSettingsTestApi test_api;
+  CaptureModeSettingsTestApi test_api;
   ClickOnView(test_api.GetDefaultDownloadsOption(), event_generator);
   CaptureModeMenuGroup* save_to_menu_group = test_api.GetSaveToMenuGroup();
   EXPECT_TRUE(save_to_menu_group->IsOptionChecked(kDownloadsFolder));
@@ -5937,8 +5813,7 @@
 // Tests that when there's no overlap betwwen capture label widget and settings
 // widget, capture label widget is shown/hidden correctly after open/close the
 // folder selection window.
-TEST_F(CaptureModeAdvancedSettingsTest,
-       CaptureLabelViewNotOverlapsWithSettingsView) {
+TEST_F(CaptureModeSettingsTest, CaptureLabelViewNotOverlapsWithSettingsView) {
   // Update the display size to make sure capture label widget will not
   // overlap with settings widget
   UpdateDisplay("1200x1000");
@@ -5958,7 +5833,7 @@
 
   // Open folder selection window, check that both capture label widget and
   // settings widget are invisible.
-  CaptureModeAdvancedSettingsTestApi test_api;
+  CaptureModeSettingsTestApi test_api;
   auto* dialog_factory = FakeFolderSelectionDialogFactory::Get();
   ClickOnView(test_api.GetSelectFolderMenuItem(), event_generator);
   EXPECT_TRUE(IsFolderSelectionDialogShown());
@@ -5983,8 +5858,7 @@
 // label widget is shown/hidden correctly after open/close the folder selection
 // window, open/close settings menu. Regression test for
 // https://crbug.com/1279606.
-TEST_F(CaptureModeAdvancedSettingsTest,
-       CaptureLabelViewOverlapsWithSettingsView) {
+TEST_F(CaptureModeSettingsTest, CaptureLabelViewOverlapsWithSettingsView) {
   // Update display size to make capture label widget overlap with settings
   // widget.
   UpdateDisplay("1100x700");
@@ -6002,7 +5876,7 @@
   EXPECT_TRUE(settings_widget->IsVisible());
 
   // Open folder selection window, capture label widget is invisible.
-  CaptureModeAdvancedSettingsTestApi test_api;
+  CaptureModeSettingsTestApi test_api;
   auto* dialog_factory = FakeFolderSelectionDialogFactory::Get();
   ClickOnView(test_api.GetSelectFolderMenuItem(), event_generator);
   EXPECT_TRUE(IsFolderSelectionDialogShown());
@@ -6022,33 +5896,36 @@
 }
 
 // Tests the basic keyboard navigation functions for the settings menu.
-TEST_F(CaptureModeAdvancedSettingsTest, KeyboardNavigationForSettingsMenu) {
+TEST_F(CaptureModeSettingsTest, KeyboardNavigationForSettingsMenu) {
   auto* controller =
       StartCaptureSession(CaptureModeSource::kRegion, CaptureModeType::kImage);
 
   using FocusGroup = CaptureModeSessionFocusCycler::FocusGroup;
-  CaptureModeSessionTestApi test_api(controller->capture_mode_session());
+  CaptureModeSessionTestApi session_test_api(
+      controller->capture_mode_session());
 
   // Tab six times to focus the settings button.
   auto* event_generator = GetEventGenerator();
   SendKey(ui::VKEY_TAB, event_generator, /*shift_down=*/false, /*count=*/6);
-  EXPECT_EQ(FocusGroup::kSettingsClose, test_api.GetCurrentFocusGroup());
-  EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
+  EXPECT_EQ(FocusGroup::kSettingsClose,
+            session_test_api.GetCurrentFocusGroup());
+  EXPECT_EQ(0u, session_test_api.GetCurrentFocusIndex());
 
   // Enter space to open the settings menu. The current focus group should be
   // `kPendingSettings`.
   SendKey(ui::VKEY_SPACE, event_generator);
-  ASSERT_TRUE(GetCaptureModeAdvancedSettingsView());
-  EXPECT_EQ(FocusGroup::kPendingSettings, test_api.GetCurrentFocusGroup());
+  ASSERT_TRUE(GetCaptureModeSettingsView());
+  EXPECT_EQ(FocusGroup::kPendingSettings,
+            session_test_api.GetCurrentFocusGroup());
 
-  CaptureModeAdvancedSettingsTestApi advanced_settings_test_api;
+  CaptureModeSettingsTestApi settings_test_api;
   CaptureModeMenuGroup* audio_input_menu_group =
-      advanced_settings_test_api.GetAudioInputMenuGroup();
+      settings_test_api.GetAudioInputMenuGroup();
   // Tab once to focus the first item on the settings menu (`Audio input`
   // header).
   SendKey(ui::VKEY_TAB, event_generator);
-  EXPECT_EQ(FocusGroup::kSettingsMenu, test_api.GetCurrentFocusGroup());
-  EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
+  EXPECT_EQ(FocusGroup::kSettingsMenu, session_test_api.GetCurrentFocusGroup());
+  EXPECT_EQ(0u, session_test_api.GetCurrentFocusIndex());
 
   // Tab once to focus the `Off` option on the settings menu. Check `Off` option
   // is the checked option not the `Microphone`.
@@ -6077,15 +5954,16 @@
   // Now tab once to focus on the settings button and enter space on it to close
   // the settings menu.
   SendKey(ui::VKEY_TAB, event_generator);
-  EXPECT_EQ(FocusGroup::kSettingsClose, test_api.GetCurrentFocusGroup());
-  EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
+  EXPECT_EQ(FocusGroup::kSettingsClose,
+            session_test_api.GetCurrentFocusGroup());
+  EXPECT_EQ(0u, session_test_api.GetCurrentFocusIndex());
   SendKey(ui::VKEY_SPACE, event_generator);
-  EXPECT_FALSE(GetCaptureModeAdvancedSettingsView());
+  EXPECT_FALSE(GetCaptureModeSettingsView());
 }
 
 // Tests that the disabled option in the settings menu will be skipped while
 // tabbing through.
-TEST_F(CaptureModeAdvancedSettingsTest,
+TEST_F(CaptureModeSettingsTest,
        KeyboardNavigationForSettingsMenuWithDisabledOption) {
   // Begin a new session with a pre-configured unavailable custom folder.
   auto* controller = CaptureModeController::Get();
@@ -6094,24 +5972,24 @@
   StartImageRegionCapture();
 
   using FocusGroup = CaptureModeSessionFocusCycler::FocusGroup;
-  CaptureModeSessionTestApi test_api(controller->capture_mode_session());
+  CaptureModeSessionTestApi session_test_api(
+      controller->capture_mode_session());
 
   // Tab six times to focus the settings button and enter space to open the
   // setting menu.
   auto* event_generator = GetEventGenerator();
   SendKey(ui::VKEY_TAB, event_generator, /*shift_down=*/false, /*count=*/6);
   SendKey(ui::VKEY_SPACE, event_generator);
-  EXPECT_EQ(FocusGroup::kPendingSettings, test_api.GetCurrentFocusGroup());
-  CaptureModeAdvancedSettingsView* settings_menu =
-      GetCaptureModeAdvancedSettingsView();
+  EXPECT_EQ(FocusGroup::kPendingSettings,
+            session_test_api.GetCurrentFocusGroup());
+  CaptureModeSettingsView* settings_menu = GetCaptureModeSettingsView();
   ASSERT_TRUE(settings_menu);
 
   // Since the custom folder is unavailable, the `kCustomFolder` should be
   // disabled and won't be returned via
-  // `CaptureModeAdvancedSettingsViews::GetHighlightableItems`.
-  CaptureModeAdvancedSettingsTestApi advanced_settings_test_api;
-  auto* custom_folder_view =
-      advanced_settings_test_api.GetCustomFolderOptionIfAny();
+  // `CaptureModeSettingsViews::GetHighlightableItems`.
+  CaptureModeSettingsTestApi settings_test_api;
+  auto* custom_folder_view = settings_test_api.GetCustomFolderOptionIfAny();
   ASSERT_TRUE(custom_folder_view);
   EXPECT_FALSE(custom_folder_view->GetEnabled());
 
@@ -6126,20 +6004,20 @@
 
   // Tab five times to focus the default `Downloads` option.
   SendKey(ui::VKEY_TAB, event_generator, /*shift_down=*/false, /*count=*/5);
-  EXPECT_EQ(test_api.GetCurrentFocusedView()->GetView(),
-            advanced_settings_test_api.GetDefaultDownloadsOption());
+  EXPECT_EQ(session_test_api.GetCurrentFocusedView()->GetView(),
+            settings_test_api.GetDefaultDownloadsOption());
 
   // Tab once to check the disabled `kCustomFolder` option is skipped and now
   // the `Select folder...` menu item gets focused.
   SendKey(ui::VKEY_TAB, event_generator);
-  EXPECT_EQ(test_api.GetCurrentFocusedView()->GetView(),
-            advanced_settings_test_api.GetSelectFolderMenuItem());
+  EXPECT_EQ(session_test_api.GetCurrentFocusedView()->GetView(),
+            settings_test_api.GetSelectFolderMenuItem());
 }
 
 // Tests that selecting the default `Downloads` folder as the custom folder via
 // keyboard navigation doesn't lead to a crash. Regression test for
 // https://crbug.com/1269373.
-TEST_F(CaptureModeAdvancedSettingsTest,
+TEST_F(CaptureModeSettingsTest,
        KeyboardNavigationForRemovingCustomFolderOption) {
   // Begin a new session with a pre-configured custom folder.
   auto* controller = CaptureModeController::Get();
@@ -6157,8 +6035,7 @@
   SendKey(ui::VKEY_SPACE, event_generator);
   WaitForSettingsMenuToBeRefreshed();
   EXPECT_EQ(FocusGroup::kPendingSettings, test_api.GetCurrentFocusGroup());
-  CaptureModeAdvancedSettingsView* settings_menu =
-      GetCaptureModeAdvancedSettingsView();
+  CaptureModeSettingsView* settings_menu = GetCaptureModeSettingsView();
   ASSERT_TRUE(settings_menu);
 
   // Tab seven times to focus the `Select folder...` menu item and enter space
@@ -6195,22 +6072,22 @@
 // Tests that first time selecting a custom folder via keyboard navigation.
 // After the custom folder is selected, tabbing one more time will move focus
 // from the settings menu to the settings button.
-TEST_F(CaptureModeAdvancedSettingsTest,
-       KeyboardNavigationForAddingCustomFolderOption) {
+TEST_F(CaptureModeSettingsTest, KeyboardNavigationForAddingCustomFolderOption) {
   auto* controller = CaptureModeController::Get();
   StartImageRegionCapture();
 
   using FocusGroup = CaptureModeSessionFocusCycler::FocusGroup;
-  CaptureModeSessionTestApi test_api(controller->capture_mode_session());
+  CaptureModeSessionTestApi session_test_api(
+      controller->capture_mode_session());
 
   // Tab six times to focus the settings button, then enter space to open the
   // setting menu.
   auto* event_generator = GetEventGenerator();
   SendKey(ui::VKEY_TAB, event_generator, /*shift_down=*/false, /*count=*/6);
   SendKey(ui::VKEY_SPACE, event_generator);
-  EXPECT_EQ(FocusGroup::kPendingSettings, test_api.GetCurrentFocusGroup());
-  CaptureModeAdvancedSettingsView* settings_menu =
-      GetCaptureModeAdvancedSettingsView();
+  EXPECT_EQ(FocusGroup::kPendingSettings,
+            session_test_api.GetCurrentFocusGroup());
+  CaptureModeSettingsView* settings_menu = GetCaptureModeSettingsView();
   ASSERT_TRUE(settings_menu);
 
   // Tab six times to focus the `Select folder...` menu item and enter space
@@ -6220,8 +6097,8 @@
   EXPECT_TRUE(IsFolderSelectionDialogShown());
   // The current focus group is `FocusGroup::kSettingsMenu` and focus index is
   // 5u.
-  EXPECT_EQ(FocusGroup::kSettingsMenu, test_api.GetCurrentFocusGroup());
-  EXPECT_EQ(5u, test_api.GetCurrentFocusIndex());
+  EXPECT_EQ(FocusGroup::kSettingsMenu, session_test_api.GetCurrentFocusGroup());
+  EXPECT_EQ(5u, session_test_api.GetCurrentFocusIndex());
 
   // Select the custom folder. Wait for the settings menu to be refreshed. The
   // custom folder option should be added to the settings menu and checked.
@@ -6230,8 +6107,8 @@
   auto* dialog_factory = FakeFolderSelectionDialogFactory::Get();
   dialog_factory->AcceptPath(custom_folder);
   WaitForSettingsMenuToBeRefreshed();
-  CaptureModeAdvancedSettingsTestApi advanced_test_api;
-  EXPECT_TRUE(advanced_test_api.GetCustomFolderOptionIfAny());
+  CaptureModeSettingsTestApi settings_test_api;
+  EXPECT_TRUE(settings_test_api.GetCustomFolderOptionIfAny());
 
   // Press space to ensure the selection window can be opened after the custom
   // folder is added to the settings menu.
@@ -6241,8 +6118,9 @@
 
   // Tab once to make sure the focus gets moved to settings button.
   SendKey(ui::VKEY_TAB, event_generator);
-  EXPECT_EQ(FocusGroup::kSettingsClose, test_api.GetCurrentFocusGroup());
-  EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
+  EXPECT_EQ(FocusGroup::kSettingsClose,
+            session_test_api.GetCurrentFocusGroup());
+  EXPECT_EQ(0u, session_test_api.GetCurrentFocusIndex());
 }
 
 // -----------------------------------------------------------------------------
@@ -6250,15 +6128,15 @@
 
 // Test fixture to verify screen capture histograms depending on the test
 // param (true for tablet mode, false for clamshell mode).
-class CaptureModeHistogramTest : public CaptureModeAdvancedSettingsTest,
+class CaptureModeHistogramTest : public CaptureModeSettingsTest,
                                  public ::testing::WithParamInterface<bool> {
  public:
   CaptureModeHistogramTest() = default;
   ~CaptureModeHistogramTest() override = default;
 
-  // CaptureModeAdvancedSettingsTest:
+  // CaptureModeSettingsTest:
   void SetUp() override {
-    CaptureModeAdvancedSettingsTest::SetUp();
+    CaptureModeSettingsTest::SetUp();
     if (GetParam())
       SwitchToTabletMode();
   }
@@ -6342,7 +6220,7 @@
   auto* event_generator = GetEventGenerator();
   OpenView(GetSettingsButton(), event_generator);
   WaitForSettingsMenuToBeRefreshed();
-  CaptureModeAdvancedSettingsTestApi test_api;
+  CaptureModeSettingsTestApi test_api;
   CaptureModeMenuGroup* save_to_menu_group = test_api.GetSaveToMenuGroup();
   EXPECT_TRUE(save_to_menu_group->IsOptionChecked(kDownloadsFolder));
   histogram_tester.ExpectBucketCount(
diff --git a/ash/clipboard/clipboard_nudge_controller.cc b/ash/clipboard/clipboard_nudge_controller.cc
index 145f372f..8407727 100644
--- a/ash/clipboard/clipboard_nudge_controller.cc
+++ b/ash/clipboard/clipboard_nudge_controller.cc
@@ -127,7 +127,7 @@
   if (!prefs)
     return;
   const int shown_count = GetNewFeatureBadgeShownCount(prefs);
-  DictionaryPrefUpdateDeprecated update(prefs, prefs::kMultipasteNudges);
+  DictionaryPrefUpdate update(prefs, prefs::kMultipasteNudges);
   update->SetIntPath(kNewFeatureBadgeCount, shown_count + 1);
   base::UmaHistogramBoolean(kNewBadge_ShowCount, true);
   if (new_feature_last_shown_time_.ShouldLogFeatureOpenTime()) {
@@ -199,7 +199,7 @@
 void ClipboardNudgeController::OnActiveUserPrefServiceChanged(
     PrefService* prefs) {
   // Reset the nudge prefs so that the nudge can be shown again.
-  DictionaryPrefUpdateDeprecated update(prefs, prefs::kMultipasteNudges);
+  DictionaryPrefUpdate update(prefs, prefs::kMultipasteNudges);
   update->SetIntPath(kShownCount, 0);
   update->SetPath(kLastTimeShown, base::TimeToValue(base::Time()));
   update->SetIntPath(kNewFeatureBadgeCount, 0);
@@ -251,7 +251,7 @@
   if (!prefs)
     return;
   const int shown_count = GetShownCount(prefs);
-  DictionaryPrefUpdateDeprecated update(prefs, prefs::kMultipasteNudges);
+  DictionaryPrefUpdate update(prefs, prefs::kMultipasteNudges);
   update->SetIntPath(kShownCount, shown_count + 1);
   update->SetPath(kLastTimeShown, base::TimeToValue(GetTime()));
 }
diff --git a/ash/components/arc/input_overlay/OWNERS b/ash/components/arc/input_overlay/OWNERS
new file mode 100644
index 0000000..79325269
--- /dev/null
+++ b/ash/components/arc/input_overlay/OWNERS
@@ -0,0 +1,2 @@
+cuicuiruan@google.com
+djacobo@chromium.org
diff --git a/ash/components/arc/input_overlay/resources/org.chromium.arc.testapp.inputoverlay.json b/ash/components/arc/input_overlay/resources/org.chromium.arc.testapp.inputoverlay.json
index 7399a48..d5ac7bd0 100644
--- a/ash/components/arc/input_overlay/resources/org.chromium.arc.testapp.inputoverlay.json
+++ b/ash/components/arc/input_overlay/resources/org.chromium.arc.testapp.inputoverlay.json
@@ -37,4 +37,4 @@
       }
     ]
   }
-}
\ No newline at end of file
+}
diff --git a/ash/components/arc/metrics/stability_metrics_manager.cc b/ash/components/arc/metrics/stability_metrics_manager.cc
index cb29007c..75883d8 100644
--- a/ash/components/arc/metrics/stability_metrics_manager.cc
+++ b/ash/components/arc/metrics/stability_metrics_manager.cc
@@ -70,7 +70,7 @@
 
 void StabilityMetricsManager::ResetMetrics() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DictionaryPrefUpdateDeprecated update(local_state_, prefs::kStabilityMetrics);
+  DictionaryPrefUpdate update(local_state_, prefs::kStabilityMetrics);
   update->DictClear();
 }
 
@@ -83,8 +83,8 @@
 
 void StabilityMetricsManager::SetArcEnabledState(bool enabled) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DictionaryPrefUpdateDeprecated update(local_state_, prefs::kStabilityMetrics);
-  update->SetKey(kArcEnabledStateKey, base::Value(enabled));
+  DictionaryPrefUpdate update(local_state_, prefs::kStabilityMetrics);
+  update->SetBoolKey(kArcEnabledStateKey, enabled);
 }
 
 absl::optional<NativeBridgeType>
@@ -104,9 +104,9 @@
 void StabilityMetricsManager::SetArcNativeBridgeType(
     NativeBridgeType native_bridge_type) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DictionaryPrefUpdateDeprecated update(local_state_, prefs::kStabilityMetrics);
-  update->SetKey(kArcNativeBridgeTypeKey,
-                 base::Value(static_cast<int>(native_bridge_type)));
+  DictionaryPrefUpdate update(local_state_, prefs::kStabilityMetrics);
+  update->SetIntKey(kArcNativeBridgeTypeKey,
+                    static_cast<int>(native_bridge_type));
 }
 
 }  // namespace arc
diff --git a/ash/components/audio/audio_devices_pref_handler_impl.cc b/ash/components/audio/audio_devices_pref_handler_impl.cc
index 09659d8..0fd2e00 100644
--- a/ash/components/audio/audio_devices_pref_handler_impl.cc
+++ b/ash/components/audio/audio_devices_pref_handler_impl.cc
@@ -310,8 +310,7 @@
 }
 
 void AudioDevicesPrefHandlerImpl::SaveDevicesMutePref() {
-  DictionaryPrefUpdateDeprecated dict_update(local_state_,
-                                             prefs::kAudioDevicesMute);
+  DictionaryPrefUpdate dict_update(local_state_, prefs::kAudioDevicesMute);
   dict_update->DictClear();
   dict_update->MergeDictionary(device_mute_settings_.get());
 }
@@ -324,8 +323,8 @@
 }
 
 void AudioDevicesPrefHandlerImpl::SaveDevicesVolumePref() {
-  DictionaryPrefUpdateDeprecated dict_update(local_state_,
-                                             prefs::kAudioDevicesVolumePercent);
+  DictionaryPrefUpdate dict_update(local_state_,
+                                   prefs::kAudioDevicesVolumePercent);
   dict_update->DictClear();
   dict_update->MergeDictionary(device_volume_settings_.get());
 }
@@ -338,8 +337,8 @@
 }
 
 void AudioDevicesPrefHandlerImpl::SaveDevicesGainPref() {
-  DictionaryPrefUpdateDeprecated dict_update(local_state_,
-                                             prefs::kAudioDevicesGainPercent);
+  DictionaryPrefUpdate dict_update(local_state_,
+                                   prefs::kAudioDevicesGainPercent);
   dict_update->DictClear();
   dict_update->MergeDictionary(device_gain_settings_.get());
 }
@@ -352,8 +351,7 @@
 }
 
 void AudioDevicesPrefHandlerImpl::SaveDevicesStatePref() {
-  DictionaryPrefUpdateDeprecated dict_update(local_state_,
-                                             prefs::kAudioDevicesState);
+  DictionaryPrefUpdate dict_update(local_state_, prefs::kAudioDevicesState);
   dict_update->DictClear();
   dict_update->MergeDictionary(device_state_settings_.get());
 }
diff --git a/ash/components/audio/audio_devices_pref_handler_impl_unittest.cc b/ash/components/audio/audio_devices_pref_handler_impl_unittest.cc
index 19b60d65..a88347f 100644
--- a/ash/components/audio/audio_devices_pref_handler_impl_unittest.cc
+++ b/ash/components/audio/audio_devices_pref_handler_impl_unittest.cc
@@ -112,26 +112,26 @@
     // are set when pref value sets up its internal state.
     std::string preset_key = GetPresetDeviceDeprecatedPrefKey();
     {
-      DictionaryPrefUpdateDeprecated update(pref_service_.get(),
-                                            prefs::kAudioDevicesState);
-      base::DictionaryValue* pref = update.Get();
-      base::DictionaryValue state;
+      DictionaryPrefUpdate update(pref_service_.get(),
+                                  prefs::kAudioDevicesState);
+      base::Value* pref = update.Get();
+      base::Value state(base::Value::Type::DICTIONARY);
       state.SetBoolKey("active", kPresetState.active);
       state.SetBoolKey("activate_by_user", kPresetState.activate_by_user);
-      pref->SetPath(preset_key, std::move(state));
+      pref->SetKey(preset_key, std::move(state));
     }
 
     {
-      DictionaryPrefUpdateDeprecated update(pref_service_.get(),
-                                            prefs::kAudioDevicesVolumePercent);
-      base::DictionaryValue* pref = update.Get();
+      DictionaryPrefUpdate update(pref_service_.get(),
+                                  prefs::kAudioDevicesVolumePercent);
+      base::Value* pref = update.Get();
       pref->SetDoubleKey(preset_key, kPresetState.sound_level);
     }
 
     {
-      DictionaryPrefUpdateDeprecated update(pref_service_.get(),
-                                            prefs::kAudioDevicesMute);
-      base::DictionaryValue* pref = update.Get();
+      DictionaryPrefUpdate update(pref_service_.get(),
+                                  prefs::kAudioDevicesMute);
+      base::Value* pref = update.Get();
       pref->SetIntKey(preset_key, static_cast<int>(kPresetState.mute));
     }
 
diff --git a/ash/components/phonehub/recent_apps_interaction_handler_impl.cc b/ash/components/phonehub/recent_apps_interaction_handler_impl.cc
index bb57b0b..c71d685 100644
--- a/ash/components/phonehub/recent_apps_interaction_handler_impl.cc
+++ b/ash/components/phonehub/recent_apps_interaction_handler_impl.cc
@@ -6,6 +6,7 @@
 
 #include "ash/components/phonehub/notification.h"
 #include "ash/components/phonehub/pref_names.h"
+#include "base/logging.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 
@@ -14,6 +15,11 @@
 
 using ::chromeos::multidevice_setup::mojom::Feature;
 using ::chromeos::multidevice_setup::mojom::FeatureState;
+using ::chromeos::multidevice_setup::mojom::HostStatus;
+using HostStatusWithDevice =
+    ::chromeos::multidevice_setup::MultiDeviceSetupClient::HostStatusWithDevice;
+using FeatureStatesMap =
+    ::chromeos::multidevice_setup::MultiDeviceSetupClient::FeatureStatesMap;
 
 const size_t kMaxMostRecentApps = 5;
 
@@ -130,11 +136,16 @@
 }
 
 void RecentAppsInteractionHandlerImpl::OnFeatureStatesChanged(
-    const multidevice_setup::MultiDeviceSetupClient::FeatureStatesMap&
-        feature_states_map) {
+    const FeatureStatesMap& feature_states_map) {
   ComputeAndUpdateUiState();
 }
 
+void RecentAppsInteractionHandlerImpl::OnHostStatusChanged(
+    const HostStatusWithDevice& host_device_with_status) {
+  if (host_device_with_status.first != HostStatus::kHostVerified)
+    ClearRecentAppMetadataListAndPref();
+}
+
 void RecentAppsInteractionHandlerImpl::ComputeAndUpdateUiState() {
   // Hide the recent apps UI if the Eche feature is disabled by user.
   FeatureState feature_state =
@@ -150,5 +161,10 @@
   NotifyRecentAppsViewUiStateUpdated();
 }
 
+void RecentAppsInteractionHandlerImpl::ClearRecentAppMetadataListAndPref() {
+  recent_app_metadata_list_.clear();
+  pref_service_->ClearPref(prefs::kRecentAppsHistory);
+}
+
 }  // namespace phonehub
 }  // namespace ash
diff --git a/ash/components/phonehub/recent_apps_interaction_handler_impl.h b/ash/components/phonehub/recent_apps_interaction_handler_impl.h
index 46d57afe..54a573a6 100644
--- a/ash/components/phonehub/recent_apps_interaction_handler_impl.h
+++ b/ash/components/phonehub/recent_apps_interaction_handler_impl.h
@@ -47,6 +47,9 @@
   void OnFeatureStatesChanged(
       const multidevice_setup::MultiDeviceSetupClient::FeatureStatesMap&
           feature_states_map) override;
+  void OnHostStatusChanged(
+      const multidevice_setup::MultiDeviceSetupClient::HostStatusWithDevice&
+          host_device_with_status) override;
 
  private:
   FRIEND_TEST_ALL_PREFIXES(RecentAppsInteractionHandlerTest, RecentAppsUpdated);
@@ -54,6 +57,7 @@
   void LoadRecentAppMetadataListFromPrefIfNeed();
   void SaveRecentAppMetadataListToPref();
   void ComputeAndUpdateUiState();
+  void ClearRecentAppMetadataListAndPref();
 
   // Whether this class has finished loading |recent_app_metadata_list_| from
   // pref.
diff --git a/ash/components/phonehub/recent_apps_interaction_handler_impl_unittest.cc b/ash/components/phonehub/recent_apps_interaction_handler_impl_unittest.cc
index 0fd53212..37cde9e86 100644
--- a/ash/components/phonehub/recent_apps_interaction_handler_impl_unittest.cc
+++ b/ash/components/phonehub/recent_apps_interaction_handler_impl_unittest.cc
@@ -18,6 +18,7 @@
 namespace {
 
 using FeatureState = ::chromeos::multidevice_setup::mojom::FeatureState;
+using HostStatus = ::chromeos::multidevice_setup::mojom::HostStatus;
 
 class FakeClickHandler : public RecentAppClickObserver {
  public:
@@ -60,7 +61,7 @@
     interaction_handler_->RemoveRecentAppClickObserver(&fake_click_handler_);
   }
 
-  void Initialize() {
+  void SaveRecentAppsToPref() {
     const char16_t app_visible_name1[] = u"Fake App";
     const char package_name1[] = "com.fakeapp";
     const int64_t expected_user_id1 = 1;
@@ -92,6 +93,11 @@
         chromeos::multidevice_setup::mojom::Feature::kEche, feature_state);
   }
 
+  void SetHostStatus(HostStatus host_status) {
+    fake_multidevice_setup_client_->SetHostStatusWithDevice(
+        std::make_pair(host_status, absl::nullopt /* host_device */));
+  }
+
   std::unique_ptr<multidevice_setup::FakeMultiDeviceSetupClient>
       fake_multidevice_setup_client_;
 
@@ -217,18 +223,17 @@
 
 TEST_F(RecentAppsInteractionHandlerTest,
        FetchRecentAppMetadataListFromPreference) {
-  Initialize();
+  SaveRecentAppsToPref();
 
   const char package_name1[] = "com.fakeapp";
   const char package_name2[] = "com.fakeapp2";
+  const size_t number_of_recent_apps_in_preference = 2;
+
   std::vector<Notification::AppMetadata> recent_apps_metadata_result =
       handler().FetchRecentAppMetadataList();
 
-  const size_t number_of_recent_apps_in_preference = 2;
-  recent_apps_metadata_result = handler().FetchRecentAppMetadataList();
   EXPECT_EQ(number_of_recent_apps_in_preference,
             recent_apps_metadata_result.size());
-
   EXPECT_EQ(package_name1, recent_apps_metadata_result[0].package_name);
   EXPECT_EQ(package_name2, recent_apps_metadata_result[1].package_name);
 }
@@ -300,5 +305,34 @@
             handler().ui_state());
 }
 
+TEST_F(RecentAppsInteractionHandlerTest,
+       PrefBeClearedWhenFeatureStatesChangedToUnavailableNoVerifiedHost) {
+  SaveRecentAppsToPref();
+  SetHostStatus(HostStatus::kHostSetButNotYetVerified);
+
+  std::vector<Notification::AppMetadata> recent_apps_metadata_result =
+      handler().FetchRecentAppMetadataList();
+
+  EXPECT_EQ(recent_apps_metadata_result.size(), 0u);
+}
+
+TEST_F(
+    RecentAppsInteractionHandlerTest,
+    RecentAppsListBeClearedWhenFeatureStatesChangedToUnavailableNoVerifiedHost) {
+  const base::Time now = base::Time::Now();
+  const char16_t app_visible_name[] = u"Fake App";
+  const char package_name[] = "com.fakeapp";
+  const int64_t expected_user_id = 1;
+  auto app_metadata = Notification::AppMetadata(app_visible_name, package_name,
+                                                gfx::Image(), expected_user_id);
+  handler().NotifyRecentAppAddedOrUpdated(app_metadata, now);
+  SetHostStatus(HostStatus::kHostSetButNotYetVerified);
+
+  std::vector<Notification::AppMetadata> recent_apps_metadata_result =
+      handler().FetchRecentAppMetadataList();
+
+  EXPECT_EQ(recent_apps_metadata_result.size(), 0u);
+}
+
 }  // namespace phonehub
 }  // namespace ash
diff --git a/ash/components/proximity_auth/proximity_auth_local_state_pref_manager.cc b/ash/components/proximity_auth/proximity_auth_local_state_pref_manager.cc
index 2f51340..d885a41 100644
--- a/ash/components/proximity_auth/proximity_auth_local_state_pref_manager.cc
+++ b/ash/components/proximity_auth/proximity_auth_local_state_pref_manager.cc
@@ -149,29 +149,24 @@
 
 void ProximityAuthLocalStatePrefManager::SetHasShownLoginDisabledMessage(
     bool has_shown) {
-  DictionaryPrefUpdateDeprecated update(local_state_,
-                                        prefs::kEasyUnlockLocalStateUserPrefs);
+  DictionaryPrefUpdate update(local_state_,
+                              prefs::kEasyUnlockLocalStateUserPrefs);
 
-  base::DictionaryValue* current_user_prefs;
-  update.Get()->GetDictionaryWithoutPathExpansion(active_user_.GetUserEmail(),
-                                                  &current_user_prefs);
+  base::Value* current_user_prefs =
+      update.Get()->FindDictKey(active_user_.GetUserEmail());
   if (current_user_prefs) {
-    current_user_prefs->SetKey(
-        prefs::kProximityAuthHasShownLoginDisabledMessage,
-        base::Value(has_shown));
+    current_user_prefs->SetBoolKey(
+        prefs::kProximityAuthHasShownLoginDisabledMessage, has_shown);
     return;
   }
 
   // Create an otherwise empty dictionary in order to ensure |has_shown| is
   // persisted for |active_user_|.
-  std::unique_ptr<base::DictionaryValue> new_current_user_prefs =
-      std::make_unique<base::DictionaryValue>();
-  new_current_user_prefs->SetKey(
-      prefs::kProximityAuthHasShownLoginDisabledMessage,
-      base::Value(has_shown));
-  update->SetKey(
-      active_user_.GetUserEmail(),
-      base::Value::FromUniquePtrValue(std::move(new_current_user_prefs)));
+  base::Value new_current_user_prefs(base::Value::Type::DICTIONARY);
+  new_current_user_prefs.SetBoolKey(
+      prefs::kProximityAuthHasShownLoginDisabledMessage, has_shown);
+  update->SetKey(active_user_.GetUserEmail(),
+                 std::move(new_current_user_prefs));
 }
 
 bool ProximityAuthLocalStatePrefManager::HasShownLoginDisabledMessage() const {
diff --git a/ash/components/proximity_auth/proximity_auth_local_state_pref_manager_unittest.cc b/ash/components/proximity_auth/proximity_auth_local_state_pref_manager_unittest.cc
index 8d91c763..3ed63336 100644
--- a/ash/components/proximity_auth/proximity_auth_local_state_pref_manager_unittest.cc
+++ b/ash/components/proximity_auth/proximity_auth_local_state_pref_manager_unittest.cc
@@ -59,37 +59,37 @@
 
     // Note: in normal circumstances, these prefs are synced to local state in
     // ProximityAuthProfilePrefService.
-    std::unique_ptr<base::DictionaryValue> user1_prefs(
-        new base::DictionaryValue());
-    user1_prefs->SetKey(
+    base::Value user1_prefs(base::Value::Type::DICTIONARY);
+    user1_prefs.SetBoolKey(
         proximity_auth::prefs::kProximityAuthIsChromeOSLoginEnabled,
-        base::Value(kIsChromeOSLoginEnabled1));
-    user1_prefs->SetKey(chromeos::multidevice_setup::kSmartLockAllowedPrefName,
-                        base::Value(kIsEasyUnlockAllowed1));
-    user1_prefs->SetKey(chromeos::multidevice_setup::kSmartLockEnabledPrefName,
-                        base::Value(kIsEasyUnlockEnabled1));
-    user1_prefs->SetKey(prefs::kSmartLockEligiblePrefName,
-                        base::Value(kIsSmartLockEligible1));
-    DictionaryPrefUpdateDeprecated update1(
-        &local_state_, prefs::kEasyUnlockLocalStateUserPrefs);
-    update1->SetKey(user1_.GetUserEmail(),
-                    base::Value::FromUniquePtrValue(std::move(user1_prefs)));
+        kIsChromeOSLoginEnabled1);
+    user1_prefs.SetBoolKey(
+        chromeos::multidevice_setup::kSmartLockAllowedPrefName,
+        kIsEasyUnlockAllowed1);
+    user1_prefs.SetBoolKey(
+        chromeos::multidevice_setup::kSmartLockEnabledPrefName,
+        kIsEasyUnlockEnabled1);
+    user1_prefs.SetBoolKey(prefs::kSmartLockEligiblePrefName,
+                           kIsSmartLockEligible1);
+    DictionaryPrefUpdate update1(&local_state_,
+                                 prefs::kEasyUnlockLocalStateUserPrefs);
+    update1->SetKey(user1_.GetUserEmail(), std::move(user1_prefs));
 
-    std::unique_ptr<base::DictionaryValue> user2_prefs(
-        new base::DictionaryValue());
-    user2_prefs->SetKey(
+    base::Value user2_prefs(base::Value::Type::DICTIONARY);
+    user2_prefs.SetBoolKey(
         proximity_auth::prefs::kProximityAuthIsChromeOSLoginEnabled,
-        base::Value(kIsChromeOSLoginEnabled2));
-    user2_prefs->SetKey(chromeos::multidevice_setup::kSmartLockAllowedPrefName,
-                        base::Value(kIsEasyUnlockAllowed2));
-    user2_prefs->SetKey(chromeos::multidevice_setup::kSmartLockEnabledPrefName,
-                        base::Value(kIsEasyUnlockEnabled2));
-    user2_prefs->SetKey(prefs::kSmartLockEligiblePrefName,
-                        base::Value(kIsSmartLockEligible2));
-    DictionaryPrefUpdateDeprecated update2(
-        &local_state_, prefs::kEasyUnlockLocalStateUserPrefs);
-    update2->SetKey(user2_.GetUserEmail(),
-                    base::Value::FromUniquePtrValue(std::move(user2_prefs)));
+        kIsChromeOSLoginEnabled2);
+    user2_prefs.SetBoolKey(
+        chromeos::multidevice_setup::kSmartLockAllowedPrefName,
+        kIsEasyUnlockAllowed2);
+    user2_prefs.SetBoolKey(
+        chromeos::multidevice_setup::kSmartLockEnabledPrefName,
+        kIsEasyUnlockEnabled2);
+    user2_prefs.SetBoolKey(prefs::kSmartLockEligiblePrefName,
+                           kIsSmartLockEligible2);
+    DictionaryPrefUpdate update2(&local_state_,
+                                 prefs::kEasyUnlockLocalStateUserPrefs);
+    update2->SetKey(user2_.GetUserEmail(), std::move(user2_prefs));
   }
 
   AccountId user1_;
diff --git a/ash/components/proximity_auth/proximity_auth_profile_pref_manager.cc b/ash/components/proximity_auth/proximity_auth_profile_pref_manager.cc
index 9d5a8bb..18cca07 100644
--- a/ash/components/proximity_auth/proximity_auth_profile_pref_manager.cc
+++ b/ash/components/proximity_auth/proximity_auth_profile_pref_manager.cc
@@ -83,22 +83,21 @@
 }
 
 void ProximityAuthProfilePrefManager::SyncPrefsToLocalState() {
-  std::unique_ptr<base::DictionaryValue> user_prefs_dict(
-      new base::DictionaryValue());
+  base::Value user_prefs_dict(base::Value::Type::DICTIONARY);
 
-  user_prefs_dict->SetKey(
+  user_prefs_dict.SetBoolKey(
       chromeos::multidevice_setup::kSmartLockAllowedPrefName,
-      base::Value(IsEasyUnlockAllowed()));
-  user_prefs_dict->SetKey(
+      IsEasyUnlockAllowed());
+  user_prefs_dict.SetBoolKey(
       chromeos::multidevice_setup::kSmartLockEnabledPrefName,
-      base::Value(IsEasyUnlockEnabled()));
-  user_prefs_dict->SetKey(prefs::kSmartLockEligiblePrefName,
-                          base::Value(IsSmartLockEligible()));
-  user_prefs_dict->SetKey(
+      IsEasyUnlockEnabled());
+  user_prefs_dict.SetBoolKey(prefs::kSmartLockEligiblePrefName,
+                             IsSmartLockEligible());
+  user_prefs_dict.SetBoolKey(
       chromeos::multidevice_setup::kSmartLockSigninAllowedPrefName,
-      base::Value(IsChromeOSLoginAllowed()));
-  user_prefs_dict->SetKey(prefs::kProximityAuthIsChromeOSLoginEnabled,
-                          base::Value(IsChromeOSLoginEnabled()));
+      IsChromeOSLoginAllowed());
+  user_prefs_dict.SetBoolKey(prefs::kProximityAuthIsChromeOSLoginEnabled,
+                             IsChromeOSLoginEnabled());
 
   // If Signin with Smart Lock is enabled, then the "has shown Signin with
   // Smart Lock is disabled message" flag should be false, to ensure the message
@@ -106,13 +105,12 @@
   // old value.
   bool has_shown_login_disabled_message =
       IsChromeOSLoginEnabled() ? false : HasShownLoginDisabledMessage();
-  user_prefs_dict->SetKey(prefs::kProximityAuthHasShownLoginDisabledMessage,
-                          base::Value(has_shown_login_disabled_message));
+  user_prefs_dict.SetBoolKey(prefs::kProximityAuthHasShownLoginDisabledMessage,
+                             has_shown_login_disabled_message);
 
-  DictionaryPrefUpdateDeprecated update(local_state_,
-                                        prefs::kEasyUnlockLocalStateUserPrefs);
-  update->SetKey(account_id_.GetUserEmail(),
-                 base::Value::FromUniquePtrValue(std::move(user_prefs_dict)));
+  DictionaryPrefUpdate update(local_state_,
+                              prefs::kEasyUnlockLocalStateUserPrefs);
+  update->SetKey(account_id_.GetUserEmail(), std::move(user_prefs_dict));
 }
 
 bool ProximityAuthProfilePrefManager::IsEasyUnlockAllowed() const {
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index c6f66216d..1a1bb2a 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -779,10 +779,6 @@
 const base::Feature kImprovedDesksKeyboardShortcuts{
     "ImprovedDesksKeyboardShortcuts", base::FEATURE_ENABLED_BY_DEFAULT};
 
-// Enable or disable the improved screen capture settings.
-const base::Feature kImprovedScreenCaptureSettings{
-    "ImprovedScreenCaptureSettings", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Enables or disables Instant Tethering on Chrome OS.
 const base::Feature kInstantTethering{"InstantTethering",
                                       base::FEATURE_ENABLED_BY_DEFAULT};
@@ -1372,10 +1368,6 @@
   return base::FeatureList::IsEnabled(kEnableDesksTrackpadSwipeImprovements);
 }
 
-bool AreImprovedScreenCaptureSettingsEnabled() {
-  return base::FeatureList::IsEnabled(kImprovedScreenCaptureSettings);
-}
-
 bool DoWindowsFollowCursor() {
   return base::FeatureList::IsEnabled(kWindowsFollowCursor);
 }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index cdba117..6277db4ef 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -297,8 +297,6 @@
 extern const base::Feature kImeStylusHandwriting;
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kImprovedDesksKeyboardShortcuts;
-COMPONENT_EXPORT(ASH_CONSTANTS)
-extern const base::Feature kImprovedScreenCaptureSettings;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kInstantTethering;
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kKeyboardBasedDisplayArrangementInSettings;
diff --git a/ash/detachable_base/detachable_base_handler.cc b/ash/detachable_base/detachable_base_handler.cc
index 555ad78..efa333b 100644
--- a/ash/detachable_base/detachable_base_handler.cc
+++ b/ash/detachable_base/detachable_base_handler.cc
@@ -79,8 +79,7 @@
   last_used_devices_.erase(user.account_id);
 
   if (local_state_) {
-    DictionaryPrefUpdateDeprecated update(local_state_,
-                                          prefs::kDetachableBaseDevices);
+    DictionaryPrefUpdate update(local_state_, prefs::kDetachableBaseDevices);
     update->RemoveKey(GetKeyForPrefs(user.account_id));
   }
 }
@@ -128,8 +127,7 @@
   last_used_devices_[user.account_id] = authenticated_base_id_;
 
   if (!user.is_ephemeral) {
-    DictionaryPrefUpdateDeprecated update(local_state_,
-                                          prefs::kDetachableBaseDevices);
+    DictionaryPrefUpdate update(local_state_, prefs::kDetachableBaseDevices);
     update->SetPath({GetKeyForPrefs(user.account_id), kLastUsedByUserPrefKey},
                     base::Value(authenticated_base_id_));
   }
diff --git a/ash/display/display_prefs.cc b/ash/display/display_prefs.cc
index 1a36981..8cda92a 100644
--- a/ash/display/display_prefs.cc
+++ b/ash/display/display_prefs.cc
@@ -85,12 +85,12 @@
   return false;
 }
 
-void InsetsToValue(const gfx::Insets& insets, base::DictionaryValue* value) {
-  DCHECK(value);
-  value->SetIntKey(kInsetsTopKey, insets.top());
-  value->SetIntKey(kInsetsLeftKey, insets.left());
-  value->SetIntKey(kInsetsBottomKey, insets.bottom());
-  value->SetIntKey(kInsetsRightKey, insets.right());
+void InsetsToValue(const gfx::Insets& insets, base::Value& value) {
+  DCHECK(value.is_dict());
+  value.SetIntKey(kInsetsTopKey, insets.top());
+  value.SetIntKey(kInsetsLeftKey, insets.left());
+  value.SetIntKey(kInsetsBottomKey, insets.bottom());
+  value.SetIntKey(kInsetsRightKey, insets.right());
 }
 
 // Unmarshalls the string containing CalibrationPointPairQuad and populates
@@ -148,8 +148,8 @@
 // Stores the touch calibration data into the dictionary.
 void TouchDataToValue(
     const display::TouchCalibrationData& touch_calibration_data,
-    base::DictionaryValue* value) {
-  DCHECK(value);
+    base::Value& value) {
+  DCHECK(value.is_dict());
   std::string str;
   for (std::size_t row = 0; row < touch_calibration_data.point_pairs.size();
        row++) {
@@ -167,11 +167,11 @@
     if (row != touch_calibration_data.point_pairs.size() - 1)
       str += " ";
   }
-  value->SetString(kTouchCalibrationPointPairs, str);
-  value->SetInteger(kTouchCalibrationWidth,
-                    touch_calibration_data.bounds.width());
-  value->SetInteger(kTouchCalibrationHeight,
-                    touch_calibration_data.bounds.height());
+  value.SetStringKey(kTouchCalibrationPointPairs, str);
+  value.SetIntKey(kTouchCalibrationWidth,
+                  touch_calibration_data.bounds.width());
+  value.SetIntKey(kTouchCalibrationHeight,
+                  touch_calibration_data.bounds.height());
 }
 
 display::DisplayManager* GetDisplayManager() {
@@ -471,13 +471,12 @@
   DCHECK(display::DisplayLayout::Validate(list, display_layout));
   std::string name = display::DisplayIdListToString(list);
 
-  DictionaryPrefUpdateDeprecated update(pref_service,
-                                        prefs::kSecondaryDisplays);
-  base::DictionaryValue* pref_data = update.Get();
+  DictionaryPrefUpdate update(pref_service, prefs::kSecondaryDisplays);
+  base::Value* pref_data = update.Get();
   base::Value layout_value(base::Value::Type::DICTIONARY);
-  const base::Value* value = pref_data->FindKey(name);
-  if (value)
+  if (base::Value* value = pref_data->FindKey(name)) {
     layout_value = value->Clone();
+  }
   if (display::DisplayLayoutToJson(display_layout, &layout_value))
     pref_data->SetPath(name, std::move(layout_value));
 }
@@ -507,9 +506,8 @@
 void StoreCurrentDisplayProperties(PrefService* pref_service) {
   display::DisplayManager* display_manager = GetDisplayManager();
 
-  DictionaryPrefUpdateDeprecated update(pref_service,
-                                        prefs::kDisplayProperties);
-  base::DictionaryValue* pref_data = update.Get();
+  DictionaryPrefUpdate update(pref_service, prefs::kDisplayProperties);
+  base::Value* pref_data = update.Get();
 
   // Pre-process data related to legacy touch calibration to opitmize lookup.
   const display::TouchDeviceIdentifier& fallback_identifier =
@@ -529,7 +527,7 @@
     int64_t id = display.id();
     display::ManagedDisplayInfo info = display_manager->GetDisplayInfo(id);
 
-    base::DictionaryValue property_value;
+    base::Value property_value(base::Value::Type::DICTIONARY);
     // Don't save the display preference in unified mode because its
     // size and modes can change depending on the combination of displays.
     if (display_manager->IsInUnifiedMode())
@@ -571,13 +569,12 @@
       }
     }
     if (!info.overscan_insets_in_dip().IsEmpty())
-      InsetsToValue(info.overscan_insets_in_dip(), &property_value);
+      InsetsToValue(info.overscan_insets_in_dip(), property_value);
 
     // Store the legacy format touch calibration data. This can be removed after
     // a couple of milestones when every device has migrated to the new format.
     if (legacy_data_map.size() && base::Contains(legacy_data_map, id)) {
-      TouchDataToValue(legacy_data_map.at(id).calibration_data,
-                       &property_value);
+      TouchDataToValue(legacy_data_map.at(id).calibration_data, property_value);
     }
 
     property_value.SetDoubleKey(kDisplayZoom, info.zoom_factor());
@@ -631,9 +628,8 @@
 void StoreDisplayRotationPrefs(PrefService* pref_service,
                                display::Display::Rotation rotation,
                                bool rotation_lock) {
-  DictionaryPrefUpdateDeprecated update(pref_service,
-                                        prefs::kDisplayRotationLock);
-  base::DictionaryValue* pref_data = update.Get();
+  DictionaryPrefUpdate update(pref_service, prefs::kDisplayRotationLock);
+  base::Value* pref_data = update.Get();
   pref_data->SetBoolKey("lock", rotation_lock);
   pref_data->SetIntKey("orientation", static_cast<int>(rotation));
 }
@@ -655,35 +651,33 @@
   display::TouchDeviceManager* touch_device_manager =
       GetDisplayManager()->touch_device_manager();
 
-  DictionaryPrefUpdateDeprecated update(pref_service,
-                                        prefs::kDisplayTouchAssociations);
-  base::DictionaryValue* pref_data = update.Get();
+  DictionaryPrefUpdate update(pref_service, prefs::kDisplayTouchAssociations);
+  base::Value* pref_data = update.Get();
   pref_data->DictClear();
 
   const display::TouchDeviceManager::TouchAssociationMap& touch_associations =
       touch_device_manager->touch_associations();
 
   for (const auto& association : touch_associations) {
-    base::DictionaryValue association_info_map_value;
+    base::Value association_info_map_value(base::Value::Type::DICTIONARY);
     for (const auto& association_info : association.second) {
       // Iteration for each pair of <Display ID, TouchAssociationInfo>.
-      std::unique_ptr<base::DictionaryValue> association_info_value(
-          new base::DictionaryValue());
+      base::Value association_info_value(base::Value::Type::DICTIONARY);
 
       // Parsing each member of TouchAssociationInfo and storing them in
       // |association_info_value|.
 
-      // Serialie timestamp.
-      association_info_value->SetKey(
+      // Serialize timestamp.
+      association_info_value.SetDoubleKey(
           kTouchAssociationTimestamp,
-          base::Value(association_info.second.timestamp.ToDoubleT()));
+          association_info.second.timestamp.ToDoubleT());
 
       // Serialize TouchCalibrationData.
-      base::DictionaryValue calibration_data_value;
+      base::Value calibration_data_value(base::Value::Type::DICTIONARY);
       TouchDataToValue(association_info.second.calibration_data,
-                       &calibration_data_value);
-      association_info_value->SetKey(kTouchAssociationCalibrationData,
-                                     calibration_data_value.Clone());
+                       calibration_data_value);
+      association_info_value.SetKey(kTouchAssociationCalibrationData,
+                                    std::move(calibration_data_value));
 
       // Move the searialzed TouchAssociationInfo stored in
       // |association_info_value| to |association_info_map_value| against the
@@ -691,7 +685,7 @@
       // AssociationInfoMap to its serialized form.
       association_info_map_value.SetKey(
           base::NumberToString(association_info.first),
-          association_info_value->Clone());
+          std::move(association_info_value));
     }
     if (association_info_map_value.DictEmpty())
       continue;
@@ -701,13 +695,13 @@
     // TouchDeviceIdentifier as key. This is a 1 to 1 mapping of a single entry
     // from TouchAssociationMap to its serialized form.
     pref_data->SetKey(association.first.ToString(),
-                      association_info_map_value.Clone());
+                      std::move(association_info_map_value));
   }
 
   // Store the port mappings. What display a touch device connected to a
   // particular port is associated with.
-  DictionaryPrefUpdateDeprecated update_port(
-      pref_service, prefs::kDisplayTouchPortAssociations);
+  DictionaryPrefUpdate update_port(pref_service,
+                                   prefs::kDisplayTouchPortAssociations);
   pref_data = update_port.Get();
   update_port->DictClear();
 
@@ -717,29 +711,26 @@
   // For each port identified by the secondary id of TouchDeviceIdentifier,
   // we store the touch device and the display associated with it.
   for (const auto& association : port_associations) {
-    std::unique_ptr<base::DictionaryValue> association_info_value(
-        new base::DictionaryValue());
-    association_info_value->SetKey(kTouchDeviceIdentifier,
-                                   base::Value(association.first.ToString()));
-    association_info_value->SetKey(
-        kPortAssociationDisplayId,
-        base::Value(base::NumberToString(association.second)));
+    base::Value association_info_value(base::Value::Type::DICTIONARY);
+    association_info_value.SetStringKey(kTouchDeviceIdentifier,
+                                        association.first.ToString());
+    association_info_value.SetStringKey(
+        kPortAssociationDisplayId, base::NumberToString(association.second));
 
     pref_data->SetKey(association.first.SecondaryIdToString(),
-                      association_info_value->Clone());
+                      std::move(association_info_value));
   }
 }
 
 // Stores mirror info for each external display.
 void StoreExternalDisplayMirrorInfo(PrefService* pref_service) {
-  ListPrefUpdateDeprecated update(pref_service,
-                                  prefs::kExternalDisplayMirrorInfo);
-  base::ListValue* pref_data = update.Get();
+  ListPrefUpdate update(pref_service, prefs::kExternalDisplayMirrorInfo);
+  base::Value* pref_data = update.Get();
   pref_data->ClearList();
   const std::set<int64_t>& external_display_mirror_info =
       GetDisplayManager()->external_display_mirror_info();
   for (const auto& id : external_display_mirror_info)
-    pref_data->Append(base::Value(base::NumberToString(id)));
+    pref_data->Append(base::NumberToString(id));
 }
 
 // Stores mixed mirror mode parameters. Clear the preferences if
@@ -747,21 +738,20 @@
 void StoreDisplayMixedMirrorModeParams(
     PrefService* pref_service,
     const absl::optional<display::MixedMirrorModeParams>& mixed_params) {
-  DictionaryPrefUpdateDeprecated update(pref_service,
-                                        prefs::kDisplayMixedMirrorModeParams);
-  base::DictionaryValue* pref_data = update.Get();
+  DictionaryPrefUpdate update(pref_service,
+                              prefs::kDisplayMixedMirrorModeParams);
+  base::Value* pref_data = update.Get();
   pref_data->DictClear();
 
   if (!mixed_params)
     return;
 
-  pref_data->SetKey(kMirroringSourceId,
-                    base::Value(base::NumberToString(mixed_params->source_id)));
+  pref_data->SetStringKey(kMirroringSourceId,
+                          base::NumberToString(mixed_params->source_id));
 
-  base::ListValue mirroring_destination_ids_value;
+  base::Value mirroring_destination_ids_value(base::Value::Type::LIST);
   for (const auto& id : mixed_params->destination_ids) {
-    mirroring_destination_ids_value.Append(
-        base::Value(base::NumberToString(id)));
+    mirroring_destination_ids_value.Append(base::NumberToString(id));
   }
   pref_data->SetKey(kMirroringDestinationIds,
                     std::move(mirroring_destination_ids_value));
@@ -905,11 +895,10 @@
 void DisplayPrefs::StoreLegacyTouchDataForTest(
     int64_t display_id,
     const display::TouchCalibrationData& data) {
-  DictionaryPrefUpdateDeprecated update(local_state_,
-                                        prefs::kDisplayProperties);
-  base::DictionaryValue* pref_data = update.Get();
-  base::DictionaryValue property_value;
-  TouchDataToValue(data, &property_value);
+  DictionaryPrefUpdate update(local_state_, prefs::kDisplayProperties);
+  base::Value* pref_data = update.Get();
+  base::Value property_value(base::Value::Type::DICTIONARY);
+  TouchDataToValue(data, property_value);
   pref_data->SetKey(base::NumberToString(display_id),
                     std::move(property_value));
 }
diff --git a/ash/display/display_prefs_unittest.cc b/ash/display/display_prefs_unittest.cc
index 49a5cfeb..17b2c506 100644
--- a/ash/display/display_prefs_unittest.cc
+++ b/ash/display/display_prefs_unittest.cc
@@ -153,18 +153,16 @@
       int offset,
       int64_t primary_id) {
     std::string name = display::DisplayIdListToString(list);
-    DictionaryPrefUpdateDeprecated update(local_state(),
-                                          prefs::kSecondaryDisplays);
+    DictionaryPrefUpdate update(local_state(), prefs::kSecondaryDisplays);
     display::DisplayLayout display_layout;
     display_layout.placement_list.emplace_back(position, offset);
     display_layout.primary_id = primary_id;
 
     DCHECK(!name.empty());
 
-    base::DictionaryValue* pref_data = update.Get();
+    base::Value* pref_data = update.Get();
     base::Value layout_value(base::Value::Type::DICTIONARY);
-    const base::Value* value = pref_data->FindKey(name);
-    if (value)
+    if (const base::Value* value = pref_data->FindKey(name))
       layout_value = value->Clone();
     if (display::DisplayLayoutToJson(display_layout, &layout_value))
       pref_data->SetPath(name, std::move(layout_value));
@@ -172,20 +170,17 @@
 
   void StoreDisplayPropertyForList(const display::DisplayIdList& list,
                                    const std::string& key,
-                                   std::unique_ptr<base::Value> value) {
+                                   base::Value value) {
     std::string name = display::DisplayIdListToString(list);
 
-    DictionaryPrefUpdateDeprecated update(local_state(),
-                                          prefs::kSecondaryDisplays);
-    base::DictionaryValue* pref_data = update.Get();
+    DictionaryPrefUpdate update(local_state(), prefs::kSecondaryDisplays);
+    base::Value* pref_data = update.Get();
 
-    base::Value* layout_value = pref_data->FindKey(name);
-    if (layout_value) {
-      layout_value->SetPath(key,
-                            base::Value::FromUniquePtrValue(std::move(value)));
+    if (base::Value* existing_layout_value = pref_data->FindKey(name)) {
+      existing_layout_value->SetKey(key, std::move(value));
     } else {
-      base::DictionaryValue layout_value;
-      layout_value.SetBoolKey(key, value != nullptr);
+      base::Value layout_value(base::Value::Type::DICTIONARY);
+      layout_value.SetBoolKey(key, true);
       pref_data->SetPath(name, std::move(layout_value));
     }
   }
@@ -193,8 +188,7 @@
   void StoreDisplayBoolPropertyForList(const display::DisplayIdList& list,
                                        const std::string& key,
                                        bool value) {
-    StoreDisplayPropertyForList(list, key,
-                                std::make_unique<base::Value>(value));
+    StoreDisplayPropertyForList(list, key, base::Value(value));
   }
 
   void StoreDisplayLayoutPrefForList(const display::DisplayIdList& list,
@@ -204,12 +198,11 @@
   }
 
   void StoreDisplayOverscan(int64_t id, const gfx::Insets& insets) {
-    DictionaryPrefUpdateDeprecated update(local_state(),
-                                          prefs::kDisplayProperties);
+    DictionaryPrefUpdate update(local_state(), prefs::kDisplayProperties);
     const std::string name = base::NumberToString(id);
 
-    base::DictionaryValue* pref_data = update.Get();
-    base::DictionaryValue insets_value;
+    base::Value* pref_data = update.Get();
+    base::Value insets_value(base::Value::Type::DICTIONARY);
     insets_value.SetIntKey("insets_top", insets.top());
     insets_value.SetIntKey("insets_left", insets.left());
     insets_value.SetIntKey("insets_bottom", insets.bottom());
@@ -226,12 +219,11 @@
 
   void StoreExternalDisplayMirrorInfo(
       const std::set<int64_t>& external_display_mirror_info) {
-    ListPrefUpdateDeprecated update(local_state(),
-                                    prefs::kExternalDisplayMirrorInfo);
-    base::ListValue* pref_data = update.Get();
+    ListPrefUpdate update(local_state(), prefs::kExternalDisplayMirrorInfo);
+    base::Value* pref_data = update.Get();
     pref_data->ClearList();
     for (const auto& id : external_display_mirror_info)
-      pref_data->Append(base::Value(base::NumberToString(id)));
+      pref_data->Append(base::NumberToString(id));
   }
 
   std::string GetRegisteredDisplayPlacementStr(
@@ -1230,8 +1222,7 @@
       display::test::CreateDisplayIdList2(first_display_id, second_display_id);
   StoreDisplayBoolPropertyForList(list, "default_unified", true);
   StoreDisplayPropertyForList(
-      list, "primary-id",
-      std::make_unique<base::Value>(base::NumberToString(first_display_id)));
+      list, "primary-id", base::Value(base::NumberToString(first_display_id)));
   LoadDisplayPreferences();
 
   // Should not restore to unified unless unified desktop is enabled.
diff --git a/ash/public/cpp/shelf_prefs.cc b/ash/public/cpp/shelf_prefs.cc
index f3becc8..cab2e261 100644
--- a/ash/public/cpp/shelf_prefs.cc
+++ b/ash/public/cpp/shelf_prefs.cc
@@ -91,8 +91,7 @@
   if (display_id == display::kInvalidDisplayId)
     return;
 
-  // Avoid DictionaryPrefUpdateDeprecated's notifications for read but
-  // unmodified prefs.
+  // Avoid DictionaryPrefUpdate's notifications for read but unmodified prefs.
   const base::Value* current_shelf_prefs =
       prefs->GetDictionary(prefs::kShelfPreferences);
   DCHECK(current_shelf_prefs);
@@ -106,8 +105,7 @@
       return;
   }
 
-  // TODO(crbug.com/1187061): Refactor this to remove base::DictionaryValue.
-  DictionaryPrefUpdateDeprecated update(prefs, prefs::kShelfPreferences);
+  DictionaryPrefUpdate update(prefs, prefs::kShelfPreferences);
   base::Value* shelf_prefs = update.Get();
   base::Value* display_prefs_weak = shelf_prefs->FindDictKey(display_key);
   if (!display_prefs_weak) {
diff --git a/ash/public/cpp/shelf_types.cc b/ash/public/cpp/shelf_types.cc
index 6fc11c2b..65dafe3 100644
--- a/ash/public/cpp/shelf_types.cc
+++ b/ash/public/cpp/shelf_types.cc
@@ -17,6 +17,15 @@
 
 }  // namespace
 
+std::ostream& operator<<(std::ostream& out, ShelfAutoHideState state) {
+  switch (state) {
+    case SHELF_AUTO_HIDE_SHOWN:
+      return out << "SHOWN";
+    case SHELF_AUTO_HIDE_HIDDEN:
+      return out << "HIDDEN";
+  }
+}
+
 std::ostream& operator<<(std::ostream& out, ShelfBackgroundType type) {
   switch (type) {
     case ShelfBackgroundType::kDefaultBg:
diff --git a/ash/public/cpp/shelf_types.h b/ash/public/cpp/shelf_types.h
index 95ee1b4..d8c590df 100644
--- a/ash/public/cpp/shelf_types.h
+++ b/ash/public/cpp/shelf_types.h
@@ -60,6 +60,9 @@
   SHELF_AUTO_HIDE_HIDDEN,
 };
 
+ASH_PUBLIC_EXPORT std::ostream& operator<<(std::ostream& out,
+                                           ShelfAutoHideState state);
+
 enum ShelfVisibilityState {
   // Always visible.
   SHELF_VISIBLE,
diff --git a/ash/quick_pair/common/fast_pair/fast_pair_metrics.h b/ash/quick_pair/common/fast_pair/fast_pair_metrics.h
index a9498ba4..f46eaa1 100644
--- a/ash/quick_pair/common/fast_pair/fast_pair_metrics.h
+++ b/ash/quick_pair/common/fast_pair/fast_pair_metrics.h
@@ -27,8 +27,12 @@
   kDiscoveryUiDismissed = 11,
   kDiscoveryUiConnectPressed = 12,
   kDiscoveryUiDismissedByUser = 13,
+  kDiscoveryUiLearnMorePressed = 14,
   kPairingFailed = 121,
   kPairingSucceeded = 122,
+  kDiscoveryUiConnectPressedAfterLearnMorePressed = 141,
+  kDiscoveryUiDismissedByUserAfterLearnMorePressed = 142,
+  kDiscoveryUiDismissedAfterLearnMorePressed = 143,
   kErrorUiDismissed = 1211,
   kErrorUiSettingsPressed = 1212,
   kErrorUiDismissedByUser = 1213,
diff --git a/ash/quick_pair/keyed_service/quick_pair_mediator.cc b/ash/quick_pair/keyed_service/quick_pair_mediator.cc
index 41e58834..e7b3066 100644
--- a/ash/quick_pair/keyed_service/quick_pair_mediator.cc
+++ b/ash/quick_pair/keyed_service/quick_pair_mediator.cc
@@ -194,6 +194,7 @@
     } break;
     case DiscoveryAction::kDismissedByUser:
     case DiscoveryAction::kDismissed:
+    case DiscoveryAction::kLearnMore:
       break;
   }
 }
diff --git a/ash/quick_pair/keyed_service/quick_pair_metrics_logger.cc b/ash/quick_pair/keyed_service/quick_pair_metrics_logger.cc
index 927e16f..bdf8abf 100644
--- a/ash/quick_pair/keyed_service/quick_pair_metrics_logger.cc
+++ b/ash/quick_pair/keyed_service/quick_pair_metrics_logger.cc
@@ -98,16 +98,53 @@
                                                DiscoveryAction action) {
   switch (action) {
     case DiscoveryAction::kPairToDevice:
+      if (base::Contains(discovery_learn_more_devices_, device)) {
+        AttemptRecordingFastPairEngagementFlow(
+            *device, FastPairEngagementFlowEvent::
+                         kDiscoveryUiConnectPressedAfterLearnMorePressed);
+        discovery_learn_more_devices_.erase(device);
+        break;
+      }
+
       AttemptRecordingFastPairEngagementFlow(
           *device, FastPairEngagementFlowEvent::kDiscoveryUiConnectPressed);
       device_pairing_start_timestamps_[device] = base::TimeTicks::Now();
       break;
+    case DiscoveryAction::kLearnMore:
+      // We need to record whether or not the Discovery UI for this
+      // device has had the Learn More button pressed because since the
+      // Learn More button is not a terminal state, we need to record
+      // if the subsequent terminal states were reached after the user
+      // has learned more about saving their accounts. So we will check
+      // this map when the user dismisses or saves their account in order
+      // to capture whether or not the user elected to learn more beforehand.
+      discovery_learn_more_devices_.insert(device);
+
+      AttemptRecordingFastPairEngagementFlow(
+          *device, FastPairEngagementFlowEvent::kDiscoveryUiLearnMorePressed);
+      break;
     case DiscoveryAction::kDismissedByUser:
+      if (base::Contains(discovery_learn_more_devices_, device)) {
+        AttemptRecordingFastPairEngagementFlow(
+            *device, FastPairEngagementFlowEvent::
+                         kDiscoveryUiDismissedByUserAfterLearnMorePressed);
+        discovery_learn_more_devices_.erase(device);
+        break;
+      }
+
       AttemptRecordingFastPairEngagementFlow(
           *device, FastPairEngagementFlowEvent::kDiscoveryUiDismissedByUser);
       feature_usage_metrics_logger_->RecordUsage(/*success=*/true);
       break;
     case DiscoveryAction::kDismissed:
+      if (base::Contains(discovery_learn_more_devices_, device)) {
+        AttemptRecordingFastPairEngagementFlow(
+            *device, FastPairEngagementFlowEvent::
+                         kDiscoveryUiDismissedAfterLearnMorePressed);
+        discovery_learn_more_devices_.erase(device);
+        break;
+      }
+
       AttemptRecordingFastPairEngagementFlow(
           *device, FastPairEngagementFlowEvent::kDiscoveryUiDismissed);
       feature_usage_metrics_logger_->RecordUsage(/*success=*/true);
@@ -151,11 +188,11 @@
     AssociateAccountAction action) {
   switch (action) {
     case AssociateAccountAction::kAssoicateAccount:
-      if (base::Contains(learn_more_devices_, device)) {
+      if (base::Contains(associate_account_learn_more_devices_, device)) {
         AttemptRecordingFastPairRetroactiveEngagementFlow(
             *device, FastPairRetroactiveEngagementFlowEvent::
                          kAssociateAccountSavePressedAfterLearnMorePressed);
-        learn_more_devices_.erase(device);
+        associate_account_learn_more_devices_.erase(device);
         break;
       }
 
@@ -171,18 +208,18 @@
       // has learned more about saving their accounts. So we will check
       // this map when the user dismisses or saves their account in order
       // to capture whether or not the user elected to learn more beforehand.
-      learn_more_devices_.insert(device);
+      associate_account_learn_more_devices_.insert(device);
 
       AttemptRecordingFastPairRetroactiveEngagementFlow(
           *device, FastPairRetroactiveEngagementFlowEvent::
                        kAssociateAccountLearnMorePressed);
       break;
     case AssociateAccountAction::kDismissedByUser:
-      if (base::Contains(learn_more_devices_, device)) {
+      if (base::Contains(associate_account_learn_more_devices_, device)) {
         AttemptRecordingFastPairRetroactiveEngagementFlow(
             *device, FastPairRetroactiveEngagementFlowEvent::
                          kAssociateAccountDismissedByUserAfterLearnMorePressed);
-        learn_more_devices_.erase(device);
+        associate_account_learn_more_devices_.erase(device);
         break;
       }
 
@@ -191,11 +228,11 @@
                        kAssociateAccountUiDismissedByUser);
       break;
     case AssociateAccountAction::kDismissed:
-      if (base::Contains(learn_more_devices_, device)) {
+      if (base::Contains(associate_account_learn_more_devices_, device)) {
         AttemptRecordingFastPairRetroactiveEngagementFlow(
             *device, FastPairRetroactiveEngagementFlowEvent::
                          kAssociateAccountDismissedAfterLearnMorePressed);
-        learn_more_devices_.erase(device);
+        associate_account_learn_more_devices_.erase(device);
         break;
       }
 
diff --git a/ash/quick_pair/keyed_service/quick_pair_metrics_logger.h b/ash/quick_pair/keyed_service/quick_pair_metrics_logger.h
index e0f6ea58..feebb1f 100644
--- a/ash/quick_pair/keyed_service/quick_pair_metrics_logger.h
+++ b/ash/quick_pair/keyed_service/quick_pair_metrics_logger.h
@@ -79,12 +79,13 @@
   base::flat_map<scoped_refptr<Device>, base::TimeTicks>
       device_pairing_start_timestamps_;
 
-  // Set of devices of which on the Associate Account UI shown, the Learn More
-  // button was pressed. We need this map to know which
-  // |FastPairRetroactiveEngagementFlowEvent| event to log at the subsequent
-  // AssociateAccount action events that will follow, since the LearnMore
-  // event is not a terminal state.
-  base::flat_set<scoped_refptr<Device>> learn_more_devices_;
+  // Set of devices of which on the Associate Account UI and Discovery UI shown,
+  // the Learn More button was pressed. We need this map to know which
+  // |FastPairRetroactiveEngagementFlowEvent| or
+  // |FastPairEngagementFlowEvent| event to log at the subsequent
+  // events that will follow, since the LearnMore event is not a terminal state.
+  base::flat_set<scoped_refptr<Device>> associate_account_learn_more_devices_;
+  base::flat_set<scoped_refptr<Device>> discovery_learn_more_devices_;
 
   // The classic pairing addresses of Fast Pair devices that we have already
   // paired to.
diff --git a/ash/quick_pair/keyed_service/quick_pair_metrics_logger_unittest.cc b/ash/quick_pair/keyed_service/quick_pair_metrics_logger_unittest.cc
index da944aa..5a5d95c 100644
--- a/ash/quick_pair/keyed_service/quick_pair_metrics_logger_unittest.cc
+++ b/ash/quick_pair/keyed_service/quick_pair_metrics_logger_unittest.cc
@@ -199,6 +199,21 @@
     }
   }
 
+  void SimulateDiscoveryUiLearnMorePressed(Protocol protocol) {
+    switch (protocol) {
+      case Protocol::kFastPairInitial:
+        mock_ui_broker_->NotifyDiscoveryAction(initial_device_,
+                                               DiscoveryAction::kLearnMore);
+        break;
+      case Protocol::kFastPairSubsequent:
+        mock_ui_broker_->NotifyDiscoveryAction(subsequent_device_,
+                                               DiscoveryAction::kLearnMore);
+        break;
+      case Protocol::kFastPairRetroactive:
+        break;
+    }
+  }
+
   void SimulateDiscoveryUiConnectPressed(Protocol protocol) {
     switch (protocol) {
       case Protocol::kFastPairInitial:
@@ -1769,5 +1784,229 @@
   histogram_tester().ExpectTotalCount(kFastPairPairResultMetricRetroactive, 1);
 }
 
+TEST_F(QuickPairMetricsLoggerTest, DiscoveryLearnMorePressed_Initial) {
+  SimulateDiscoveryUiLearnMorePressed(Protocol::kFastPairInitial);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricInitial,
+                FastPairEngagementFlowEvent::kDiscoveryUiLearnMorePressed),
+            1);
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricInitial,
+                FastPairEngagementFlowEvent::
+                    kDiscoveryUiConnectPressedAfterLearnMorePressed),
+            0);
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricInitial,
+                FastPairEngagementFlowEvent::
+                    kDiscoveryUiDismissedByUserAfterLearnMorePressed),
+            0);
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricInitial,
+                FastPairEngagementFlowEvent::
+                    kDiscoveryUiDismissedAfterLearnMorePressed),
+            0);
+}
+
+TEST_F(QuickPairMetricsLoggerTest,
+       LogDiscoveryUiLearnMorePressed_ConnectPressed_Initial) {
+  SimulateDiscoveryUiLearnMorePressed(Protocol::kFastPairInitial);
+  base::RunLoop().RunUntilIdle();
+
+  SimulateDiscoveryUiConnectPressed(Protocol::kFastPairInitial);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricInitial,
+                FastPairEngagementFlowEvent::kDiscoveryUiLearnMorePressed),
+            1);
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricInitial,
+                FastPairEngagementFlowEvent::
+                    kDiscoveryUiConnectPressedAfterLearnMorePressed),
+            1);
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricInitial,
+                FastPairEngagementFlowEvent::
+                    kDiscoveryUiDismissedByUserAfterLearnMorePressed),
+            0);
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricInitial,
+                FastPairEngagementFlowEvent::
+                    kDiscoveryUiDismissedAfterLearnMorePressed),
+            0);
+}
+
+TEST_F(QuickPairMetricsLoggerTest,
+       LogDiscoveryUiLearnMorePressed_DismissedByUser_Initial) {
+  SimulateDiscoveryUiLearnMorePressed(Protocol::kFastPairInitial);
+  base::RunLoop().RunUntilIdle();
+
+  SimulateDiscoveryUiDismissedByUser(Protocol::kFastPairInitial);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricInitial,
+                FastPairEngagementFlowEvent::kDiscoveryUiLearnMorePressed),
+            1);
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricInitial,
+                FastPairEngagementFlowEvent::
+                    kDiscoveryUiConnectPressedAfterLearnMorePressed),
+            0);
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricInitial,
+                FastPairEngagementFlowEvent::
+                    kDiscoveryUiDismissedByUserAfterLearnMorePressed),
+            1);
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricInitial,
+                FastPairEngagementFlowEvent::
+                    kDiscoveryUiDismissedAfterLearnMorePressed),
+            0);
+}
+
+TEST_F(QuickPairMetricsLoggerTest,
+       LogDiscoveryUiLearnMorePressed_Dismissed_Initial) {
+  SimulateDiscoveryUiLearnMorePressed(Protocol::kFastPairInitial);
+  base::RunLoop().RunUntilIdle();
+
+  SimulateDiscoveryUiDismissed(Protocol::kFastPairInitial);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricInitial,
+                FastPairEngagementFlowEvent::kDiscoveryUiLearnMorePressed),
+            1);
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricInitial,
+                FastPairEngagementFlowEvent::
+                    kDiscoveryUiConnectPressedAfterLearnMorePressed),
+            0);
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricInitial,
+                FastPairEngagementFlowEvent::
+                    kDiscoveryUiDismissedByUserAfterLearnMorePressed),
+            0);
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricInitial,
+                FastPairEngagementFlowEvent::
+                    kDiscoveryUiDismissedAfterLearnMorePressed),
+            1);
+}
+
+TEST_F(QuickPairMetricsLoggerTest, DiscoveryLearnMorePressed_Subsequent) {
+  SimulateDiscoveryUiLearnMorePressed(Protocol::kFastPairSubsequent);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricSubsequent,
+                FastPairEngagementFlowEvent::kDiscoveryUiLearnMorePressed),
+            1);
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricSubsequent,
+                FastPairEngagementFlowEvent::
+                    kDiscoveryUiConnectPressedAfterLearnMorePressed),
+            0);
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricSubsequent,
+                FastPairEngagementFlowEvent::
+                    kDiscoveryUiDismissedByUserAfterLearnMorePressed),
+            0);
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricSubsequent,
+                FastPairEngagementFlowEvent::
+                    kDiscoveryUiDismissedAfterLearnMorePressed),
+            0);
+}
+
+TEST_F(QuickPairMetricsLoggerTest,
+       LogDiscoveryUiLearnMorePressed_ConnectPressed_Subsequent) {
+  SimulateDiscoveryUiLearnMorePressed(Protocol::kFastPairSubsequent);
+  base::RunLoop().RunUntilIdle();
+
+  SimulateDiscoveryUiConnectPressed(Protocol::kFastPairSubsequent);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricSubsequent,
+                FastPairEngagementFlowEvent::kDiscoveryUiLearnMorePressed),
+            1);
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricSubsequent,
+                FastPairEngagementFlowEvent::
+                    kDiscoveryUiConnectPressedAfterLearnMorePressed),
+            1);
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricSubsequent,
+                FastPairEngagementFlowEvent::
+                    kDiscoveryUiDismissedByUserAfterLearnMorePressed),
+            0);
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricSubsequent,
+                FastPairEngagementFlowEvent::
+                    kDiscoveryUiDismissedAfterLearnMorePressed),
+            0);
+}
+
+TEST_F(QuickPairMetricsLoggerTest,
+       LogDiscoveryUiLearnMorePressed_DismissedByUser_Subsequent) {
+  SimulateDiscoveryUiLearnMorePressed(Protocol::kFastPairSubsequent);
+  base::RunLoop().RunUntilIdle();
+
+  SimulateDiscoveryUiDismissedByUser(Protocol::kFastPairSubsequent);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricSubsequent,
+                FastPairEngagementFlowEvent::kDiscoveryUiLearnMorePressed),
+            1);
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricSubsequent,
+                FastPairEngagementFlowEvent::
+                    kDiscoveryUiConnectPressedAfterLearnMorePressed),
+            0);
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricSubsequent,
+                FastPairEngagementFlowEvent::
+                    kDiscoveryUiDismissedByUserAfterLearnMorePressed),
+            1);
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricSubsequent,
+                FastPairEngagementFlowEvent::
+                    kDiscoveryUiDismissedAfterLearnMorePressed),
+            0);
+}
+
+TEST_F(QuickPairMetricsLoggerTest,
+       LogDiscoveryUiLearnMorePressed_Dismissed_Subsequent) {
+  SimulateDiscoveryUiLearnMorePressed(Protocol::kFastPairSubsequent);
+  base::RunLoop().RunUntilIdle();
+
+  SimulateDiscoveryUiDismissed(Protocol::kFastPairSubsequent);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricSubsequent,
+                FastPairEngagementFlowEvent::kDiscoveryUiLearnMorePressed),
+            1);
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricSubsequent,
+                FastPairEngagementFlowEvent::
+                    kDiscoveryUiConnectPressedAfterLearnMorePressed),
+            0);
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricSubsequent,
+                FastPairEngagementFlowEvent::
+                    kDiscoveryUiDismissedByUserAfterLearnMorePressed),
+            0);
+  EXPECT_EQ(histogram_tester().GetBucketCount(
+                kFastPairEngagementFlowMetricSubsequent,
+                FastPairEngagementFlowEvent::
+                    kDiscoveryUiDismissedAfterLearnMorePressed),
+            1);
+}
+
 }  // namespace quick_pair
 }  // namespace ash
diff --git a/ash/quick_pair/repository/fast_pair/pending_write_store.cc b/ash/quick_pair/repository/fast_pair/pending_write_store.cc
index 6a97aeb..39bbb9c 100644
--- a/ash/quick_pair/repository/fast_pair/pending_write_store.cc
+++ b/ash/quick_pair/repository/fast_pair/pending_write_store.cc
@@ -43,8 +43,7 @@
     QP_LOG(WARNING) << __func__ << ": No user pref service available.";
     return;
   }
-  DictionaryPrefUpdateDeprecated update(pref_service,
-                                        kFastPairPendingWritesPref);
+  DictionaryPrefUpdate update(pref_service, kFastPairPendingWritesPref);
   update->SetStringKey(mac_address, hex_model_id);
 }
 
@@ -78,8 +77,7 @@
     return;
   }
 
-  DictionaryPrefUpdateDeprecated update(pref_service,
-                                        kFastPairPendingWritesPref);
+  DictionaryPrefUpdate update(pref_service, kFastPairPendingWritesPref);
   update->RemoveKey(mac_address);
 }
 
@@ -90,7 +88,7 @@
     QP_LOG(WARNING) << __func__ << ": No user pref service available.";
     return;
   }
-  ListPrefUpdateDeprecated update(pref_service, kFastPairPendingDeletesPref);
+  ListPrefUpdate update(pref_service, kFastPairPendingDeletesPref);
   update->Append(hex_account_key);
 }
 
@@ -125,7 +123,7 @@
     return;
   }
 
-  ListPrefUpdateDeprecated update(pref_service, kFastPairPendingDeletesPref);
+  ListPrefUpdate update(pref_service, kFastPairPendingDeletesPref);
   update->EraseListValue(base::Value(hex_account_key));
 }
 
diff --git a/ash/quick_pair/repository/fast_pair/saved_device_registry.cc b/ash/quick_pair/repository/fast_pair/saved_device_registry.cc
index 55dc44d..b659e2e6 100644
--- a/ash/quick_pair/repository/fast_pair/saved_device_registry.cc
+++ b/ash/quick_pair/repository/fast_pair/saved_device_registry.cc
@@ -37,8 +37,7 @@
     return;
   }
   std::string encoded = base::Base64Encode(account_key);
-  DictionaryPrefUpdateDeprecated update(pref_service,
-                                        kFastPairSavedDevicesPref);
+  DictionaryPrefUpdate update(pref_service, kFastPairSavedDevicesPref);
   update->SetStringKey(mac_address, encoded);
 }
 
diff --git a/ash/quick_pair/ui/actions.cc b/ash/quick_pair/ui/actions.cc
index cef1b8f..b629f010 100644
--- a/ash/quick_pair/ui/actions.cc
+++ b/ash/quick_pair/ui/actions.cc
@@ -18,6 +18,9 @@
     case DiscoveryAction::kDismissed:
       stream << "[Dismissed]";
       break;
+    case DiscoveryAction::kLearnMore:
+      stream << "[Learn more]";
+      break;
   }
 
   return stream;
diff --git a/ash/quick_pair/ui/actions.h b/ash/quick_pair/ui/actions.h
index 23d8217..99aab46 100644
--- a/ash/quick_pair/ui/actions.h
+++ b/ash/quick_pair/ui/actions.h
@@ -14,7 +14,8 @@
 enum class COMPONENT_EXPORT(QUICK_PAIR_UI) DiscoveryAction {
   kPairToDevice = 0,
   kDismissedByUser = 1,
-  kDismissed = 2
+  kDismissed = 2,
+  kLearnMore = 3,
 };
 
 enum class COMPONENT_EXPORT(QUICK_PAIR_UI) AssociateAccountAction {
diff --git a/ash/quick_pair/ui/fast_pair/fast_pair_notification_controller.cc b/ash/quick_pair/ui/fast_pair/fast_pair_notification_controller.cc
index df843a318d..1fc5b6bc 100644
--- a/ash/quick_pair/ui/fast_pair/fast_pair_notification_controller.cc
+++ b/ash/quick_pair/ui/fast_pair/fast_pair_notification_controller.cc
@@ -159,6 +159,7 @@
     const std::u16string& device_name,
     const gfx::Image device_image,
     base::RepeatingClosure on_connect_clicked,
+    base::RepeatingClosure on_learn_more_clicked,
     base::OnceCallback<void(bool)> on_close) {
   std::unique_ptr<message_center::Notification> discovery_notification =
       CreateNotification(
@@ -171,13 +172,15 @@
 
   message_center::ButtonInfo connect_button(
       l10n_util::GetStringUTF16(IDS_FAST_PAIR_CONNECT_BUTTON));
-  discovery_notification->set_buttons({connect_button});
+  message_center::ButtonInfo learn_more_button(
+      l10n_util::GetStringUTF16(IDS_FAST_PAIR_LEARN_MORE_BUTTON));
+  discovery_notification->set_buttons({connect_button, learn_more_button});
 
   discovery_notification->set_delegate(
       base::MakeRefCounted<NotificationDelegate>(
           /*on_primary_click=*/on_connect_clicked,
           /*on_close=*/std::move(on_close),
-          /*on_secondary_click=*/base::DoNothing(),
+          /*on_secondary_click=*/on_learn_more_clicked,
           /*expire_notification_timer=*/&expire_notification_timer_));
   discovery_notification->set_image(device_image);
 
diff --git a/ash/quick_pair/ui/fast_pair/fast_pair_notification_controller.h b/ash/quick_pair/ui/fast_pair/fast_pair_notification_controller.h
index 315c7796..09a6fab 100644
--- a/ash/quick_pair/ui/fast_pair/fast_pair_notification_controller.h
+++ b/ash/quick_pair/ui/fast_pair/fast_pair_notification_controller.h
@@ -33,6 +33,7 @@
   void ShowDiscoveryNotification(const std::u16string& device_name,
                                  gfx::Image device_image,
                                  base::RepeatingClosure on_connect_clicked,
+                                 base::RepeatingClosure on_learn_more_clicked,
                                  base::OnceCallback<void(bool)> on_close);
   void ShowPairingNotification(const std::u16string& device_name,
                                gfx::Image device_image,
diff --git a/ash/quick_pair/ui/fast_pair/fast_pair_presenter.cc b/ash/quick_pair/ui/fast_pair/fast_pair_presenter.cc
index 34608a3..eb4e1a9 100644
--- a/ash/quick_pair/ui/fast_pair/fast_pair_presenter.cc
+++ b/ash/quick_pair/ui/fast_pair/fast_pair_presenter.cc
@@ -74,6 +74,8 @@
       device_metadata->image(),
       base::BindRepeating(&FastPairPresenter::OnDiscoveryClicked,
                           weak_pointer_factory_.GetWeakPtr(), callback),
+      base::BindRepeating(&FastPairPresenter::OnDiscoveryLearnMoreClicked,
+                          weak_pointer_factory_.GetWeakPtr(), callback),
       base::BindOnce(&FastPairPresenter::OnDiscoveryDismissed,
                      weak_pointer_factory_.GetWeakPtr(), callback));
 }
@@ -88,6 +90,12 @@
                               : DiscoveryAction::kDismissed);
 }
 
+void FastPairPresenter::OnDiscoveryLearnMoreClicked(
+    DiscoveryCallback callback) {
+  // TODO (b/207589697): Implement support for "Learn More" Buttons.
+  callback.Run(DiscoveryAction::kLearnMore);
+}
+
 void FastPairPresenter::ShowPairing(scoped_refptr<Device> device) {
   const auto metadata_id = device->metadata_id;
   FastPairRepository::Get()->GetDeviceMetadata(
@@ -192,8 +200,9 @@
       base::ASCIIToUTF16(email), device_metadata->image(),
       base::BindRepeating(&FastPairPresenter::OnAssociateAccountActionClicked,
                           weak_pointer_factory_.GetWeakPtr(), callback),
-      base::BindRepeating(&FastPairPresenter::OnLearnMoreClicked,
-                          weak_pointer_factory_.GetWeakPtr(), callback),
+      base::BindRepeating(
+          &FastPairPresenter::OnAssociateAccountLearnMoreClicked,
+          weak_pointer_factory_.GetWeakPtr(), callback),
       base::BindOnce(&FastPairPresenter::OnAssociateAccountDismissed,
                      weak_pointer_factory_.GetWeakPtr(), callback));
 }
@@ -203,8 +212,9 @@
   callback.Run(AssociateAccountAction::kAssoicateAccount);
 }
 
-void FastPairPresenter::OnLearnMoreClicked(AssociateAccountCallback callback) {
-  // TODO (crbug/1256983): Implement support for "Learn More" Button in Show
+void FastPairPresenter::OnAssociateAccountLearnMoreClicked(
+    AssociateAccountCallback callback) {
+  // TODO (b/207589697): Implement support for "Learn More" Button in Show
   // Associate Account Notification
   callback.Run(AssociateAccountAction::kLearnMore);
 }
diff --git a/ash/quick_pair/ui/fast_pair/fast_pair_presenter.h b/ash/quick_pair/ui/fast_pair/fast_pair_presenter.h
index eee2a66..7a40bc1 100644
--- a/ash/quick_pair/ui/fast_pair/fast_pair_presenter.h
+++ b/ash/quick_pair/ui/fast_pair/fast_pair_presenter.h
@@ -45,13 +45,14 @@
  private:
   void OnDiscoveryClicked(DiscoveryCallback action_callback);
   void OnDiscoveryDismissed(DiscoveryCallback callback, bool user_dismissed);
+  void OnDiscoveryLearnMoreClicked(DiscoveryCallback action_callback);
 
   void OnNavigateToSettings(PairingFailedCallback callback);
   void OnPairingFailedDismissed(PairingFailedCallback callback,
                                 bool user_dismissed);
 
   void OnAssociateAccountActionClicked(AssociateAccountCallback callback);
-  void OnLearnMoreClicked(AssociateAccountCallback callback);
+  void OnAssociateAccountLearnMoreClicked(AssociateAccountCallback callback);
   void OnAssociateAccountDismissed(AssociateAccountCallback callback,
                                    bool user_dismissed);
 
diff --git a/ash/shelf/contextual_tooltip.cc b/ash/shelf/contextual_tooltip.cc
index 158bf7d2..1215c40 100644
--- a/ash/shelf/contextual_tooltip.cc
+++ b/ash/shelf/contextual_tooltip.cc
@@ -228,7 +228,7 @@
 
 void HandleNudgeShown(PrefService* prefs, TooltipType type) {
   const int shown_count = GetShownCount(prefs, type);
-  DictionaryPrefUpdateDeprecated update(prefs, prefs::kContextualTooltips);
+  DictionaryPrefUpdate update(prefs, prefs::kContextualTooltips);
   update->SetIntPath(GetPath(type, kShownCount), shown_count + 1);
   update->SetPath(GetPath(type, kLastTimeShown), base::TimeToValue(GetTime()));
   GetStatusTracker(type)->HandleNudgeShown(base::TimeTicks::Now());
@@ -236,7 +236,7 @@
 
 void HandleGesturePerformed(PrefService* prefs, TooltipType type) {
   const int success_count = GetSuccessCount(prefs, type);
-  DictionaryPrefUpdateDeprecated update(prefs, prefs::kContextualTooltips);
+  DictionaryPrefUpdate update(prefs, prefs::kContextualTooltips);
   update->SetIntPath(GetPath(type, kSuccessCount), success_count + 1);
   GetStatusTracker(type)->HandleGesturePerformed(base::TimeTicks::Now());
 }
@@ -256,10 +256,10 @@
 
 void ClearPrefs() {
   DCHECK(Shell::Get()->session_controller()->GetLastActiveUserPrefService());
-  DictionaryPrefUpdateDeprecated update(
+  DictionaryPrefUpdate update(
       Shell::Get()->session_controller()->GetLastActiveUserPrefService(),
       prefs::kContextualTooltips);
-  base::DictionaryValue* nudges_dict = update.Get();
+  base::Value* nudges_dict = update.Get();
   if (nudges_dict && !nudges_dict->DictEmpty())
     nudges_dict->DictClear();
 }
diff --git a/ash/shelf/hotseat_widget_unittest.cc b/ash/shelf/hotseat_widget_unittest.cc
index 615fc7b..bcc3d08 100644
--- a/ash/shelf/hotseat_widget_unittest.cc
+++ b/ash/shelf/hotseat_widget_unittest.cc
@@ -122,6 +122,9 @@
     return shelf_auto_hide_behavior_;
   }
   bool is_assistant_enabled() const { return is_assistant_enabled_; }
+  bool navigation_buttons_shown_in_tablet_mode() const {
+    return navigation_buttons_shown_in_tablet_mode_;
+  }
   AssistantTestApi* assistant_test_api() { return assistant_test_api_.get(); }
 
   void ShowShelfAndActivateAssistant() {
@@ -322,14 +325,15 @@
   HotseatTransitionAnimator* hotseat_transition_animator_;
 };
 
-// Used to test the Hotseat, ScrollabeShelf, and DenseShelf features.
+// Used to test the Hotseat, ScrollableShelf, and DenseShelf features.
 INSTANTIATE_TEST_SUITE_P(
     All,
     HotseatWidgetTest,
-    testing::Combine(testing::Values(ShelfAutoHideBehavior::kNever,
-                                     ShelfAutoHideBehavior::kAlways),
-                     testing::Bool(),
-                     testing::Bool()));
+    testing::Combine(
+        testing::Values(ShelfAutoHideBehavior::kNever,
+                        ShelfAutoHideBehavior::kAlways),
+        /*is_assistant_enabled*/ testing::Bool(),
+        /*navigation_buttons_shown_in_tablet_mode*/ testing::Bool()));
 
 TEST_P(HotseatWidgetTest, LongPressHomeWithoutAppWindow) {
   GetPrimaryShelf()->SetAutoHideBehavior(shelf_auto_hide_behavior());
@@ -374,6 +378,10 @@
     // |ShowShelfAndActivateAssistant()| will bring up shelf so it will trigger
     // one hotseat state change.
     expected_state.push_back(HotseatState::kExtended);
+    // Launching the assistant from a shelf button on an autohidden shelf will
+    // hide the shelf at the end of the operation.
+    if (is_assistant_enabled() && navigation_buttons_shown_in_tablet_mode())
+      expected_state.push_back(HotseatState::kHidden);
   }
   watcher.CheckEqual(expected_state);
 }
diff --git a/ash/shelf/launcher_nudge_controller.cc b/ash/shelf/launcher_nudge_controller.cc
index 5f9a7635e..c48da84a 100644
--- a/ash/shelf/launcher_nudge_controller.cc
+++ b/ash/shelf/launcher_nudge_controller.cc
@@ -51,7 +51,7 @@
   if (!dictionary)
     return base::Time();
   absl::optional<base::Time> last_shown_time =
-      base::ValueToTime(dictionary->FindPath(kLastShownTime));
+      base::ValueToTime(dictionary->FindKey(kLastShownTime));
   return last_shown_time.value_or(base::Time());
 }
 
@@ -64,7 +64,7 @@
   if (!dictionary)
     return base::Time();
   absl::optional<base::Time> first_login_time =
-      base::ValueToTime(dictionary->FindPath(kFirstLoginTime));
+      base::ValueToTime(dictionary->FindKey(kFirstLoginTime));
   return first_login_time.value_or(base::Time());
 }
 
@@ -74,7 +74,7 @@
       prefs->GetDictionary(prefs::kShelfLauncherNudge);
   if (!dictionary)
     return false;
-  return dictionary->FindBoolPath(kWasLauncherShown).value_or(false);
+  return dictionary->FindBoolKey(kWasLauncherShown).value_or(false);
 }
 
 }  // namespace
@@ -117,7 +117,7 @@
       prefs->GetDictionary(prefs::kShelfLauncherNudge);
   if (!dictionary)
     return 0;
-  return dictionary->FindIntPath(kShownCount).value_or(0);
+  return dictionary->FindIntKey(kShownCount).value_or(0);
 }
 
 base::TimeDelta LauncherNudgeController::GetNudgeInterval(
@@ -195,9 +195,9 @@
     return;
 
   const int shown_count = GetShownCount(prefs);
-  DictionaryPrefUpdateDeprecated update(prefs, prefs::kShelfLauncherNudge);
-  update->SetIntPath(kShownCount, shown_count + 1);
-  update->SetPath(kLastShownTime, base::TimeToValue(GetNow()));
+  DictionaryPrefUpdate update(prefs, prefs::kShelfLauncherNudge);
+  update->SetIntKey(kShownCount, shown_count + 1);
+  update->SetKey(kLastShownTime, base::TimeToValue(GetNow()));
 }
 
 void LauncherNudgeController::MaybeShowNudge() {
@@ -249,8 +249,8 @@
   if (Shell::Get()->session_controller()->IsUserFirstLogin()) {
     // If the current logged in user is a new one, record the first login time
     // to know when to show the nudge.
-    DictionaryPrefUpdateDeprecated update(prefs, prefs::kShelfLauncherNudge);
-    update->SetPath(kFirstLoginTime, base::TimeToValue(GetNow()));
+    DictionaryPrefUpdate update(prefs, prefs::kShelfLauncherNudge);
+    update->SetKey(kFirstLoginTime, base::TimeToValue(GetNow()));
   } else if (GetFirstLoginTime(prefs).is_null()) {
     // For the users that has logged in before the nudge feature is landed, we
     // assume the user has opened the launcher before and thus don't show the
@@ -278,8 +278,8 @@
     return;
 
   if (!WasLauncherShownPreviously(prefs) && shown) {
-    DictionaryPrefUpdateDeprecated update(prefs, prefs::kShelfLauncherNudge);
-    update->SetBoolPath(kWasLauncherShown, true);
+    DictionaryPrefUpdate update(prefs, prefs::kShelfLauncherNudge);
+    update->SetBoolKey(kWasLauncherShown, true);
   }
 }
 
diff --git a/ash/shelf/shelf.cc b/ash/shelf/shelf.cc
index e1317667..4d9f30d 100644
--- a/ash/shelf/shelf.cc
+++ b/ash/shelf/shelf.cc
@@ -239,6 +239,7 @@
       shelf_layout_manager->LockAutoHideState(true);
     } else if (event->type() == ui::ET_TOUCH_RELEASED ||
                event->type() == ui::ET_TOUCH_CANCELLED) {
+      // Unlock auto hide (and eventually recompute auto hide state).
       shelf_layout_manager->LockAutoHideState(false);
     }
   }
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index ab5af4a..5ac06d8e 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -1080,6 +1080,8 @@
 
 void ShelfLayoutManager::OnAppListVisibilityChanged(bool shown,
                                                     int64_t display_id) {
+  DVLOG(1) << __PRETTY_FUNCTION__ << " shown " << shown << " display "
+           << display_id;
   // Shell may be under destruction.
   if (!shelf_widget_ || !shelf_widget_->GetNativeWindow())
     return;
@@ -1194,6 +1196,19 @@
   return target_opacity_;
 }
 
+void ShelfLayoutManager::LockAutoHideState(bool lock_auto_hide_state) {
+  if (is_auto_hide_state_locked_ == lock_auto_hide_state)
+    return;
+  is_auto_hide_state_locked_ = lock_auto_hide_state;
+  // If unlocking, recompute the current state, but do it after the current
+  // event is processed.
+  if (!is_auto_hide_state_locked_) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(&ShelfLayoutManager::UpdateAutoHideState,
+                                  weak_factory_.GetWeakPtr()));
+  }
+}
+
 void ShelfLayoutManager::OnShelfConfigUpdated() {
   SetState(state_.visibility_state);
   LayoutShelf(/*animate=*/true);
diff --git a/ash/shelf/shelf_layout_manager.h b/ash/shelf/shelf_layout_manager.h
index 4a30d225..7a8dde81 100644
--- a/ash/shelf/shelf_layout_manager.h
+++ b/ash/shelf/shelf_layout_manager.h
@@ -288,9 +288,9 @@
 
   bool is_shelf_auto_hidden() const { return state_.IsShelfAutoHidden(); }
 
-  void LockAutoHideState(bool lock_auto_hide_state) {
-    is_auto_hide_state_locked_ = lock_auto_hide_state;
-  }
+  // Locks or unlocks the state of shelf auto-hide. On unlock, the auto-hide
+  // state will be recomputed.
+  void LockAutoHideState(bool lock_auto_hide_state);
 
   ShelfAutoHideBehavior auto_hide_behavior() const {
     return shelf_->auto_hide_behavior();
diff --git a/ash/shelf/shelf_layout_manager_unittest.cc b/ash/shelf/shelf_layout_manager_unittest.cc
index 9566a02..d1f6628 100644
--- a/ash/shelf/shelf_layout_manager_unittest.cc
+++ b/ash/shelf/shelf_layout_manager_unittest.cc
@@ -1701,7 +1701,11 @@
   GetAppListTestHelper()->CheckVisibility(false);
 }
 
-TEST_F(ShelfLayoutManagerTest, SwipingUpOnShelfInLaptopModeForAppList) {
+TEST_F(ShelfLayoutManagerTest, SwipingUpOnShelfInLaptopModeShowsAppList) {
+  // ProductivityLauncher does not support swipe-to-show.
+  if (features::IsProductivityLauncherEnabled())
+    return;
+
   Shelf* shelf = GetPrimaryShelf();
   EXPECT_EQ(ShelfAlignment::kBottom, shelf->alignment());
   EXPECT_EQ(ShelfAutoHideBehavior::kNever, shelf->auto_hide_behavior());
@@ -1754,8 +1758,25 @@
   GetAppListTestHelper()->DismissAndRunLoop();
   GetAppListTestHelper()->CheckVisibility(false);
   GetAppListTestHelper()->CheckState(AppListViewState::kClosed);
+}
 
+// TODO(https://crbug.com/1286875): This behavior is broken in production. An
+// auto-hidden shelf will close after a short swipe up that fails to show the
+// app list.
+TEST_F(ShelfLayoutManagerTest,
+       DISABLED_ShortSwipeUpOnAutoHideShelfKeepsShelfOpen) {
+  Shelf* shelf = GetPrimaryShelf();
   shelf->SetAutoHideBehavior(ShelfAutoHideBehavior::kAlways);
+
+  auto* generator = GetEventGenerator();
+  constexpr base::TimeDelta kTimeDelta = base::Milliseconds(100);
+  constexpr int kNumScrollSteps = 4;
+
+  // Starts the drag from the center of the shelf's bottom.
+  gfx::Rect shelf_bounds = GetVisibleShelfWidgetBoundsInScreen();
+  gfx::Point start = shelf_bounds.bottom_center();
+  gfx::Vector2d delta;
+
   // Create a normal unmaximized window, the auto-hide shelf should be hidden.
   aura::Window* window = CreateTestWindow();
   window->SetBounds(gfx::Rect(0, 0, 100, 100));
@@ -1765,7 +1786,7 @@
   EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState());
 
   // Swiping up to show the auto-hide shelf.
-  end = shelf_bounds.top_center();
+  gfx::Point end = shelf_bounds.top_center();
   generator->GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
   EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState());
 
@@ -1777,6 +1798,7 @@
   generator->GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
   GetAppListTestHelper()->WaitUntilIdle();
   GetAppListTestHelper()->CheckVisibility(false);
+  // This line fails, see https://crbug.com/1286875.
   EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState());
 }
 
diff --git a/ash/system/message_center/ash_notification_view.cc b/ash/system/message_center/ash_notification_view.cc
index d3c98b5..4a98fd3 100644
--- a/ash/system/message_center/ash_notification_view.cc
+++ b/ash/system/message_center/ash_notification_view.cc
@@ -205,6 +205,17 @@
 BEGIN_METADATA(AshNotificationView, NotificationTitleRow, views::View)
 END_METADATA
 
+void AshNotificationView::GroupedNotificationsContainer::
+    ChildPreferredSizeChanged(views::View* view) {
+  PreferredSizeChanged();
+  parent_notification_view_->GroupedNotificationsPreferredSizeChanged();
+}
+
+void AshNotificationView::GroupedNotificationsContainer::
+    SetParentNotificationView(AshNotificationView* parent_notification_view) {
+  parent_notification_view_ = parent_notification_view;
+}
+
 AshNotificationView::NotificationTitleRow::NotificationTitleRow(
     const std::u16string& title)
     : title_view_(AddChildView(GenerateTitleView(title))),
@@ -413,8 +424,9 @@
             .SetDrawOverflowIndicator(false)
             .ClipHeightTo(0, std::numeric_limits<int>::max())
             .SetContents(
-                views::Builder<views::BoxLayoutView>()
+                views::Builder<GroupedNotificationsContainer>()
                     .CopyAddressTo(&grouped_notifications_container_)
+                    .SetParentNotificationView(this)
                     .SetOrientation(Orientation::kVertical)
                     .SetInsideBorderInsets(kGroupedNotificationContainerInsets)
                     .SetBetweenChildSpacing(
@@ -540,6 +552,10 @@
   PerformExpandCollapseAnimation();
 }
 
+void AshNotificationView::GroupedNotificationsPreferredSizeChanged() {
+  PreferredSizeChanged();
+}
+
 base::TimeDelta AshNotificationView::GetBoundsAnimationDuration(
     const message_center::Notification& notification) const {
   // This is called after the parent gets notified of
diff --git a/ash/system/message_center/ash_notification_view.h b/ash/system/message_center/ash_notification_view.h
index dab3584..638d4d8 100644
--- a/ash/system/message_center/ash_notification_view.h
+++ b/ash/system/message_center/ash_notification_view.h
@@ -54,6 +54,9 @@
   // Toggle the expand state of the notification.
   void ToggleExpand();
 
+  // Called when a child notificaiton's preferred size changes.
+  void GroupedNotificationsPreferredSizeChanged();
+
   // Gets the animation duration for a recent bounds change. Called after
   // `PreferredSizeChanged()`, so the current state is the target state.
   base::TimeDelta GetBoundsAnimationDuration(
@@ -97,6 +100,28 @@
   void ToggleInlineSettings(const ui::Event& event) override;
   void ActionButtonPressed(size_t index, const ui::Event& event) override;
 
+  // View containing all grouped notifications, propagates size changes
+  // to the parent notification view.
+  class GroupedNotificationsContainer : public views::BoxLayoutView {
+   public:
+    GroupedNotificationsContainer() = default;
+    GroupedNotificationsContainer(const GroupedNotificationsContainer&) =
+        delete;
+    GroupedNotificationsContainer& operator=(
+        const GroupedNotificationsContainer&) = delete;
+    void ChildPreferredSizeChanged(views::View* view) override;
+    void SetParentNotificationView(
+        AshNotificationView* parent_notification_view);
+
+   private:
+    AshNotificationView* parent_notification_view_ = nullptr;
+  };
+  BEGIN_VIEW_BUILDER(/*no export*/,
+                     GroupedNotificationsContainer,
+                     views::BoxLayoutView)
+  VIEW_BUILDER_PROPERTY(AshNotificationView*, ParentNotificationView)
+  END_VIEW_BUILDER
+
  private:
   friend class AshNotificationViewTest;
 
@@ -229,4 +254,7 @@
 
 }  // namespace ash
 
+DEFINE_VIEW_BUILDER(/* no export */,
+                    ash::AshNotificationView::GroupedNotificationsContainer)
+
 #endif  // ASH_SYSTEM_MESSAGE_CENTER_ASH_NOTIFICATION_VIEW_H_
diff --git a/ash/wallpaper/wallpaper_controller_impl.cc b/ash/wallpaper/wallpaper_controller_impl.cc
index d8aca2d..740e4ea 100644
--- a/ash/wallpaper/wallpaper_controller_impl.cc
+++ b/ash/wallpaper/wallpaper_controller_impl.cc
@@ -612,7 +612,7 @@
   if (!pref_service)
     return false;
 
-  DictionaryPrefUpdateDeprecated wallpaper_update(pref_service, pref_name);
+  DictionaryPrefUpdate wallpaper_update(pref_service, pref_name);
   base::Value wallpaper_info_dict(base::Value::Type::DICTIONARY);
   if (info.asset_id.has_value()) {
     wallpaper_info_dict.SetStringPath(
@@ -665,8 +665,7 @@
                          const std::string& pref_name) {
   if (!pref_service)
     return;
-  DictionaryPrefUpdateDeprecated prefs_wallpapers_info_update(pref_service,
-                                                              pref_name);
+  DictionaryPrefUpdate prefs_wallpapers_info_update(pref_service, pref_name);
   prefs_wallpapers_info_update->RemoveKey(account_id.GetUserEmail());
 }
 
@@ -996,8 +995,8 @@
   WallpaperInfo old_info;
   if (local_state_ && GetUserWallpaperInfo(account_id, &old_info)) {
     // Remove the color cache of the previous wallpaper if it exists.
-    DictionaryPrefUpdateDeprecated wallpaper_colors_update(
-        local_state_, prefs::kWallpaperColors);
+    DictionaryPrefUpdate wallpaper_colors_update(local_state_,
+                                                 prefs::kWallpaperColors);
     wallpaper_colors_update->RemoveKey(old_info.location);
   }
   bool success = SetLocalWallpaperInfo(account_id, info);
@@ -1884,8 +1883,8 @@
   if (!local_state_)
     return;
   // Remove the color cache of the previous wallpaper if it exists.
-  DictionaryPrefUpdateDeprecated wallpaper_colors_update(
-      local_state_, prefs::kWallpaperColors);
+  DictionaryPrefUpdate wallpaper_colors_update(local_state_,
+                                               prefs::kWallpaperColors);
   wallpaper_colors_update->RemoveKey(info.location);
 }
 
@@ -2418,14 +2417,13 @@
     const std::string& current_location) {
   if (!local_state_)
     return;
-  DictionaryPrefUpdateDeprecated wallpaper_colors_update(
-      local_state_, prefs::kWallpaperColors);
-  auto wallpaper_colors = std::make_unique<base::ListValue>();
+  DictionaryPrefUpdate wallpaper_colors_update(local_state_,
+                                               prefs::kWallpaperColors);
+  base::Value wallpaper_colors(base::Value::Type::LIST);
   for (SkColor color : colors)
-    wallpaper_colors->Append(static_cast<double>(color));
-  wallpaper_colors_update->SetKey(
-      current_location,
-      base::Value::FromUniquePtrValue(std::move(wallpaper_colors)));
+    wallpaper_colors.Append(static_cast<double>(color));
+  wallpaper_colors_update->SetKey(current_location,
+                                  std::move(wallpaper_colors));
 }
 
 absl::optional<std::vector<SkColor>> WallpaperControllerImpl::GetCachedColors(
diff --git a/ash/wallpaper/wallpaper_controller_unittest.cc b/ash/wallpaper/wallpaper_controller_unittest.cc
index c19fab7..bb901a2 100644
--- a/ash/wallpaper/wallpaper_controller_unittest.cc
+++ b/ash/wallpaper/wallpaper_controller_unittest.cc
@@ -259,16 +259,15 @@
   }
 }
 
-std::unique_ptr<base::DictionaryValue> CreateWallpaperInfoDict(
-    WallpaperInfo info) {
-  auto wallpaper_info_dict = std::make_unique<base::DictionaryValue>();
+base::Value CreateWallpaperInfoDict(WallpaperInfo info) {
+  base::Value wallpaper_info_dict(base::Value::Type::DICTIONARY);
   if (info.asset_id.has_value()) {
-    wallpaper_info_dict->SetStringKey(
+    wallpaper_info_dict.SetStringKey(
         WallpaperControllerImpl::kNewWallpaperAssetIdNodeName,
         base::NumberToString(info.asset_id.value()));
   }
   if (info.unit_id.has_value()) {
-    wallpaper_info_dict->SetStringKey(
+    wallpaper_info_dict.SetStringKey(
         WallpaperControllerImpl::kNewWallpaperUnitIdNodeName,
         base::NumberToString(info.unit_id.value()));
   }
@@ -281,26 +280,26 @@
     online_wallpaper_variant_dict.SetStringKey(
         WallpaperControllerImpl::kOnlineWallpaperUrlNodeName,
         variant.raw_url.spec());
-    online_wallpaper_variant_dict.SetIntPath(
+    online_wallpaper_variant_dict.SetIntKey(
         WallpaperControllerImpl::kOnlineWallpaperTypeNodeName,
         static_cast<int>(variant.type));
     online_wallpaper_variant_list.Append(
         std::move(online_wallpaper_variant_dict));
   }
-  wallpaper_info_dict->SetKey(
+  wallpaper_info_dict.SetKey(
       WallpaperControllerImpl::kNewWallpaperVariantListNodeName,
       std::move(online_wallpaper_variant_list));
-  wallpaper_info_dict->SetStringKey(
+  wallpaper_info_dict.SetStringKey(
       WallpaperControllerImpl::kNewWallpaperCollectionIdNodeName,
       info.collection_id);
-  wallpaper_info_dict->SetStringKey(
+  wallpaper_info_dict.SetStringKey(
       WallpaperControllerImpl::kNewWallpaperDateNodeName,
       base::NumberToString(info.date.ToInternalValue()));
-  wallpaper_info_dict->SetStringKey(
+  wallpaper_info_dict.SetStringKey(
       WallpaperControllerImpl::kNewWallpaperLocationNodeName, info.location);
-  wallpaper_info_dict->SetIntKey(
+  wallpaper_info_dict.SetIntKey(
       WallpaperControllerImpl::kNewWallpaperLayoutNodeName, info.layout);
-  wallpaper_info_dict->SetIntKey(
+  wallpaper_info_dict.SetIntKey(
       WallpaperControllerImpl::kNewWallpaperTypeNodeName,
       static_cast<int>(info.type));
   return wallpaper_info_dict;
@@ -319,11 +318,10 @@
                              WallpaperInfo info,
                              PrefService* pref_service,
                              const std::string& pref_name) {
-  DictionaryPrefUpdateDeprecated wallpaper_update(pref_service, pref_name);
-  auto wallpaper_info_dict = CreateWallpaperInfoDict(info);
-  wallpaper_update->SetKey(
-      account_id.GetUserEmail(),
-      base::Value::FromUniquePtrValue(std::move(wallpaper_info_dict)));
+  DictionaryPrefUpdate wallpaper_update(pref_service, pref_name);
+  base::Value wallpaper_info_dict = CreateWallpaperInfoDict(info);
+  wallpaper_update->SetKey(account_id.GetUserEmail(),
+                           std::move(wallpaper_info_dict));
 }
 
 void AssertWallpaperInfoInPrefs(const PrefService* pref_service,
@@ -333,8 +331,8 @@
   const base::Value* stored_info_dict =
       pref_service->GetDictionary(pref_name)->FindDictKey(
           account_id.GetUserEmail());
-  auto expected_info_dict = CreateWallpaperInfoDict(info);
-  EXPECT_EQ(*expected_info_dict.get(), *stored_info_dict);
+  base::Value expected_info_dict = CreateWallpaperInfoDict(info);
+  EXPECT_EQ(expected_info_dict, *stored_info_dict);
 }
 
 WallpaperInfo InfoWithType(WallpaperType type) {
@@ -3147,14 +3145,13 @@
                                     public testing::WithParamInterface<bool> {
  public:
   WallpaperControllerPrefTest() {
-    base::DictionaryValue property;
+    base::Value property(base::Value::Type::DICTIONARY);
     property.SetIntKey("rotation",
                        static_cast<int>(display::Display::ROTATE_90));
     property.SetIntKey("width", 800);
     property.SetIntKey("height", 600);
 
-    DictionaryPrefUpdateDeprecated update(local_state(),
-                                          prefs::kDisplayProperties);
+    DictionaryPrefUpdate update(local_state(), prefs::kDisplayProperties);
     update.Get()->SetKey("2200000000", std::move(property));
   }
 
diff --git a/ash/webui/firmware_update_ui/resources/firmware_update_dialog.html b/ash/webui/firmware_update_ui/resources/firmware_update_dialog.html
index bc436b0..4e0cf55 100644
--- a/ash/webui/firmware_update_ui/resources/firmware_update_dialog.html
+++ b/ash/webui/firmware_update_ui/resources/firmware_update_dialog.html
@@ -32,16 +32,16 @@
   <cr-dialog id="updateDialog" show-on-attach
       on-close="closeDialog_">
     <div slot="title" id="updateDialogTitle" class="firmware-dialog-title-font">
-      [[computeUpdateDialogTitle_(installationProgress.state)]]
+      [[dialogContent.title]]
     </div>
     <div slot="body" class="firmware-dialog-body-font">
       <div>
-        [[computeUpdateDialogBodyText_(installationProgress.state)]]
+        [[dialogContent.body]]
       </div>
     </div>
     <div slot="footer" hidden$="[[!isUpdateInProgress_(installationProgress.state)]]">
       <label id="progress" class="firmware-dialog-installing-font">
-        [[computeProgressText_(installationProgress.percentage)]]
+        [[dialogContent.footer]]
       </label>
       <paper-progress id="updateProgressBar"
           value="[[computePercentageValue_(installationProgress.percentage)]]"
diff --git a/ash/webui/firmware_update_ui/resources/firmware_update_dialog.js b/ash/webui/firmware_update_ui/resources/firmware_update_dialog.js
index eea4cd9..907dea9d 100644
--- a/ash/webui/firmware_update_ui/resources/firmware_update_dialog.js
+++ b/ash/webui/firmware_update_ui/resources/firmware_update_dialog.js
@@ -15,10 +15,17 @@
 import 'chrome://resources/polymer/v3_0/paper-progress/paper-progress.js';
 import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/js/i18n_behavior.m.js';
 import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {FirmwareUpdate, InstallationProgress, InstallControllerRemote, UpdateProgressObserverInterface, UpdateProgressObserverReceiver, UpdateProviderInterface, UpdateState} from './firmware_update_types.js';
+import {DialogContent, FirmwareUpdate, InstallationProgress, InstallControllerRemote, UpdateProgressObserverInterface, UpdateProgressObserverReceiver, UpdateProviderInterface, UpdateState} from './firmware_update_types.js';
 import {getUpdateProvider} from './mojo_interface_provider.js';
 import {mojoString16ToString} from './mojo_utils.js';
 
+/** @type {!DialogContent} */
+const initialDialogContent = {
+  title: '',
+  body: '',
+  footer: ''
+};
+
 /**
  * @fileoverview
  * 'firmware-update-dialog' displays information related to a firmware update.
@@ -54,6 +61,13 @@
       installationProgress: {
         type: Object,
       },
+
+      /** @type {!DialogContent} */
+      dialogContent: {
+        type: Object,
+        value: initialDialogContent,
+        computed: 'computeDialogContent_(installationProgress.*)',
+      }
     };
   }
 
@@ -171,33 +185,48 @@
 
   /**
    * @protected
-   * @return {string}
+   * @return {boolean}
    */
-  computeUpdateDialogTitle_() {
-    return this.isUpdateInProgress_() ?
-        this.i18n('updating', mojoString16ToString(this.update.deviceName)) :
-        this.i18n(
-            'deviceUpToDate', mojoString16ToString(this.update.deviceName));
+  isUpdateDone_() {
+    // TODO(michaelcheco): Handle failed state.
+    return this.installationProgress.state === UpdateState.kSuccess;
   }
 
   /**
-   * @protected
-   * @return {string}
+   * @param {!UpdateState} state
+   * @return {!DialogContent}
    */
-  computeProgressText_() {
-    return this.i18n('installing', this.installationProgress.percentage);
-  }
-
-  /**
-   * @protected
-   * @return {string}
-   */
-  computeUpdateDialogBodyText_() {
+  createDialogContentObj_(state) {
     const {deviceName, deviceVersion} = this.update;
-    return this.installationProgress.state === UpdateState.kSuccess ?
-        this.i18n(
-            'hasBeenUpdated', mojoString16ToString(deviceName), deviceVersion) :
-        this.i18n('updatingInfo');
+    const {percentage} = this.installationProgress;
+
+    const dialogContent = {
+      [UpdateState.kUpdating]: {
+        title: this.i18n('updating', mojoString16ToString(deviceName)),
+        body: this.i18n('updatingInfo'),
+        footer: this.i18n('installing', percentage),
+      },
+      [UpdateState.kSuccess]: {
+        title: this.i18n('deviceUpToDate', mojoString16ToString(deviceName)),
+        body: this.i18n(
+            'hasBeenUpdated', mojoString16ToString(deviceName), deviceVersion),
+        footer: '',
+      },
+    };
+
+    return dialogContent[state];
+  }
+
+  /** @return {!DialogContent} */
+  computeDialogContent_() {
+    if (this.isUpdateInProgress_()) {
+      return this.createDialogContentObj_(UpdateState.kUpdating);
+    }
+
+    if (this.isUpdateDone_()) {
+      return this.createDialogContentObj_(UpdateState.kSuccess);
+    }
+    return initialDialogContent;
   }
 }
 
diff --git a/ash/webui/firmware_update_ui/resources/firmware_update_types.js b/ash/webui/firmware_update_ui/resources/firmware_update_types.js
index 3c8f381..e46f0985 100644
--- a/ash/webui/firmware_update_ui/resources/firmware_update_types.js
+++ b/ash/webui/firmware_update_ui/resources/firmware_update_types.js
@@ -148,3 +148,12 @@
  */
 export const InstallationProgress =
     ash.firmwareUpdate.mojom.InstallationProgress;
+
+/**
+ * @typedef {{
+ *   title: string,
+ *   body: string,
+ *   footer: string,
+ * }}
+ */
+export let DialogContent;
diff --git a/ash/webui/personalization_app/resources/common/icons.html b/ash/webui/personalization_app/resources/common/icons.html
index b587ba4..fae4f1f 100644
--- a/ash/webui/personalization_app/resources/common/icons.html
+++ b/ash/webui/personalization_app/resources/common/icons.html
@@ -79,6 +79,9 @@
        <g id="confirm_selection">
          <path d="M7.49999 13.475L4.02499 9.99999L2.84166 11.175L7.49999 15.8333L17.5 5.83333L16.325 4.65833L7.49999 13.475Z"/>
        </g>
+       <g id="pencil">
+         <path d="M.945 15.197v3.75h3.75l11.06-11.06-3.75-3.75zm17.71-10.21a.996.996 0 0 0 0-1.41l-2.34-2.34a.996.996 0 0 0-1.41 0l-1.83 1.83 3.75 3.75z"/>
+        </g>
      </defs>
    </svg>
  </iron-iconset-svg>
diff --git a/ash/webui/personalization_app/resources/trusted/personalization_main_element.html b/ash/webui/personalization_app/resources/trusted/personalization_main_element.html
index 28534181..cd8ea13 100644
--- a/ash/webui/personalization_app/resources/trusted/personalization_main_element.html
+++ b/ash/webui/personalization_app/resources/trusted/personalization_main_element.html
@@ -1,7 +1,10 @@
 <style></style>
 <div id="container">
   <h1>Personalization</h1>
-  <user-preview></user-preview>
+  <user-preview>
+    <cr-icon-button id="userSubpageLink" iron-icon="personalization:pencil"
+        on-click="onClickUserSubpageLink_"></cr-icon-button>
+  </user-preview>
   <wallpaper-preview></wallpaper-preview>
   <template is="dom-if" if="[[isDarkLightModeEnabled_()]]">
     <personalization-theme></personalization-theme>
diff --git a/ash/webui/personalization_app/resources/trusted/personalization_main_element.ts b/ash/webui/personalization_app/resources/trusted/personalization_main_element.ts
index a11c8ce..85d8efc 100644
--- a/ash/webui/personalization_app/resources/trusted/personalization_main_element.ts
+++ b/ash/webui/personalization_app/resources/trusted/personalization_main_element.ts
@@ -9,6 +9,7 @@
 
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {html} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {Paths, PersonalizationRouter} from './personalization_router_element.js';
 import {WithPersonalizationStore} from './personalization_store.js';
 
 export class PersonalizationMain extends WithPersonalizationStore {
@@ -27,6 +28,10 @@
   private isDarkLightModeEnabled_(): boolean {
     return loadTimeData.getBoolean('isDarkLightModeEnabled');
   }
+
+  private onClickUserSubpageLink_() {
+    PersonalizationRouter.instance().goToRoute(Paths.User);
+  }
 }
 
 customElements.define(PersonalizationMain.is, PersonalizationMain);
diff --git a/ash/webui/personalization_app/resources/trusted/personalization_router_element.ts b/ash/webui/personalization_app/resources/trusted/personalization_router_element.ts
index a6c9110e..52e9a9c 100644
--- a/ash/webui/personalization_app/resources/trusted/personalization_router_element.ts
+++ b/ash/webui/personalization_app/resources/trusted/personalization_router_element.ts
@@ -16,12 +16,16 @@
 
 export enum Paths {
   Ambient = '/ambient',
-  User = '/user',
   CollectionImages = '/wallpaper/collection',
   Collections = '/wallpaper',
   GooglePhotosCollection = '/wallpaper/google-photos',
   LocalCollection = '/wallpaper/local',
   Root = '/',
+  User = '/user',
+}
+
+function isPersonalizationHubEnabled(): boolean {
+  return loadTimeData.getBoolean('isPersonalizationHubEnabled');
 }
 
 export class PersonalizationRouter extends PolymerElement {
@@ -87,32 +91,19 @@
    */
   selectCollection(collection: WallpaperCollection) {
     document.title = collection.name;
-    this.setProperties(
-        {path_: Paths.CollectionImages, queryParams_: {id: collection.id}});
+    this.goToRoute(Paths.CollectionImages, {id: collection.id});
   }
 
   /**
    * Navigate to a specific album in the Google Photos collection page.
    */
   selectGooglePhotosAlbum(album: WallpaperCollection) {
-    this.setProperties({
-      path_: Paths.GooglePhotosCollection,
-      queryParams_: {googlePhotosAlbumId: album.id}
-    });
+    this.goToRoute(
+        Paths.GooglePhotosCollection, {googlePhotosAlbumId: album.id});
   }
 
-  /**
-   * Navigate to the Google Photos collection page.
-   */
-  selectGooglePhotosCollection() {
-    this.setProperties({path_: Paths.GooglePhotosCollection, query_: ''});
-  }
-
-  /**
-   * Navigate to the local collection page.
-   */
-  selectLocalCollection() {
-    this.setProperties({path_: Paths.LocalCollection, query_: ''});
+  goToRoute(path: Paths, queryParams: Object = {}) {
+    this.setProperties({path_: path, queryParams_: queryParams});
   }
 
   private shouldShowCollections_(path: string): boolean {
@@ -139,8 +130,7 @@
   }
 
   private shouldShowRootPage_(path: string|null): boolean {
-    return loadTimeData.getBoolean('isPersonalizationHubEnabled') &&
-        path === Paths.Root;
+    return isPersonalizationHubEnabled() && path === Paths.Root;
   }
 
   private shouldShowAmbientSubpage_(path: string|null): boolean {
diff --git a/ash/webui/personalization_app/resources/trusted/user/user_subpage_element.html b/ash/webui/personalization_app/resources/trusted/user/user_subpage_element.html
index 1c70bf0..735b1b166 100644
--- a/ash/webui/personalization_app/resources/trusted/user/user_subpage_element.html
+++ b/ash/webui/personalization_app/resources/trusted/user/user_subpage_element.html
@@ -1,4 +1,5 @@
 <style></style>
 <div id="container">
   <h2>User</h2>
+  <user-preview></user-preview>
 </div>
diff --git a/ash/webui/personalization_app/resources/trusted/user/user_subpage_element.ts b/ash/webui/personalization_app/resources/trusted/user/user_subpage_element.ts
index c320c2b..9d62afb 100644
--- a/ash/webui/personalization_app/resources/trusted/user/user_subpage_element.ts
+++ b/ash/webui/personalization_app/resources/trusted/user/user_subpage_element.ts
@@ -1,16 +1,15 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 /**
- * @fileoverview The avatar-main component displays the main content of
- * the user info.
+ * @fileoverview The user-subpage component displays information about the
+ * current user and allows changing device avatar image.
  */
 
-import {html} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {WithPersonalizationStore} from '../personalization_store.js';
+import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-export class UserSubpage extends WithPersonalizationStore {
+export class UserSubpage extends PolymerElement {
   static get is() {
     return 'user-subpage';
   }
diff --git a/ash/webui/personalization_app/resources/trusted/user_preview_element.html b/ash/webui/personalization_app/resources/trusted/user_preview_element.html
index d110b7f..d1516b4 100644
--- a/ash/webui/personalization_app/resources/trusted/user_preview_element.html
+++ b/ash/webui/personalization_app/resources/trusted/user_preview_element.html
@@ -1,8 +1,21 @@
-<style></style>
+<style>
+  #imageContainer {
+    position: relative;
+  }
+
+  ::slotted(cr-icon-button) {
+    bottom: 0;
+    position: absolute;
+    right: 0;
+  }
+</style>
 <div id="container">
   <template is="dom-if" if="[[info_]]">
     <p id="name">[[info_.name]]</p>
     <p id="email">[[info_.email]]</p>
-    <img id="avatar" src="[[info_.avatar.url]]">
+    <div id="imageContainer">
+      <img id="avatar" src="[[info_.avatar.url]]">
+      <slot></slot>
+    </div>
   </template>
 </div>
diff --git a/ash/webui/personalization_app/resources/trusted/wallpaper/untrusted_message_handler.ts b/ash/webui/personalization_app/resources/trusted/wallpaper/untrusted_message_handler.ts
index 57301a4..95b97e6 100644
--- a/ash/webui/personalization_app/resources/trusted/wallpaper/untrusted_message_handler.ts
+++ b/ash/webui/personalization_app/resources/trusted/wallpaper/untrusted_message_handler.ts
@@ -6,7 +6,7 @@
 
 import {Events, EventType, untrustedOrigin} from '../../common/constants.js';
 import {IFrameApi} from '../iframe_api.js';
-import {PersonalizationRouter} from '../personalization_router_element.js';
+import {Paths, PersonalizationRouter} from '../personalization_router_element.js';
 import {PersonalizationStore} from '../personalization_store.js';
 
 import {selectWallpaper} from './wallpaper_controller.js';
@@ -32,10 +32,10 @@
       PersonalizationRouter.instance().selectCollection(selectedCollection);
       break;
     case EventType.SELECT_GOOGLE_PHOTOS_COLLECTION:
-      PersonalizationRouter.instance().selectGooglePhotosCollection();
+      PersonalizationRouter.instance().goToRoute(Paths.GooglePhotosCollection);
       break;
     case EventType.SELECT_LOCAL_COLLECTION:
-      PersonalizationRouter.instance().selectLocalCollection();
+      PersonalizationRouter.instance().goToRoute(Paths.LocalCollection);
       break;
     case EventType.SELECT_IMAGE:
       const collectionId = PersonalizationRouter.instance().collectionId;
diff --git a/ash/webui/shimless_rma/resources/onboarding_network_page.html b/ash/webui/shimless_rma/resources/onboarding_network_page.html
index 57885a1..e955619 100644
--- a/ash/webui/shimless_rma/resources/onboarding_network_page.html
+++ b/ash/webui/shimless_rma/resources/onboarding_network_page.html
@@ -43,7 +43,8 @@
   </div>
   <div slot="body" id="container">
     <network-list id="networkList" show-technology-badge
-        networks="[[networks_]]" on-selected="onNetworkSelected_">
+        networks="[[networks_]]" on-selected="onNetworkSelected_"
+        disabled="[[allButtonsDisabled]]">
     </network-list>
   </div>
 </base-page>
diff --git a/ash/webui/shimless_rma/resources/onboarding_network_page.js b/ash/webui/shimless_rma/resources/onboarding_network_page.js
index 5588403..2744335 100644
--- a/ash/webui/shimless_rma/resources/onboarding_network_page.js
+++ b/ash/webui/shimless_rma/resources/onboarding_network_page.js
@@ -52,6 +52,12 @@
   static get properties() {
     return {
       /**
+       * Set by shimless_rma.js.
+       * @type {boolean}
+       */
+      allButtonsDisabled: Boolean,
+
+      /**
        * Array of available networks
        * @protected
        * @type {!Array<chromeos.networkConfig.mojom.NetworkStateProperties>}
diff --git a/ash/webui/shimless_rma/resources/wrapup_finalize_page.html b/ash/webui/shimless_rma/resources/wrapup_finalize_page.html
index be90e75d..c0c1b3a9 100644
--- a/ash/webui/shimless_rma/resources/wrapup_finalize_page.html
+++ b/ash/webui/shimless_rma/resources/wrapup_finalize_page.html
@@ -8,7 +8,8 @@
     <div>
       <cr-button id="retryFinalizationButton" class="cancel-button"
           on-click="onRetryFinalizationButtonClicked_"
-          hidden$="[[!shouldShowRetryButton_]]">
+          hidden$="[[!shouldShowRetryButton_]]"
+          disabled="[[allButtonsDisabled]]">
         [[i18n('finalizePageFailedRetryButtonLabel')]]
       </cr-button>
     </div>
diff --git a/ash/webui/shimless_rma/resources/wrapup_finalize_page.js b/ash/webui/shimless_rma/resources/wrapup_finalize_page.js
index a17ddd8f..15d478f4 100644
--- a/ash/webui/shimless_rma/resources/wrapup_finalize_page.js
+++ b/ash/webui/shimless_rma/resources/wrapup_finalize_page.js
@@ -45,6 +45,12 @@
 
   static get properties() {
     return {
+      /**
+       * Set by shimless_rma.js.
+       * @type {boolean}
+       */
+      allButtonsDisabled: Boolean,
+
       /** @protected */
       finalizationMessage_: {
         type: String,
diff --git a/ash/wm/desks/desks_restore_util.cc b/ash/wm/desks/desks_restore_util.cc
index e4142ef..ce6ad4e 100644
--- a/ash/wm/desks/desks_restore_util.cc
+++ b/ash/wm/desks/desks_restore_util.cc
@@ -260,9 +260,8 @@
     return;
   }
 
-  ListPrefUpdateDeprecated name_update(primary_user_prefs,
-                                       prefs::kDesksNamesList);
-  base::ListValue* name_pref_data = name_update.Get();
+  ListPrefUpdate name_update(primary_user_prefs, prefs::kDesksNamesList);
+  base::Value* name_pref_data = name_update.Get();
   name_pref_data->ClearList();
 
   const auto& desks = DesksController::Get()->desks();
@@ -294,15 +293,14 @@
   }
 
   // Save per-desk metrics.
-  ListPrefUpdateDeprecated metrics_update(primary_user_prefs,
-                                          prefs::kDesksMetricsList);
-  base::ListValue* metrics_pref_data = metrics_update.Get();
+  ListPrefUpdate metrics_update(primary_user_prefs, prefs::kDesksMetricsList);
+  base::Value* metrics_pref_data = metrics_update.Get();
   metrics_pref_data->ClearList();
 
   auto* desks_controller = DesksController::Get();
   const auto& desks = desks_controller->desks();
   for (const auto& desk : desks) {
-    base::DictionaryValue metrics_dict;
+    base::Value metrics_dict(base::Value::Type::DICTIONARY);
     metrics_dict.SetIntKey(
         kCreationTimeKey,
         desk->creation_time().ToDeltaSinceWindowsEpoch().InMinutes());
@@ -316,7 +314,7 @@
   DCHECK_EQ(metrics_pref_data->GetList().size(), desks.size());
 
   // Save weekly active report time.
-  DictionaryPrefUpdateDeprecated weekly_active_desks_update(
+  DictionaryPrefUpdate weekly_active_desks_update(
       primary_user_prefs, prefs::kDesksWeeklyActiveDesksMetrics);
   weekly_active_desks_update->SetIntPath(
       kReportTimeKey, desks_controller->GetWeeklyActiveReportTime()
diff --git a/ash/wm/desks/desks_unittests.cc b/ash/wm/desks/desks_unittests.cc
index 327db5d..f85ea9fd 100644
--- a/ash/wm/desks/desks_unittests.cc
+++ b/ash/wm/desks/desks_unittests.cc
@@ -3255,8 +3255,8 @@
   void InitPrefsWithDesksRestoreData(PrefService* prefs,
                                      std::vector<std::string> desk_names) {
     DCHECK(prefs);
-    ListPrefUpdateDeprecated update(prefs, prefs::kDesksNamesList);
-    base::ListValue* pref_data = update.Get();
+    ListPrefUpdate update(prefs, prefs::kDesksNamesList);
+    base::Value* pref_data = update.Get();
     ASSERT_TRUE(pref_data->GetList().empty());
     for (auto desk_name : desk_names)
       pref_data->Append(desk_name);
diff --git a/base/BUILD.gn b/base/BUILD.gn
index ef7f44e..f7d54628 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -3095,6 +3095,7 @@
     "i18n/string_search_unittest.cc",
     "i18n/time_formatting_unittest.cc",
     "i18n/timezone_unittest.cc",
+    "i18n/transliterator_unittest.cc",
     "immediate_crash_unittest.cc",
     "json/json_parser_unittest.cc",
     "json/json_reader_unittest.cc",
diff --git a/base/android/java/src/org/chromium/base/BundleUtils.java b/base/android/java/src/org/chromium/base/BundleUtils.java
index 2d4fe3f..28082e0 100644
--- a/base/android/java/src/org/chromium/base/BundleUtils.java
+++ b/base/android/java/src/org/chromium/base/BundleUtils.java
@@ -11,20 +11,27 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.os.Build;
+import android.os.Bundle;
+import android.view.LayoutInflater;
 
 import androidx.annotation.Nullable;
+import androidx.collection.ArrayMap;
 import androidx.collection.SimpleArrayMap;
 
 import dalvik.system.BaseDexClassLoader;
 import dalvik.system.PathClassLoader;
 
 import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.IdentifierNameString;
 import org.chromium.base.compat.ApiHelperForO;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.build.BuildConfig;
 
 import java.lang.reflect.Field;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
 
 /**
  * Utils for working with android app bundles.
@@ -43,8 +50,9 @@
  * we can dynamically set whether or not we're in a bundle for targets that use static shared
  * library APKs.
  */
-public final class BundleUtils {
+public class BundleUtils {
     private static final String TAG = "BundleUtils";
+    private static final String LOADED_SPLITS_KEY = "split_compat_loaded_splits";
     private static Boolean sIsBundle;
     private static final Object sSplitLock = new Object();
 
@@ -53,6 +61,14 @@
     private static final SimpleArrayMap<String, ClassLoader> sCachedClassLoaders =
             new SimpleArrayMap<>();
 
+    private static final Map<String, ClassLoader> sInflationClassLoaders =
+            Collections.synchronizedMap(new ArrayMap<>());
+    private static SplitCompatClassLoader sSplitCompatClassLoaderInstance;
+
+    // List of splits that were loaded during the last run of chrome when
+    // restoring from recents.
+    private static ArrayList<String> sSplitsToRestore;
+
     /**
      * {@link BundleUtils#isBundle()}  is not called directly by native because
      * {@link CalledByNative} prevents inlining, causing the bundle support lib to not be
@@ -230,6 +246,169 @@
         return getNativeLibraryPath(libraryName, "");
     }
 
+    public static void checkContextClassLoader(Context baseContext, Activity activity) {
+        ClassLoader activityClassLoader = activity.getClass().getClassLoader();
+        ClassLoader contextClassLoader = baseContext.getClassLoader();
+        if (activityClassLoader != contextClassLoader) {
+            Log.w(TAG, "Mismatched ClassLoaders between Activity and context (fixing): %s",
+                    activity.getClass());
+            replaceClassLoader(baseContext, activityClassLoader);
+        }
+    }
+
+    /**
+     * Gets the obfuscated name for the passed in class name. Important: this MUST be called with a
+     * string literal, otherwise @IdentifierNameString will not work.
+     */
+    @IdentifierNameString
+    public static String getIdentifierName(String className) {
+        return className;
+    }
+
+    /**
+     * Constructs a new instance of the given class name. If the application context class loader
+     * can load the class, that class loader will be used, otherwise the class loader from the
+     * passed in context will be used.
+     */
+    public static Object newInstance(Context context, String className) {
+        Context appContext = ContextUtils.getApplicationContext();
+        if (appContext != null && canLoadClass(appContext.getClassLoader(), className)) {
+            context = appContext;
+        }
+        try {
+            return context.getClassLoader().loadClass(className).newInstance();
+        } catch (ReflectiveOperationException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Creates a context which can access classes from the specified split, but inherits theme
+     * resources from the passed in context. This is useful if a context is needed to inflate
+     * layouts which reference classes from a split.
+     */
+    public static Context createContextForInflation(Context context, String splitName) {
+        if (!BundleUtils.isIsolatedSplitInstalled(context, splitName)) {
+            return context;
+        }
+        ClassLoader splitClassLoader = registerSplitClassLoaderForInflation(splitName);
+        return new ContextWrapper(context) {
+            @Override
+            public ClassLoader getClassLoader() {
+                return splitClassLoader;
+            }
+
+            @Override
+            public Object getSystemService(String name) {
+                Object ret = super.getSystemService(name);
+                if (Context.LAYOUT_INFLATER_SERVICE.equals(name)) {
+                    ret = ((LayoutInflater) ret).cloneInContext(this);
+                }
+                return ret;
+            }
+        };
+    }
+
+    public static ClassLoader registerSplitClassLoaderForInflation(String splitName) {
+        ClassLoader splitClassLoader = sInflationClassLoaders.get(splitName);
+        if (splitClassLoader == null) {
+            splitClassLoader = BundleUtils
+                                       .createIsolatedSplitContext(
+                                               ContextUtils.getApplicationContext(), splitName)
+                                       .getClassLoader();
+            sInflationClassLoaders.put(splitName, splitClassLoader);
+        }
+        return splitClassLoader;
+    }
+
+    public static boolean canLoadClass(ClassLoader classLoader, String className) {
+        try {
+            Class.forName(className, false, classLoader);
+            return true;
+        } catch (ClassNotFoundException e) {
+            return false;
+        }
+    }
+
+    public static ClassLoader getSplitCompatClassLoader() {
+        // SplitCompatClassLoader needs to be lazy loaded to ensure the Chrome
+        // context is loaded and its class loader is set as the parent
+        // classloader for the SplitCompatClassLoader. This happens in
+        // Application#attachBaseContext.
+        if (sSplitCompatClassLoaderInstance == null) {
+            sSplitCompatClassLoaderInstance = new SplitCompatClassLoader();
+        }
+        return sSplitCompatClassLoaderInstance;
+    }
+
+    public static void saveLoadedSplits(Bundle outState) {
+        outState.putStringArrayList(
+                LOADED_SPLITS_KEY, new ArrayList(sInflationClassLoaders.keySet()));
+    }
+
+    public static void restoreLoadedSplits(Bundle savedInstanceState) {
+        if (savedInstanceState == null) {
+            return;
+        }
+        sSplitsToRestore = savedInstanceState.getStringArrayList(LOADED_SPLITS_KEY);
+    }
+
+    private static class SplitCompatClassLoader extends ClassLoader {
+        public SplitCompatClassLoader() {
+            // The chrome split classloader if the chrome split exists, otherwise
+            // the base module class loader.
+            super(ContextUtils.getApplicationContext().getClassLoader());
+        }
+
+        private Class<?> checkSplitsClassLoaders(String className) throws ClassNotFoundException {
+            for (ClassLoader cl : sInflationClassLoaders.values()) {
+                try {
+                    return cl.loadClass(className);
+                } catch (ClassNotFoundException ignore) {
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Loads the class with the specified binary name.
+         */
+        @Override
+        public Class<?> findClass(String cn) throws ClassNotFoundException {
+            Class<?> foundClass = checkSplitsClassLoaders(cn);
+            if (foundClass != null) {
+                return foundClass;
+            }
+            // We will never have android.* classes in isolated split class loaders,
+            // but android framework inflater does sometimes try loading classes
+            // that do not exist when inflating xml files on startup.
+            if (!cn.startsWith("android.") && sSplitsToRestore != null) {
+                // If we fail from all the currently loaded classLoaders, lets
+                // try loading some splits that were loaded when chrome was last
+                // run and check again.
+                restoreSplitsClassLoaders();
+                foundClass = checkSplitsClassLoaders(cn);
+                if (foundClass != null) {
+                    return foundClass;
+                }
+            }
+            throw new ClassNotFoundException(cn);
+        }
+
+        private void restoreSplitsClassLoaders() {
+            if (sSplitsToRestore == null) {
+                return;
+            }
+            // Load splits that were stored in the SavedInstanceState Bundle.
+            for (String splitName : sSplitsToRestore) {
+                if (!sInflationClassLoaders.containsKey(splitName)) {
+                    registerSplitClassLoaderForInflation(splitName);
+                }
+            }
+            sSplitsToRestore = null;
+        }
+    }
+
     @Nullable
     private static String getSplitApkLibraryPath(String libraryName, String splitName) {
         // If isolated splits aren't supported, the library should have already been found.
@@ -265,14 +444,4 @@
         }
         return false;
     }
-
-    public static void checkContextClassLoader(Context baseContext, Activity activity) {
-        ClassLoader activityClassLoader = activity.getClass().getClassLoader();
-        ClassLoader contextClassLoader = baseContext.getClassLoader();
-        if (activityClassLoader != contextClassLoader) {
-            Log.w(TAG, "Mismatched ClassLoaders between Activity and context (fixing): %s",
-                    activity.getClass());
-            replaceClassLoader(baseContext, activityClassLoader);
-        }
-    }
 }
diff --git a/base/android/proguard/chromium_code.flags b/base/android/proguard/chromium_code.flags
index bcef6db..81d446c 100644
--- a/base/android/proguard/chromium_code.flags
+++ b/base/android/proguard/chromium_code.flags
@@ -99,7 +99,8 @@
     public static **[] values();
 }
 
+# TODO(b/214263216): Re-enable this once R8 is fixed.
 # Mark members annotated with IdentifierNameString as identifier name strings
--identifiernamestring class * {
-    @org.chromium.base.annotations.IdentifierNameString *;
-}
+# -identifiernamestring class * {
+#     @org.chromium.base.annotations.IdentifierNameString *;
+# }
diff --git a/base/i18n/transliterator_unittest.cc b/base/i18n/transliterator_unittest.cc
new file mode 100644
index 0000000..54916c6
--- /dev/null
+++ b/base/i18n/transliterator_unittest.cc
@@ -0,0 +1,51 @@
+// Copyright (c) 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "build/build_config.h"
+#include "base/i18n/unicodestring.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/icu/source/common/unicode/ustring.h"
+#include "third_party/icu/source/i18n/unicode/translit.h"
+
+namespace base {
+namespace i18n {
+
+TEST(TransliteratorTest, LowerCorrect) {
+  UParseError parseErr;
+  UErrorCode err = U_ZERO_ERROR;
+  std::unique_ptr<icu::Transliterator> transliterator(
+      icu::Transliterator::createInstance("Lower", UTRANS_FORWARD,
+                                          parseErr, err));
+  ASSERT_TRUE(U_SUCCESS(err));
+  icu::UnicodeString text(u"ÎÑÅ¢ÉRÑÅÅ¢ÎÖÑÅĻΎÅÅ¢ÎÖÑ");
+  transliterator->transliterate(text);
+  EXPECT_EQ(base::i18n::UnicodeStringToString16(text), u"îñÅ£érñåÅ£îöñåļîžåÅ£îöñ");
+}
+
+TEST(TransliteratorTest, LatinASCIICorrect) {
+  UParseError parseErr;
+  UErrorCode err = U_ZERO_ERROR;
+  std::unique_ptr<icu::Transliterator> transliterator(
+      icu::Transliterator::createInstance("Latin-ASCII", UTRANS_FORWARD,
+                                          parseErr, err));
+  ASSERT_TRUE(U_SUCCESS(err));
+  icu::UnicodeString text(u"ÎÑÅ¢ÉRÑÅÅ¢ÎÖÑÅĻΎÅÅ¢ÎÖÑ");
+  transliterator->transliterate(text);
+  EXPECT_EQ(base::i18n::UnicodeStringToString16(text), u"INTERNATIONALIZATION");
+}
+
+TEST(TransliteratorTest, LowerLatinASCIICorrect) {
+  UParseError parseErr;
+  UErrorCode err = U_ZERO_ERROR;
+  std::unique_ptr<icu::Transliterator> transliterator(
+      icu::Transliterator::createInstance("Lower;Latin-ASCII", UTRANS_FORWARD,
+                                          parseErr, err));
+  ASSERT_TRUE(U_SUCCESS(err));
+  icu::UnicodeString text(u"ÎÑÅ¢ÉRÑÅÅ¢ÎÖÑÅĻΎÅÅ¢ÎÖÑ");
+  transliterator->transliterate(text);
+  EXPECT_EQ(base::i18n::UnicodeStringToString16(text), u"internationalization");
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/process/launch_posix.cc b/base/process/launch_posix.cc
index 08f3004..6ed067c 100644
--- a/base/process/launch_posix.cc
+++ b/base/process/launch_posix.cc
@@ -738,9 +738,9 @@
 
 #if defined(OS_LINUX) || defined(OS_CHROMEOS)
   // Since we use clone() directly, it does not call any pthread_aftork()
-  // callbacks, we explicitly clear tid cache here (normally this call is
+  // callbacks, we explicitly invalidate tid cache here (normally this call is
   // done as pthread_aftork() callback).  See crbug.com/902514.
-  base::internal::ClearTidCache();
+  base::internal::InvalidateTidCache();
 #endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
 
   return 0;
diff --git a/base/threading/platform_thread_internal_posix.h b/base/threading/platform_thread_internal_posix.h
index 6b3711c..ea74613 100644
--- a/base/threading/platform_thread_internal_posix.h
+++ b/base/threading/platform_thread_internal_posix.h
@@ -48,10 +48,11 @@
 
 #if defined(OS_LINUX) || defined(OS_CHROMEOS)
 // Current thread id is cached in thread local storage for performance reasons.
-// In some rare cases it's important to clear that cache explicitly (e.g. after
-// going through clone() syscall which does not call pthread_atfork()
+// In some rare cases it's important to invalidate that cache explicitly (e.g.
+// after going through clone() syscall which does not call pthread_atfork()
 // handlers).
-BASE_EXPORT void ClearTidCache();
+// This can only be called when the process is single-threaded.
+BASE_EXPORT void InvalidateTidCache();
 #endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
 
 }  // namespace internal
diff --git a/base/threading/platform_thread_posix.cc b/base/threading/platform_thread_posix.cc
index dfdd94db..e8177f21 100644
--- a/base/threading/platform_thread_posix.cc
+++ b/base/threading/platform_thread_posix.cc
@@ -33,6 +33,7 @@
 
 #if defined(OS_LINUX) || defined(OS_CHROMEOS)
 #include <sys/syscall.h>
+#include <atomic>
 #endif
 
 #if defined(OS_FUCHSIA)
@@ -159,19 +160,32 @@
 #if defined(OS_LINUX) || defined(OS_CHROMEOS)
 
 // Store the thread ids in local storage since calling the SWI can be
-// expensive and PlatformThread::CurrentId is used liberally. Clear
-// the stored value after a fork() because forking changes the thread
-// id. Forking without going through fork() (e.g. clone()) is not
-// supported, but there is no known usage. Using thread_local is
-// fine here (despite being banned) since it is going to be allowed
-// but is blocked on a clang bug for Mac (https://crbug.com/829078)
-// and we can't use ThreadLocalStorage because of re-entrancy due to
-// CHECK/DCHECKs.
+// expensive and PlatformThread::CurrentId is used liberally.
 thread_local pid_t g_thread_id = -1;
 
+// A boolean value that indicates that the value stored in |g_thread_id| on the
+// main thread is invalid, because it hasn't been updated since the process
+// forked.
+//
+// This used to work by setting |g_thread_id| to -1 in a pthread_atfork handler.
+// However, when a multithreaded process forks, it is only allowed to call
+// async-signal-safe functions until it calls an exec() syscall. However,
+// accessing TLS may allocate (see crbug.com/1275748), which is not
+// async-signal-safe and therefore causes deadlocks, corruption, and crashes.
+//
+// It's Atomic to placate TSAN.
+std::atomic<bool> g_main_thread_tid_cache_valid = false;
+
+// Tracks whether the current thread is the main thread, and therefore whether
+// |g_main_thread_tid_cache_valid| is relevant for the current thread. This is
+// also updated by PlatformThread::CurrentId().
+thread_local bool g_is_main_thread = true;
+
 class InitAtFork {
  public:
-  InitAtFork() { pthread_atfork(nullptr, nullptr, internal::ClearTidCache); }
+  InitAtFork() {
+    pthread_atfork(nullptr, nullptr, internal::InvalidateTidCache);
+  }
 };
 
 #endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
@@ -182,8 +196,8 @@
 
 namespace internal {
 
-void ClearTidCache() {
-  g_thread_id = -1;
+void InvalidateTidCache() {
+  g_main_thread_tid_cache_valid.store(false, std::memory_order_relaxed);
 }
 
 }  // namespace internal
@@ -198,13 +212,28 @@
   return pthread_mach_thread_np(pthread_self());
 #elif defined(OS_LINUX) || defined(OS_CHROMEOS)
   static InitAtFork init_at_fork;
-  if (g_thread_id == -1) {
+  if (g_thread_id == -1 ||
+      (g_is_main_thread &&
+       !g_main_thread_tid_cache_valid.load(std::memory_order_relaxed))) {
+    // Update the cached tid.
     g_thread_id = syscall(__NR_gettid);
+    // If this is the main thread, we can mark the tid_cache as valid.
+    // Otherwise, stop the current thread from always entering this slow path.
+    if (g_thread_id == getpid()) {
+      g_main_thread_tid_cache_valid.store(true, std::memory_order_relaxed);
+    } else {
+      g_is_main_thread = false;
+    }
   } else {
-    DCHECK_EQ(g_thread_id, syscall(__NR_gettid))
-        << "Thread id stored in TLS is different from thread id returned by "
-           "the system. It is likely that the process was forked without going "
-           "through fork().";
+#if DCHECK_IS_ON()
+    if (g_thread_id != syscall(__NR_gettid)) {
+      RAW_LOG(
+          FATAL,
+          "Thread id stored in TLS is different from thread id returned by "
+          "the system. It is likely that the process was forked without going "
+          "through fork().");
+    }
+#endif
   }
   return g_thread_id;
 #elif defined(OS_ANDROID)
diff --git a/base/threading/platform_thread_unittest.cc b/base/threading/platform_thread_unittest.cc
index 7c9a1d30..c97de2d 100644
--- a/base/threading/platform_thread_unittest.cc
+++ b/base/threading/platform_thread_unittest.cc
@@ -30,6 +30,14 @@
 #include "base/time/time.h"
 #endif
 
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#include <pthread.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#endif
+
 namespace base {
 
 // Trivial tests that thread runs and doesn't crash on create, join, or detach -
@@ -569,6 +577,77 @@
 
 }  // namespace
 
-#endif
+#endif  // defined(OS_APPLE)
+
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+
+namespace {
+
+bool IsTidCacheCorrect() {
+  return PlatformThread::CurrentId() == syscall(__NR_gettid);
+}
+
+void* CheckTidCacheCorrectWrapper(void*) {
+  CHECK(IsTidCacheCorrect());
+  return nullptr;
+}
+
+void CreatePthreadToCheckCache() {
+  pthread_t thread_id;
+  pthread_create(&thread_id, nullptr, CheckTidCacheCorrectWrapper, nullptr);
+  pthread_join(thread_id, nullptr);
+}
+
+// This test must use raw pthreads and fork() to avoid calls from //base to
+// PlatformThread::CurrentId(), as the ordering of calls is important to the
+// test.
+void TestTidCacheCorrect(bool main_thread_accesses_cache_first) {
+  EXPECT_TRUE(IsTidCacheCorrect());
+
+  CreatePthreadToCheckCache();
+
+  // Now fork a process and make sure the TID cache gets correctly updated on
+  // both its main thread and a child thread.
+  pid_t child_pid = fork();
+  ASSERT_GE(child_pid, 0);
+
+  if (child_pid == 0) {
+    // In the child.
+    if (main_thread_accesses_cache_first) {
+      if (!IsTidCacheCorrect())
+        _exit(1);
+    }
+
+    // Access the TID cache on another thread and make sure the cached value is
+    // correct.
+    CreatePthreadToCheckCache();
+
+    if (!main_thread_accesses_cache_first) {
+      // Make sure the main thread's cache is correct even though another thread
+      // accessed the cache first.
+      if (!IsTidCacheCorrect())
+        _exit(1);
+    }
+
+    _exit(0);
+  }
+
+  int status;
+  ASSERT_EQ(waitpid(child_pid, &status, 0), child_pid);
+  ASSERT_TRUE(WIFEXITED(status));
+  ASSERT_EQ(WEXITSTATUS(status), 0);
+}
+
+TEST(PlatformThreadTidCacheTest, MainThreadFirst) {
+  TestTidCacheCorrect(true);
+}
+
+TEST(PlatformThreadTidCacheTest, MainThreadSecond) {
+  TestTidCacheCorrect(false);
+}
+
+}  // namespace
+
+#endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
 
 }  // namespace base
diff --git a/base/timer/timer.cc b/base/timer/timer.cc
index e5df43a..1b79037f 100644
--- a/base/timer/timer.cc
+++ b/base/timer/timer.cc
@@ -153,13 +153,24 @@
   if (g_is_always_abandon_scheduled_task_enabled)
     AbandonScheduledTask();
 
-  // It's safe to destroy or restart Timer on another sequence after Stop().
-  DETACH_FROM_SEQUENCE(sequence_checker_);
-
   OnStop();
   // No more member accesses here: |this| could be deleted after Stop() call.
 }
 
+void TimerBase::AbandonAndStop() {
+  // Note: Stop() is more or less re-implemented here because it cannot be
+  // called without rebinding the |sequence_checker_| to the current sequence
+  // after the call to AbandonScheduledTask().
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  is_running_ = false;
+
+  AbandonScheduledTask();
+
+  OnStop();
+  // No more member accesses here: |this| could be deleted at this point.
+}
+
 void TimerBase::Reset() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
@@ -229,6 +240,10 @@
     DCHECK(delayed_task_handle_.IsValid());
     delayed_task_handle_.CancelTask();
   }
+
+  // It's safe to destroy or restart Timer on another sequence after the task is
+  // abandoned.
+  DETACH_FROM_SEQUENCE(sequence_checker_);
 }
 
 void TimerBase::OnScheduledTaskInvoked(
diff --git a/base/timer/timer.h b/base/timer/timer.h
index e5e4f015..62df95d 100644
--- a/base/timer/timer.h
+++ b/base/timer/timer.h
@@ -130,13 +130,11 @@
   // is not running.
   virtual void Stop();
 
-  // Abandons the scheduled task (if any) and stops the timer (if running).
-  void AbandonAndStop() {
-    AbandonScheduledTask();
-
-    Stop();
-    // No more member accesses here: |this| could be deleted at this point.
-  }
+  // Abandons the scheduled task (if any) and stops the timer (if running). Use
+  // this instead of Stop() only if the timer will need to be used or destroyed
+  // on another sequence.
+  // TODO(1262205): Remove once kAlwaysAbandonScheduledTask is gone.
+  void AbandonAndStop();
 
   // Call this method to reset the timer delay. The user task must be set. If
   // the timer is not running, this will start it by posting a task.
diff --git a/build/config/arm.gni b/build/config/arm.gni
index 7a73832b..fa6522a0 100644
--- a/build/config/arm.gni
+++ b/build/config/arm.gni
@@ -128,7 +128,7 @@
     # - "pac": Enables Pointer Authentication Code (PAC, featured in Armv8.3)
     # - "standard": Enables both PAC and Branch Target Identification (Armv8.5).
     # - "none": No branch protection.
-    arm_control_flow_integrity = "pac"
+    arm_control_flow_integrity = "none"
   }
   assert(arm_control_flow_integrity == "none" ||
              arm_control_flow_integrity == "standard" ||
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index cfd6ca1c..1aca8e94 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-7.20220112.1.1
+7.20220112.3.1
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1
index 52114a9..1aca8e94 100644
--- a/build/fuchsia/linux_internal.sdk.sha1
+++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@
-7.20220112.2.1
+7.20220112.3.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index cfd6ca1c..1aca8e94 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-7.20220112.1.1
+7.20220112.3.1
diff --git a/build/lacros/mojo_connection_lacros_launcher.py b/build/lacros/mojo_connection_lacros_launcher.py
index 53fcc67..cb508a9 100755
--- a/build/lacros/mojo_connection_lacros_launcher.py
+++ b/build/lacros/mojo_connection_lacros_launcher.py
@@ -102,8 +102,11 @@
     legacy_mojo_fd = None
     startup_fd = os.fdopen(fds[0])
     mojo_fd = os.fdopen(fds[1])
+  elif version:
+    raise AssertionError('Unknown version: \\x%s' % version.hex())
   else:
-    raise AssertionError('Unknown version: \\x%s' % version.encode('hex'))
+    raise AssertionError('Failed to receive startup message from ash-chrome. '
+                         'Make sure you\'re logged in to Chrome OS.')
   return legacy_mojo_fd, startup_fd, mojo_fd
 
 
diff --git a/cc/paint/paint_filter.cc b/cc/paint/paint_filter.cc
index 8dd7b218..301e7e8 100644
--- a/cc/paint/paint_filter.cc
+++ b/cc/paint/paint_filter.cc
@@ -8,6 +8,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/memory/values_equivalent.h"
 #include "base/no_destructor.h"
 #include "base/stl_util.h"
 #include "build/build_config.h"
@@ -248,12 +249,6 @@
 }
 #endif
 
-bool AreFiltersEqual(const PaintFilter* one, const PaintFilter* two) {
-  if (!one || !two)
-    return !one && !two;
-  return *one == *two;
-}
-
 bool AreScalarsEqual(SkScalar one, SkScalar two) {
   return PaintOp::AreEqualEvenIfNaN(one, two);
 }
@@ -496,7 +491,7 @@
     const ColorFilterPaintFilter& other) const {
   return PaintOp::AreSkFlattenablesEqual(color_filter_.get(),
                                          other.color_filter_.get()) &&
-         AreFiltersEqual(input_.get(), other.input_.get());
+         base::ValuesEquivalent(input_.get(), other.input_.get());
 }
 
 BlurPaintFilter::BlurPaintFilter(SkScalar sigma_x,
@@ -534,7 +529,7 @@
   return PaintOp::AreEqualEvenIfNaN(sigma_x_, other.sigma_x_) &&
          PaintOp::AreEqualEvenIfNaN(sigma_y_, other.sigma_y_) &&
          tile_mode_ == other.tile_mode_ &&
-         AreFiltersEqual(input_.get(), other.input_.get());
+         base::ValuesEquivalent(input_.get(), other.input_.get());
 }
 
 DropShadowPaintFilter::DropShadowPaintFilter(SkScalar dx,
@@ -588,7 +583,7 @@
          PaintOp::AreEqualEvenIfNaN(sigma_x_, other.sigma_x_) &&
          PaintOp::AreEqualEvenIfNaN(sigma_y_, other.sigma_y_) &&
          color_ == other.color_ && shadow_mode_ == other.shadow_mode_ &&
-         AreFiltersEqual(input_.get(), other.input_.get());
+         base::ValuesEquivalent(input_.get(), other.input_.get());
 }
 
 MagnifierPaintFilter::MagnifierPaintFilter(const SkRect& src_rect,
@@ -621,7 +616,7 @@
 bool MagnifierPaintFilter::operator==(const MagnifierPaintFilter& other) const {
   return PaintOp::AreSkRectsEqual(src_rect_, other.src_rect_) &&
          PaintOp::AreEqualEvenIfNaN(inset_, other.inset_) &&
-         AreFiltersEqual(input_.get(), other.input_.get());
+         base::ValuesEquivalent(input_.get(), other.input_.get());
 }
 
 ComposePaintFilter::ComposePaintFilter(sk_sp<PaintFilter> outer,
@@ -651,8 +646,8 @@
 }
 
 bool ComposePaintFilter::operator==(const ComposePaintFilter& other) const {
-  return AreFiltersEqual(outer_.get(), other.outer_.get()) &&
-         AreFiltersEqual(inner_.get(), other.inner_.get());
+  return base::ValuesEquivalent(outer_.get(), other.outer_.get()) &&
+         base::ValuesEquivalent(inner_.get(), other.inner_.get());
 }
 
 AlphaThresholdPaintFilter::AlphaThresholdPaintFilter(const SkRegion& region,
@@ -692,7 +687,7 @@
   return region_ == other.region_ &&
          PaintOp::AreEqualEvenIfNaN(inner_min_, other.inner_min_) &&
          PaintOp::AreEqualEvenIfNaN(outer_max_, other.outer_max_) &&
-         AreFiltersEqual(input_.get(), other.input_.get());
+         base::ValuesEquivalent(input_.get(), other.input_.get());
 }
 
 XfermodePaintFilter::XfermodePaintFilter(SkBlendMode blend_mode,
@@ -730,8 +725,8 @@
 
 bool XfermodePaintFilter::operator==(const XfermodePaintFilter& other) const {
   return blend_mode_ == other.blend_mode_ &&
-         AreFiltersEqual(background_.get(), other.background_.get()) &&
-         AreFiltersEqual(foreground_.get(), other.foreground_.get());
+         base::ValuesEquivalent(background_.get(), other.background_.get()) &&
+         base::ValuesEquivalent(foreground_.get(), other.foreground_.get());
 }
 
 ArithmeticPaintFilter::ArithmeticPaintFilter(float k1,
@@ -784,8 +779,8 @@
          PaintOp::AreEqualEvenIfNaN(k3_, other.k3_) &&
          PaintOp::AreEqualEvenIfNaN(k4_, other.k4_) &&
          enforce_pm_color_ == other.enforce_pm_color_ &&
-         AreFiltersEqual(background_.get(), other.background_.get()) &&
-         AreFiltersEqual(foreground_.get(), other.foreground_.get());
+         base::ValuesEquivalent(background_.get(), other.background_.get()) &&
+         base::ValuesEquivalent(foreground_.get(), other.foreground_.get());
 }
 
 MatrixConvolutionPaintFilter::MatrixConvolutionPaintFilter(
@@ -845,7 +840,7 @@
          kernel_offset_ == other.kernel_offset_ &&
          tile_mode_ == other.tile_mode_ &&
          convolve_alpha_ == other.convolve_alpha_ &&
-         AreFiltersEqual(input_.get(), other.input_.get());
+         base::ValuesEquivalent(input_.get(), other.input_.get());
 }
 
 DisplacementMapEffectPaintFilter::DisplacementMapEffectPaintFilter(
@@ -891,8 +886,9 @@
     const DisplacementMapEffectPaintFilter& other) const {
   return channel_x_ == other.channel_x_ && channel_y_ == other.channel_y_ &&
          PaintOp::AreEqualEvenIfNaN(scale_, other.scale_) &&
-         AreFiltersEqual(displacement_.get(), other.displacement_.get()) &&
-         AreFiltersEqual(color_.get(), other.color_.get());
+         base::ValuesEquivalent(displacement_.get(),
+                                other.displacement_.get()) &&
+         base::ValuesEquivalent(color_.get(), other.color_.get());
 }
 
 ImagePaintFilter::ImagePaintFilter(PaintImage image,
@@ -1102,7 +1098,7 @@
   if (inputs_->size() != other.inputs_->size())
     return false;
   for (size_t i = 0; i < inputs_->size(); ++i) {
-    if (!AreFiltersEqual(inputs_[i].get(), other.inputs_[i].get()))
+    if (!base::ValuesEquivalent(inputs_[i].get(), other.inputs_[i].get()))
       return false;
   }
   return true;
@@ -1151,7 +1147,7 @@
     const MorphologyPaintFilter& other) const {
   return morph_type_ == other.morph_type_ && radius_x_ == other.radius_x_ &&
          radius_y_ == other.radius_y_ &&
-         AreFiltersEqual(input_.get(), other.input_.get());
+         base::ValuesEquivalent(input_.get(), other.input_.get());
 }
 
 OffsetPaintFilter::OffsetPaintFilter(SkScalar dx,
@@ -1184,7 +1180,7 @@
 bool OffsetPaintFilter::operator==(const OffsetPaintFilter& other) const {
   return PaintOp::AreEqualEvenIfNaN(dx_, other.dx_) &&
          PaintOp::AreEqualEvenIfNaN(dy_, other.dy_) &&
-         AreFiltersEqual(input_.get(), other.input_.get());
+         base::ValuesEquivalent(input_.get(), other.input_.get());
 }
 
 TilePaintFilter::TilePaintFilter(const SkRect& src,
@@ -1216,7 +1212,7 @@
 bool TilePaintFilter::operator==(const TilePaintFilter& other) const {
   return PaintOp::AreSkRectsEqual(src_, other.src_) &&
          PaintOp::AreSkRectsEqual(dst_, other.dst_) &&
-         AreFiltersEqual(input_.get(), other.input_.get());
+         base::ValuesEquivalent(input_.get(), other.input_.get());
 }
 
 TurbulencePaintFilter::TurbulencePaintFilter(TurbulenceType turbulence_type,
@@ -1372,7 +1368,7 @@
 bool MatrixPaintFilter::operator==(const MatrixPaintFilter& other) const {
   return PaintOp::AreSkMatricesEqual(matrix_, other.matrix_) &&
          filter_quality_ == other.filter_quality_ &&
-         AreFiltersEqual(input_.get(), other.input_.get());
+         base::ValuesEquivalent(input_.get(), other.input_.get());
 }
 
 LightingDistantPaintFilter::LightingDistantPaintFilter(
@@ -1432,7 +1428,7 @@
          PaintOp::AreEqualEvenIfNaN(surface_scale_, other.surface_scale_) &&
          PaintOp::AreEqualEvenIfNaN(kconstant_, other.kconstant_) &&
          PaintOp::AreEqualEvenIfNaN(shininess_, other.shininess_) &&
-         AreFiltersEqual(input_.get(), other.input_.get());
+         base::ValuesEquivalent(input_.get(), other.input_.get());
 }
 
 LightingPointPaintFilter::LightingPointPaintFilter(LightingType lighting_type,
@@ -1491,7 +1487,7 @@
          PaintOp::AreEqualEvenIfNaN(surface_scale_, other.surface_scale_) &&
          PaintOp::AreEqualEvenIfNaN(kconstant_, other.kconstant_) &&
          PaintOp::AreEqualEvenIfNaN(shininess_, other.shininess_) &&
-         AreFiltersEqual(input_.get(), other.input_.get());
+         base::ValuesEquivalent(input_.get(), other.input_.get());
 }
 
 LightingSpotPaintFilter::LightingSpotPaintFilter(LightingType lighting_type,
@@ -1563,7 +1559,7 @@
          PaintOp::AreEqualEvenIfNaN(surface_scale_, other.surface_scale_) &&
          PaintOp::AreEqualEvenIfNaN(kconstant_, other.kconstant_) &&
          PaintOp::AreEqualEvenIfNaN(shininess_, other.shininess_) &&
-         AreFiltersEqual(input_.get(), other.input_.get());
+         base::ValuesEquivalent(input_.get(), other.input_.get());
 }
 
 StretchPaintFilter::StretchPaintFilter(SkScalar stretch_x,
@@ -1637,7 +1633,7 @@
          PaintOp::AreEqualEvenIfNaN(stretch_y_, other.stretch_y_) &&
          PaintOp::AreEqualEvenIfNaN(width_, other.width_) &&
          PaintOp::AreEqualEvenIfNaN(height_, other.height_) &&
-         AreFiltersEqual(input_.get(), other.input_.get());
+         base::ValuesEquivalent(input_.get(), other.input_.get());
 }
 
 }  // namespace cc
diff --git a/chrome/VERSION b/chrome/VERSION
index 0071067e..b0d3e42 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=99
 MINOR=0
-BUILD=4827
+BUILD=4828
 PATCH=0
diff --git a/chrome/android/expectations/monochrome_public_bundle.proguard_flags.expected b/chrome/android/expectations/monochrome_public_bundle.proguard_flags.expected
index c64bb42..caeadef2 100644
--- a/chrome/android/expectations/monochrome_public_bundle.proguard_flags.expected
+++ b/chrome/android/expectations/monochrome_public_bundle.proguard_flags.expected
@@ -242,10 +242,11 @@
     public static **[] values();
 }
 
+# TODO(b/214263216): Re-enable this once R8 is fixed.
 # Mark members annotated with IdentifierNameString as identifier name strings
--identifiernamestring class * {
-    @org.chromium.base.annotations.IdentifierNameString *;
-}
+# -identifiernamestring class * {
+#     @org.chromium.base.annotations.IdentifierNameString *;
+# }
 
 # File: ../../build/android/dcheck_is_off.flags
 # Copyright 2019 The Chromium Authors. All rights reserved.
@@ -300,9 +301,10 @@
   *** build() return null;
 }
 
+# TODO(b/214263216): Allow obfuscation once R8 is fixed.
 # Keep implementation classes needed for split compat. These will be accessed by
 # reflection.
--keep,allowobfuscation public class ** extends org.chromium.chrome.browser.base.SplitCompat*$Impl {
+-keep public class ** extends org.chromium.chrome.browser.base.SplitCompat*$Impl {
   public <init>();
 }
 
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/LayoutUtils.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/LayoutUtils.java
index a7a210663..1f62b97 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/LayoutUtils.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/LayoutUtils.java
@@ -7,7 +7,7 @@
 import android.content.Context;
 import android.view.LayoutInflater;
 
-import org.chromium.chrome.browser.base.SplitCompatUtils;
+import org.chromium.base.BundleUtils;
 
 /** Utilities for dealing with layouts and inflation. */
 public class LayoutUtils {
@@ -19,6 +19,6 @@
      */
     public static LayoutInflater createInflater(Context context) {
         return LayoutInflater.from(
-                SplitCompatUtils.createContextForInflation(context, ASSISTANT_SPLIT_NAME));
+                BundleUtils.createContextForInflation(context, ASSISTANT_SPLIT_NAME));
     }
 }
diff --git a/chrome/android/java/src/PRESUBMIT.py b/chrome/android/java/src/PRESUBMIT.py
index e8016e19..cfe1fa9 100644
--- a/chrome/android/java/src/PRESUBMIT.py
+++ b/chrome/android/java/src/PRESUBMIT.py
@@ -31,7 +31,7 @@
     r'\bnew\sAlertDialog\.Builder\b')
 
 SPLIT_COMPAT_UTILS_IMPL_NAME_RE = re.compile(
-    r'\bSplitCompatUtils\.getIdentifierName\(\s*[^\s"]')
+    r'\bBundleUtils\.getIdentifierName\(\s*[^\s"]')
 
 COMMENT_RE = re.compile(r'^\s*(//|/\*|\*)')
 
@@ -54,7 +54,7 @@
   result.extend(_CheckNotificationConstructors(input_api, output_api))
   result.extend(_CheckAlertDialogBuilder(input_api, output_api))
   result.extend(_CheckCompatibleAlertDialogBuilder(input_api, output_api))
-  result.extend(_CheckSplitCompatUtilsIdentifierName(input_api, output_api))
+  result.extend(_CheckBundleUtilsIdentifierName(input_api, output_api))
   # Add more checks here
   return result
 
@@ -182,10 +182,10 @@
                                NEW_COMPATIBLE_ALERTDIALOG_BUILDER_RE)
 
 
-def _CheckSplitCompatUtilsIdentifierName(input_api, output_api):
+def _CheckBundleUtilsIdentifierName(input_api, output_api):
   error_msg = '''
-  SplitCompatUtils.getIdentifierName() not check failed:
-  SplitCompatUtils.getIdentifierName() must be called with a String literal,
+  BundleUtils.getIdentifierName() not check failed:
+  BundleUtils.getIdentifierName() must be called with a String literal,
   otherwise R8 may not correctly obfuscate the class name passed in.
   '''
   return _CheckReIgnoreComment(input_api, output_api, error_msg, [],
diff --git a/chrome/android/java/src/PRESUBMIT_test.py b/chrome/android/java/src/PRESUBMIT_test.py
index 6fb6681..9d53349 100755
--- a/chrome/android/java/src/PRESUBMIT_test.py
+++ b/chrome/android/java/src/PRESUBMIT_test.py
@@ -176,26 +176,26 @@
         mock_input, MockOutputApi())
     self.assertEqual(0, len(errors))
 
-class CheckSplitCompatUtilsIdentifierName(unittest.TestCase):
-  """Test the _CheckSplitCompatUtilsIdentifierName presubmit check."""
+class CheckBundleUtilsIdentifierName(unittest.TestCase):
+  """Test the _CheckBundleUtilsIdentifierName presubmit check."""
 
   def testFailure(self):
     """
-    SplitCompatUtils.getIdentifierName() without a String literal is flagged.
+    BundleUtils.getIdentifierName() without a String literal is flagged.
     """
     mock_input = MockInputApi()
     mock_input.files = [
         MockFile('path/One.java',
                  [
-                  'SplitCompatUtils.getIdentifierName(foo)',
+                  'BundleUtils.getIdentifierName(foo)',
                   'A new line to make sure there is no duplicate error.']),
         MockFile('path/Two.java',
-                 ['SplitCompatUtils.getIdentifierName(    foo)']),
+                 ['BundleUtils.getIdentifierName(    foo)']),
         MockFile('path/Three.java',
-                 ['SplitCompatUtils.getIdentifierName(',
+                 ['BundleUtils.getIdentifierName(',
                   '     bar)']),
     ]
-    errors = PRESUBMIT._CheckSplitCompatUtilsIdentifierName(
+    errors = PRESUBMIT._CheckBundleUtilsIdentifierName(
         mock_input, MockOutputApi())
     self.assertEqual(1, len(errors))
     self.assertEqual(3, len(errors[0].items))
@@ -205,24 +205,24 @@
 
   def testSuccess(self):
     """
-    Examples of when SplitCompatUtils.getIdentifierName() should not be flagged.
+    Examples of when BundleUtils.getIdentifierName() should not be flagged.
     """
     mock_input = MockInputApi()
     mock_input.files = [
         MockFile('path/One.java',
                  [
-                  'SplitCompatUtils.getIdentifierName("foo")',
+                  'BundleUtils.getIdentifierName("foo")',
                   'A new line.']),
         MockFile('path/Two.java',
-                 ['SplitCompatUtils.getIdentifierName(    "foo")']),
+                 ['BundleUtils.getIdentifierName(    "foo")']),
         MockFile('path/Three.java',
-                 ['SplitCompatUtils.getIdentifierName(',
+                 ['BundleUtils.getIdentifierName(',
                   '    "bar")']),
         MockFile('path/Four.java',
-                 ['  super(SplitCompatUtils.getIdentifierName(',
+                 ['  super(BundleUtils.getIdentifierName(',
                   '"bar"))']),
     ]
-    errors = PRESUBMIT._CheckSplitCompatUtilsIdentifierName(
+    errors = PRESUBMIT._CheckBundleUtilsIdentifierName(
         mock_input, MockOutputApi())
     self.assertEqual(0, len(errors))
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackgroundService.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackgroundService.java
index 86f47e1e..a4cb4dd6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackgroundService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackgroundService.java
@@ -4,13 +4,16 @@
 
 package org.chromium.chrome.browser;
 
+import org.chromium.base.annotations.IdentifierNameString;
 import org.chromium.chrome.browser.base.SplitCompatGcmTaskService;
-import org.chromium.chrome.browser.base.SplitCompatUtils;
 
 /** See {@link ChromeBackgroundServiceImpl}. */
 public class ChromeBackgroundService extends SplitCompatGcmTaskService {
+    @IdentifierNameString
+    private static final String IMPL_CLASS_NAME =
+            "org.chromium.chrome.browser.ChromeBackgroundServiceImpl";
+
     public ChromeBackgroundService() {
-        super(SplitCompatUtils.getIdentifierName(
-                "org.chromium.chrome.browser.ChromeBackgroundServiceImpl"));
+        super(IMPL_CLASS_NAME);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackupAgent.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackupAgent.java
index a49e4c79..475c158 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackupAgent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackupAgent.java
@@ -4,13 +4,16 @@
 
 package org.chromium.chrome.browser;
 
+import org.chromium.base.annotations.IdentifierNameString;
 import org.chromium.chrome.browser.base.SplitCompatBackupAgent;
-import org.chromium.chrome.browser.base.SplitCompatUtils;
 
 /** See {@link ChromeBackupAgentImpl}. */
 public class ChromeBackupAgent extends SplitCompatBackupAgent {
+    @IdentifierNameString
+    private static final String IMPL_CLASS_NAME =
+            "org.chromium.chrome.browser.ChromeBackupAgentImpl";
+
     public ChromeBackupAgent() {
-        super(SplitCompatUtils.getIdentifierName(
-                "org.chromium.chrome.browser.ChromeBackupAgentImpl"));
+        super(IMPL_CLASS_NAME);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBaseAppCompatActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBaseAppCompatActivity.java
index fec36a2..9fde92b2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBaseAppCompatActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBaseAppCompatActivity.java
@@ -4,7 +4,7 @@
 
 package org.chromium.chrome.browser;
 
-import static org.chromium.chrome.browser.base.SplitCompatUtils.CHROME_SPLIT_NAME;
+import static org.chromium.chrome.browser.base.SplitCompatApplication.CHROME_SPLIT_NAME;
 
 import android.app.ActivityManager.TaskDescription;
 import android.content.Context;
@@ -28,7 +28,6 @@
 import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.base.SplitChromeApplication;
-import org.chromium.chrome.browser.base.SplitCompatUtils;
 import org.chromium.chrome.browser.flags.CachedFeatureFlags;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.language.GlobalAppLocaleController;
@@ -87,7 +86,7 @@
 
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
-        SplitCompatUtils.restoreLoadedSplits(savedInstanceState);
+        BundleUtils.restoreLoadedSplits(savedInstanceState);
         mModalDialogManagerSupplier.set(createModalDialogManager());
 
         initializeNightModeStateProvider();
@@ -117,13 +116,13 @@
         // LayoutInflaters that use this ClassLoader can find view classes that
         // live inside splits. Very useful when FragmentManger tries to inflate
         // the UI automatically on restore.
-        return SplitCompatUtils.getSplitCompatClassLoader();
+        return BundleUtils.getSplitCompatClassLoader();
     }
 
     @Override
     protected void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
-        SplitCompatUtils.saveLoadedSplits(outState);
+        BundleUtils.saveLoadedSplits(outState);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java
index 813ad12e..c91cae7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java
@@ -4,8 +4,6 @@
 
 package org.chromium.chrome.browser.base;
 
-import static org.chromium.chrome.browser.base.SplitCompatUtils.CHROME_SPLIT_NAME;
-
 import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -17,6 +15,7 @@
 import org.chromium.base.BundleUtils;
 import org.chromium.base.JNIUtils;
 import org.chromium.base.TraceEvent;
+import org.chromium.base.annotations.IdentifierNameString;
 import org.chromium.base.metrics.RecordHistogram;
 
 /**
@@ -30,14 +29,17 @@
 public class SplitChromeApplication extends SplitCompatApplication {
     private static final String TAG = "SplitChromeApp";
 
+    @IdentifierNameString
+    private static final String IMPL_CLASS_NAME =
+            "org.chromium.chrome.browser.ChromeApplicationImpl";
+
     @SuppressLint("StaticFieldLeak")
     private static SplitPreloader sSplitPreloader;
 
     private String mChromeApplicationClassName;
 
     public SplitChromeApplication() {
-        this(SplitCompatUtils.getIdentifierName(
-                "org.chromium.chrome.browser.ChromeApplicationImpl"));
+        this(IMPL_CLASS_NAME);
     }
 
     public SplitChromeApplication(String chromeApplicationClassName) {
@@ -58,9 +60,8 @@
                 DexFixer.setHasIsolatedSplits(true);
             }
             setImplSupplier(() -> {
-                Context chromeContext = SplitCompatUtils.createChromeContext(this);
-                return (Impl) SplitCompatUtils.newInstance(
-                        chromeContext, mChromeApplicationClassName);
+                Context chromeContext = createChromeContext(this);
+                return (Impl) BundleUtils.newInstance(chromeContext, mChromeApplicationClassName);
             });
         } else {
             setImplSupplier(() -> createNonBrowserApplication());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatAppComponentFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatAppComponentFactory.java
index 196026a..cbb8995a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatAppComponentFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatAppComponentFactory.java
@@ -4,7 +4,7 @@
 
 package org.chromium.chrome.browser.base;
 
-import static org.chromium.chrome.browser.base.SplitCompatUtils.CHROME_SPLIT_NAME;
+import static org.chromium.chrome.browser.base.SplitCompatApplication.CHROME_SPLIT_NAME;
 
 import android.annotation.TargetApi;
 import android.app.Activity;
@@ -15,6 +15,7 @@
 import android.content.Intent;
 import android.os.Build;
 
+import org.chromium.base.BundleUtils;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 
@@ -64,9 +65,8 @@
 
         ClassLoader baseClassLoader = SplitCompatAppComponentFactory.class.getClassLoader();
         ClassLoader chromeClassLoader = appContext.getClassLoader();
-        if (!cl.equals(chromeClassLoader)
-                && !SplitCompatUtils.canLoadClass(baseClassLoader, className)
-                && SplitCompatUtils.canLoadClass(chromeClassLoader, className)) {
+        if (!cl.equals(chromeClassLoader) && !BundleUtils.canLoadClass(baseClassLoader, className)
+                && BundleUtils.canLoadClass(chromeClassLoader, className)) {
             Log.w(TAG, "Mismatched ClassLoaders between Application and component: %s", className);
             return chromeClassLoader;
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatApplication.java
index 63b2387..de615fc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatApplication.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatApplication.java
@@ -55,6 +55,7 @@
  * {@link SplitChromeApplication}.
  */
 public class SplitCompatApplication extends Application {
+    public static final String CHROME_SPLIT_NAME = "chrome";
     private static final String TAG = "SplitCompatApp";
     private static final String COMMAND_LINE_FILE = "chrome-command-line";
     private static final String ATTACH_BASE_CONTEXT_EVENT = "ChromeApplication.attachBaseContext";
@@ -208,8 +209,8 @@
             PureJavaExceptionHandler.installHandler(() -> {
                 // ChromePureJavaExceptionReporter may be in the chrome module, so load by
                 // reflection from there.
-                return (JavaExceptionReporter) SplitCompatUtils.newInstance(
-                        SplitCompatUtils.createChromeContext(ContextUtils.getApplicationContext()),
+                return (JavaExceptionReporter) BundleUtils.newInstance(
+                        createChromeContext(ContextUtils.getApplicationContext()),
                         "org.chromium.chrome.browser.crash.ChromePureJavaExceptionReporter");
             });
         }
@@ -265,6 +266,14 @@
         return !ContextUtils.getProcessName().contains(":");
     }
 
+    /** Creates a context which can be used to load code and resources in the chrome split. */
+    public static Context createChromeContext(Context base) {
+        if (!BundleUtils.isIsolatedSplitInstalled(base, CHROME_SPLIT_NAME)) {
+            return base;
+        }
+        return BundleUtils.createIsolatedSplitContext(base, CHROME_SPLIT_NAME);
+    }
+
     private void maybeInitProcessType() {
         if (isBrowserProcess()) {
             LibraryLoader.getInstance().setLibraryProcessType(LibraryProcessType.PROCESS_BROWSER);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatBackupAgent.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatBackupAgent.java
index ff5771da..3834b55b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatBackupAgent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatBackupAgent.java
@@ -10,6 +10,8 @@
 import android.content.Context;
 import android.os.ParcelFileDescriptor;
 
+import org.chromium.base.BundleUtils;
+
 import java.io.IOException;
 
 /**
@@ -26,8 +28,8 @@
 
     @Override
     protected void attachBaseContext(Context context) {
-        context = SplitCompatUtils.createChromeContext(context);
-        mImpl = (Impl) SplitCompatUtils.newInstance(context, mBackupAgentClassName);
+        context = SplitCompatApplication.createChromeContext(context);
+        mImpl = (Impl) BundleUtils.newInstance(context, mBackupAgentClassName);
         mImpl.setBackupAgent(this);
         super.attachBaseContext(context);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatContentProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatContentProvider.java
index a9e404b..de3aab3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatContentProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatContentProvider.java
@@ -10,6 +10,8 @@
 import android.database.Cursor;
 import android.net.Uri;
 
+import org.chromium.base.BundleUtils;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
@@ -31,8 +33,8 @@
         // when it is created.
         synchronized (mImplLock) {
             if (mImpl == null) {
-                Context context = SplitCompatUtils.createChromeContext(getContext());
-                mImpl = (Impl) SplitCompatUtils.newInstance(context, mContentProviderClassName);
+                Context context = SplitCompatApplication.createChromeContext(getContext());
+                mImpl = (Impl) BundleUtils.newInstance(context, mContentProviderClassName);
                 mImpl.setContentProvider(this);
             }
             return mImpl;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatCustomTabsService.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatCustomTabsService.java
index dcc6c100..ed47eff 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatCustomTabsService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatCustomTabsService.java
@@ -13,6 +13,8 @@
 import androidx.browser.customtabs.CustomTabsService;
 import androidx.browser.customtabs.CustomTabsSessionToken;
 
+import org.chromium.base.BundleUtils;
+
 import java.util.List;
 
 /**
@@ -29,8 +31,8 @@
 
     @Override
     protected void attachBaseContext(Context context) {
-        context = SplitCompatUtils.createChromeContext(context);
-        mImpl = (Impl) SplitCompatUtils.newInstance(context, mServiceClassName);
+        context = SplitCompatApplication.createChromeContext(context);
+        mImpl = (Impl) BundleUtils.newInstance(context, mServiceClassName);
         mImpl.setService(this);
         super.attachBaseContext(context);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatGcmListenerService.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatGcmListenerService.java
index a112b99..df01c8a2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatGcmListenerService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatGcmListenerService.java
@@ -10,6 +10,8 @@
 import com.google.firebase.messaging.FirebaseMessagingService;
 import com.google.firebase.messaging.RemoteMessage;
 
+import org.chromium.base.BundleUtils;
+
 /**
  * GcmListenerService base class which will call through to the given {@link Impl}. This class must
  * be present in the base module, while the Impl can be in the chrome module.
@@ -24,8 +26,8 @@
 
     @Override
     protected void attachBaseContext(Context context) {
-        context = SplitCompatUtils.createChromeContext(context);
-        mImpl = (Impl) SplitCompatUtils.newInstance(context, mServiceClassName);
+        context = SplitCompatApplication.createChromeContext(context);
+        mImpl = (Impl) BundleUtils.newInstance(context, mServiceClassName);
         mImpl.setService(this);
         super.attachBaseContext(context);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatGcmTaskService.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatGcmTaskService.java
index b451de9..bd826e2e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatGcmTaskService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatGcmTaskService.java
@@ -9,6 +9,8 @@
 import com.google.android.gms.gcm.GcmTaskService;
 import com.google.android.gms.gcm.TaskParams;
 
+import org.chromium.base.BundleUtils;
+
 /**
  * GcmTaskService base class which will call through to the given {@link Impl}. This class must be
  * present in the base module, while the Impl can be in the chrome module.
@@ -23,8 +25,8 @@
 
     @Override
     protected void attachBaseContext(Context context) {
-        context = SplitCompatUtils.createChromeContext(context);
-        mImpl = (Impl) SplitCompatUtils.newInstance(context, mServiceClassName);
+        context = SplitCompatApplication.createChromeContext(context);
+        mImpl = (Impl) BundleUtils.newInstance(context, mServiceClassName);
         mImpl.setService(this);
         super.attachBaseContext(context);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatIntentService.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatIntentService.java
index 9ab91f5..1eb0840 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatIntentService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatIntentService.java
@@ -10,6 +10,8 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import org.chromium.base.BundleUtils;
+
 /**
  * IntentService base class which will call through to the given {@link Impl}. This class must be
  * present in the base module, while the Impl can be in the chrome module.
@@ -25,8 +27,8 @@
 
     @Override
     protected void attachBaseContext(Context context) {
-        context = SplitCompatUtils.createChromeContext(context);
-        mImpl = (Impl) SplitCompatUtils.newInstance(context, mServiceClassName);
+        context = SplitCompatApplication.createChromeContext(context);
+        mImpl = (Impl) BundleUtils.newInstance(context, mServiceClassName);
         mImpl.setService(this);
         super.attachBaseContext(context);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatJobService.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatJobService.java
index bcf1045..0c915b2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatJobService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatJobService.java
@@ -34,9 +34,9 @@
         if (mSplitName != null && BundleUtils.isIsolatedSplitInstalled(context, mSplitName)) {
             context = BundleUtils.createIsolatedSplitContext(context, mSplitName);
         } else {
-            context = SplitCompatUtils.createChromeContext(context);
+            context = SplitCompatApplication.createChromeContext(context);
         }
-        mImpl = (Impl) SplitCompatUtils.newInstance(context, mServiceClassName);
+        mImpl = (Impl) BundleUtils.newInstance(context, mServiceClassName);
         mImpl.setService(this);
         super.attachBaseContext(context);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatMinidumpUploadJobService.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatMinidumpUploadJobService.java
index 1f8cfb9..6710b4a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatMinidumpUploadJobService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatMinidumpUploadJobService.java
@@ -7,6 +7,7 @@
 import android.content.Context;
 import android.os.PersistableBundle;
 
+import org.chromium.base.BundleUtils;
 import org.chromium.components.minidump_uploader.MinidumpUploadJob;
 import org.chromium.components.minidump_uploader.MinidumpUploadJobService;
 
@@ -24,8 +25,8 @@
 
     @Override
     protected void attachBaseContext(Context context) {
-        context = SplitCompatUtils.createChromeContext(context);
-        mImpl = (Impl) SplitCompatUtils.newInstance(context, mServiceClassName);
+        context = SplitCompatApplication.createChromeContext(context);
+        mImpl = (Impl) BundleUtils.newInstance(context, mServiceClassName);
         mImpl.setService(this);
         super.attachBaseContext(context);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatRemoteViewsService.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatRemoteViewsService.java
index 455f1db..0532cc67 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatRemoteViewsService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatRemoteViewsService.java
@@ -8,6 +8,8 @@
 import android.content.Intent;
 import android.widget.RemoteViewsService;
 
+import org.chromium.base.BundleUtils;
+
 /**
  * RemoteViewsService base class which will call through to the given {@link Impl}. This class must
  * be present in the base module, while the Impl can be in the chrome module.
@@ -22,8 +24,8 @@
 
     @Override
     protected void attachBaseContext(Context context) {
-        context = SplitCompatUtils.createChromeContext(context);
-        mImpl = (Impl) SplitCompatUtils.newInstance(context, mServiceClassName);
+        context = SplitCompatApplication.createChromeContext(context);
+        mImpl = (Impl) BundleUtils.newInstance(context, mServiceClassName);
         mImpl.setService(this);
         super.attachBaseContext(context);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatService.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatService.java
index 5162d49..74ccc8f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatService.java
@@ -11,6 +11,8 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import org.chromium.base.BundleUtils;
+
 /**
  * Service base class which will call through to the given {@link Impl}. This class must be present
  * in the base module, while the Impl can be in the chrome module.
@@ -25,8 +27,8 @@
 
     @Override
     protected void attachBaseContext(Context context) {
-        context = SplitCompatUtils.createChromeContext(context);
-        mImpl = (Impl) SplitCompatUtils.newInstance(context, mServiceClassName);
+        context = SplitCompatApplication.createChromeContext(context);
+        mImpl = (Impl) BundleUtils.newInstance(context, mServiceClassName);
         mImpl.setService(this);
         super.attachBaseContext(context);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatUtils.java
index 52189ca..f6c6824 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatUtils.java
@@ -4,192 +4,5 @@
 
 package org.chromium.chrome.browser.base;
 
-import android.content.Context;
-import android.content.ContextWrapper;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-
-import androidx.collection.ArrayMap;
-
-import org.chromium.base.BundleUtils;
-import org.chromium.base.ContextUtils;
-import org.chromium.base.annotations.IdentifierNameString;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Map;
-
-/** Utils for compatibility with isolated splits. */
-public class SplitCompatUtils {
-    public static final String CHROME_SPLIT_NAME = "chrome";
-    private static final String LOADED_SPLITS_KEY = "split_compat_loaded_splits";
-    private static final Map<String, ClassLoader> sInflationClassLoaders =
-            Collections.synchronizedMap(new ArrayMap<>());
-    private static SplitCompatClassLoader sSplitCompatClassLoaderInstance;
-    // List of splits that were loaded during the last run of chrome when
-    // restoring from recents.
-    private static ArrayList<String> sSplitsToRestore;
-
-    private SplitCompatUtils() {}
-
-    /**
-     * Gets the obfuscated name for the passed in class name. Important: this MUST be called with a
-     * string literal, otherwise @IdentifierNameString will not work.
-     */
-    @IdentifierNameString
-    public static String getIdentifierName(String className) {
-        return className;
-    }
-
-    /** Creates a context which can be used to load code and resources in the chrome split. */
-    public static Context createChromeContext(Context base) {
-        if (!BundleUtils.isIsolatedSplitInstalled(base, CHROME_SPLIT_NAME)) {
-            return base;
-        }
-        return BundleUtils.createIsolatedSplitContext(base, CHROME_SPLIT_NAME);
-    }
-
-    /**
-     * Constructs a new instance of the given class name. If the application context class loader
-     * can load the class, that class loader will be used, otherwise the class loader from the
-     * passed in context will be used.
-     */
-    public static Object newInstance(Context context, String className) {
-        Context appContext = ContextUtils.getApplicationContext();
-        if (appContext != null && canLoadClass(appContext.getClassLoader(), className)) {
-            context = appContext;
-        }
-        try {
-            return context.getClassLoader().loadClass(className).newInstance();
-        } catch (ReflectiveOperationException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Creates a context which can access classes from the specified split, but inherits theme
-     * resources from the passed in context. This is useful if a context is needed to inflate
-     * layouts which reference classes from a split.
-     */
-    public static Context createContextForInflation(Context context, String splitName) {
-        if (!BundleUtils.isIsolatedSplitInstalled(context, splitName)) {
-            return context;
-        }
-        ClassLoader splitClassLoader = registerSplitClassLoaderForInflation(splitName);
-        return new ContextWrapper(context) {
-            @Override
-            public ClassLoader getClassLoader() {
-                return splitClassLoader;
-            }
-
-            @Override
-            public Object getSystemService(String name) {
-                Object ret = super.getSystemService(name);
-                if (Context.LAYOUT_INFLATER_SERVICE.equals(name)) {
-                    ret = ((LayoutInflater) ret).cloneInContext(this);
-                }
-                return ret;
-            }
-        };
-    }
-
-    public static ClassLoader registerSplitClassLoaderForInflation(String splitName) {
-        ClassLoader splitClassLoader = sInflationClassLoaders.get(splitName);
-        if (splitClassLoader == null) {
-            splitClassLoader = BundleUtils
-                                       .createIsolatedSplitContext(
-                                               ContextUtils.getApplicationContext(), splitName)
-                                       .getClassLoader();
-            sInflationClassLoaders.put(splitName, splitClassLoader);
-        }
-        return splitClassLoader;
-    }
-
-    static boolean canLoadClass(ClassLoader classLoader, String className) {
-        try {
-            Class.forName(className, false, classLoader);
-            return true;
-        } catch (ClassNotFoundException e) {
-            return false;
-        }
-    }
-
-    public static ClassLoader getSplitCompatClassLoader() {
-        // SplitCompatClassLoader needs to be lazy loaded to ensure the Chrome
-        // context is loaded and its class loader is set as the parent
-        // classloader for the SplitCompatClassLoader. This happens in
-        // Application#attachBaseContext.
-        if (sSplitCompatClassLoaderInstance == null) {
-            sSplitCompatClassLoaderInstance = new SplitCompatClassLoader();
-        }
-        return sSplitCompatClassLoaderInstance;
-    }
-
-    public static void saveLoadedSplits(Bundle outState) {
-        outState.putStringArrayList(
-                LOADED_SPLITS_KEY, new ArrayList(sInflationClassLoaders.keySet()));
-    }
-
-    public static void restoreLoadedSplits(Bundle savedInstanceState) {
-        if (savedInstanceState == null) {
-            return;
-        }
-        sSplitsToRestore = savedInstanceState.getStringArrayList(LOADED_SPLITS_KEY);
-    }
-
-    private static class SplitCompatClassLoader extends ClassLoader {
-        public SplitCompatClassLoader() {
-            // The chrome split classloader if the chrome split exists, otherwise
-            // the base module class loader.
-            super(ContextUtils.getApplicationContext().getClassLoader());
-        }
-
-        private Class<?> checkSplitsClassLoaders(String className) throws ClassNotFoundException {
-            for (ClassLoader cl : sInflationClassLoaders.values()) {
-                try {
-                    return cl.loadClass(className);
-                } catch (ClassNotFoundException ignore) {
-                }
-            }
-            return null;
-        }
-
-        /**
-         * Loads the class with the specified binary name.
-         */
-        @Override
-        public Class<?> findClass(String cn) throws ClassNotFoundException {
-            Class<?> foundClass = checkSplitsClassLoaders(cn);
-            if (foundClass != null) {
-                return foundClass;
-            }
-            // We will never have android.* classes in isolated split class loaders,
-            // but android framework inflater does sometimes try loading classes
-            // that do not exist when inflating xml files on startup.
-            if (!cn.startsWith("android.") && sSplitsToRestore != null) {
-                // If we fail from all the currently loaded classLoaders, lets
-                // try loading some splits that were loaded when chrome was last
-                // run and check again.
-                restoreSplitsClassLoaders();
-                foundClass = checkSplitsClassLoaders(cn);
-                if (foundClass != null) {
-                    return foundClass;
-                }
-            }
-            throw new ClassNotFoundException(cn);
-        }
-
-        private void restoreSplitsClassLoaders() {
-            if (sSplitsToRestore == null) {
-                return;
-            }
-            // Load splits that were stored in the SavedInstanceState Bundle.
-            for (String splitName : sSplitsToRestore) {
-                if (!sInflationClassLoaders.containsKey(splitName)) {
-                    registerSplitClassLoaderForInflation(splitName);
-                }
-            }
-            sSplitsToRestore = null;
-        }
-    }
-}
+// TODO(b/b/183478921): Remove this once all references are removed in internal repos.
+public class SplitCompatUtils extends org.chromium.base.BundleUtils {}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitMonochromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitMonochromeApplication.java
index df2e59d..39c3fb8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitMonochromeApplication.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitMonochromeApplication.java
@@ -7,6 +7,7 @@
 import android.content.Context;
 
 import org.chromium.android_webview.nonembedded.WebViewApkApplication;
+import org.chromium.base.annotations.IdentifierNameString;
 import org.chromium.base.library_loader.LibraryProcessType;
 import org.chromium.components.version_info.VersionInfo;
 import org.chromium.content_public.browser.ChildProcessCreationParams;
@@ -16,6 +17,10 @@
  * SplitChromeApplication} for more info.
  */
 public class SplitMonochromeApplication extends SplitChromeApplication {
+    @IdentifierNameString
+    private static final String IMPL_CLASS_NAME =
+            "org.chromium.chrome.browser.MonochromeApplicationImpl";
+
     private static class NonBrowserMonochromeApplication extends Impl {
         @Override
         public void onCreate() {
@@ -29,8 +34,7 @@
     }
 
     public SplitMonochromeApplication() {
-        super(SplitCompatUtils.getIdentifierName(
-                "org.chromium.chrome.browser.MonochromeApplicationImpl"));
+        super(IMPL_CLASS_NAME);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkBridge.java
index 88fae7d..d56d1b0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkBridge.java
@@ -229,71 +229,70 @@
             mRead = read;
         }
 
-        /** @return Title of the bookmark item. */
+        /** Returns the title of the bookmark item. */
         public String getTitle() {
             return mTitle;
         }
 
-        /** @return Url of the bookmark item. */
+        /** Returns the url of the bookmark item. */
         public GURL getUrl() {
             return mUrl;
         }
 
-        /** @return The string to display for the item's url. */
+        /** Returns the string to display for the item's url. */
         public String getUrlForDisplay() {
             return UrlFormatter.formatUrlForSecurityDisplay(
                     getUrl(), SchemeDisplay.OMIT_HTTP_AND_HTTPS);
         }
 
-        /** @return Whether item is a folder or a bookmark. */
+        /** Returns whether item is a folder or a bookmark. */
         public boolean isFolder() {
             return mIsFolder;
         }
 
-        /** @return Parent id of the bookmark item. */
+        /** Returns the parent id of the bookmark item. */
         public BookmarkId getParentId() {
             return mParentId;
         }
 
-        /** @return Whether this bookmark can be edited. */
+        /** Returns whether this bookmark can be edited. */
         public boolean isEditable() {
             return mForceEditableForTesting || mIsEditable;
         }
 
-        /**@return Whether this bookmark's URL can be edited */
+        /** Returns whether this bookmark's URL can be edited */
         public boolean isUrlEditable() {
             return isEditable() && mId.getType() == BookmarkType.NORMAL;
         }
 
-        /**@return Whether this bookmark can be moved */
+        /** Returns whether this bookmark can be moved */
         public boolean isMovable() {
             return ReadingListUtils.isSwappableReadingListItem(mId) || isReorderable();
         }
 
-        /**@return Whether this bookmark can be moved */
+        /** Returns whether this bookmark can be moved */
         public boolean isReorderable() {
             return isEditable() && mId.getType() == BookmarkType.NORMAL;
         }
 
-        /** @return Whether this is a managed bookmark. */
+        /** Returns whether this is a managed bookmark. */
         public boolean isManaged() {
             return mIsManaged;
         }
 
+        /** Returns the {@link BookmarkId}. */
         public BookmarkId getId() {
             return mId;
         }
 
-        /**
-         * @return The timestamp in milliseconds since epoch that the bookmark is added.
-         */
+        /** Retuns the timestamp in milliseconds since epoch that the bookmark is added. */
         public long getDateAdded() {
             return mDateAdded;
         }
 
         /**
-         * @return Whether the bookmark is read. Only valid for {@link BookmarkType#READING_LIST}.
-         *         Defaults to "false" for other types.
+         * Returns whether the bookmark is read. Only valid for {@link BookmarkType#READING_LIST}.
+         * Defaults to "false" for other types.
          */
         public boolean isRead() {
             return mRead;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetService.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetService.java
index f695494d..a7f599a3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetService.java
@@ -4,13 +4,16 @@
 
 package org.chromium.chrome.browser.bookmarkswidget;
 
+import org.chromium.base.annotations.IdentifierNameString;
 import org.chromium.chrome.browser.base.SplitCompatRemoteViewsService;
-import org.chromium.chrome.browser.base.SplitCompatUtils;
 
 /** See {@link BookmarkWidgetServiceImpl}. */
 public class BookmarkWidgetService extends SplitCompatRemoteViewsService {
+    @IdentifierNameString
+    private static final String IMPL_CLASS_NAME =
+            "org.chromium.chrome.browser.bookmarkswidget.BookmarkWidgetServiceImpl";
+
     public BookmarkWidgetService() {
-        super(SplitCompatUtils.getIdentifierName(
-                "org.chromium.chrome.browser.bookmarkswidget.BookmarkWidgetServiceImpl"));
+        super(IMPL_CLASS_NAME);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/crash/ChromeMinidumpUploadJobService.java b/chrome/android/java/src/org/chromium/chrome/browser/crash/ChromeMinidumpUploadJobService.java
index 9cc2ec51..043a1370 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/crash/ChromeMinidumpUploadJobService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/crash/ChromeMinidumpUploadJobService.java
@@ -4,13 +4,16 @@
 
 package org.chromium.chrome.browser.crash;
 
+import org.chromium.base.annotations.IdentifierNameString;
 import org.chromium.chrome.browser.base.SplitCompatMinidumpUploadJobService;
-import org.chromium.chrome.browser.base.SplitCompatUtils;
 
 /** See {@link ChromeMinidumpUploadJobServiceImpl}. */
 public class ChromeMinidumpUploadJobService extends SplitCompatMinidumpUploadJobService {
+    @IdentifierNameString
+    private static final String IMPL_CLASS_NAME =
+            "org.chromium.chrome.browser.crash.ChromeMinidumpUploadJobServiceImpl";
+
     public ChromeMinidumpUploadJobService() {
-        super(SplitCompatUtils.getIdentifierName(
-                "org.chromium.chrome.browser.crash.ChromeMinidumpUploadJobServiceImpl"));
+        super(IMPL_CLASS_NAME);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java b/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java
index f57cd0ad..5eb3b4e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java
@@ -4,16 +4,18 @@
 
 package org.chromium.chrome.browser.crash;
 
+import org.chromium.base.annotations.IdentifierNameString;
 import org.chromium.chrome.browser.base.SplitCompatIntentService;
-import org.chromium.chrome.browser.base.SplitCompatUtils;
 
 /** See {@link MinidumpUploadServiceImpl}. */
 public class MinidumpUploadService extends SplitCompatIntentService {
     private static final String TAG = "MinidmpUploadService";
 
+    @IdentifierNameString
+    private static final String IMPL_CLASS_NAME =
+            "org.chromium.chrome.browser.crash.MinidumpUploadServiceImpl";
+
     public MinidumpUploadService() {
-        super(SplitCompatUtils.getIdentifierName(
-                      "org.chromium.chrome.browser.crash.MinidumpUploadServiceImpl"),
-                TAG);
+        super(IMPL_CLASS_NAME, TAG);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionService.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionService.java
index 0f4409b..787b483f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionService.java
@@ -4,13 +4,16 @@
 
 package org.chromium.chrome.browser.customtabs;
 
+import org.chromium.base.annotations.IdentifierNameString;
 import org.chromium.chrome.browser.base.SplitCompatCustomTabsService;
-import org.chromium.chrome.browser.base.SplitCompatUtils;
 
 /** See {@link CustomTabsConnectionServiceImpl}. */
 public class CustomTabsConnectionService extends SplitCompatCustomTabsService {
+    @IdentifierNameString
+    private static final String IMPL_CLASS_NAME =
+            "org.chromium.chrome.browser.customtabs.CustomTabsConnectionServiceImpl";
+
     public CustomTabsConnectionService() {
-        super(SplitCompatUtils.getIdentifierName(
-                "org.chromium.chrome.browser.customtabs.CustomTabsConnectionServiceImpl"));
+        super(IMPL_CLASS_NAME);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java
index 9804531..c7f991d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java
@@ -4,13 +4,16 @@
 
 package org.chromium.chrome.browser.download;
 
+import org.chromium.base.annotations.IdentifierNameString;
 import org.chromium.chrome.browser.base.SplitCompatService;
-import org.chromium.chrome.browser.base.SplitCompatUtils;
 
 /** See {@link DownloadBroadcastManagerImpl}. */
 public class DownloadBroadcastManager extends SplitCompatService {
+    @IdentifierNameString
+    private static final String IMPL_CLASS_NAME =
+            "org.chromium.chrome.browser.download.DownloadBroadcastManagerImpl";
+
     public DownloadBroadcastManager() {
-        super(SplitCompatUtils.getIdentifierName(
-                "org.chromium.chrome.browser.download.DownloadBroadcastManagerImpl"));
+        super(IMPL_CLASS_NAME);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadForegroundService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadForegroundService.java
index 7089725..3f831ae 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadForegroundService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadForegroundService.java
@@ -4,13 +4,16 @@
 
 package org.chromium.chrome.browser.download;
 
+import org.chromium.base.annotations.IdentifierNameString;
 import org.chromium.chrome.browser.base.SplitCompatService;
-import org.chromium.chrome.browser.base.SplitCompatUtils;
 
 /** See {@link DownloadForegroundServiceImpl}. */
 public class DownloadForegroundService extends SplitCompatService {
+    @IdentifierNameString
+    private static final String IMPL_CLASS_NAME =
+            "org.chromium.chrome.browser.download.DownloadForegroundServiceImpl";
+
     public DownloadForegroundService() {
-        super(SplitCompatUtils.getIdentifierName(
-                "org.chromium.chrome.browser.download.DownloadForegroundServiceImpl"));
+        super(IMPL_CLASS_NAME);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoNotificationService.java b/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoNotificationService.java
index 2a9a586..3bb0b6a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoNotificationService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoNotificationService.java
@@ -4,15 +4,18 @@
 
 package org.chromium.chrome.browser.incognito;
 
+import org.chromium.base.annotations.IdentifierNameString;
 import org.chromium.chrome.browser.base.SplitCompatIntentService;
-import org.chromium.chrome.browser.base.SplitCompatUtils;
 
 /** See {@link IncognitoNotificationServiceImpl}. */
 public class IncognitoNotificationService extends SplitCompatIntentService {
     private static final String TAG = "incognito_notification";
+
+    @IdentifierNameString
+    private static final String IMPL_CLASS_NAME =
+            "org.chromium.chrome.browser.incognito.IncognitoNotificationServiceImpl";
+
     public IncognitoNotificationService() {
-        super(SplitCompatUtils.getIdentifierName(
-                      "org.chromium.chrome.browser.incognito.IncognitoNotificationServiceImpl"),
-                TAG);
+        super(IMPL_CLASS_NAME, TAG);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCaptureNotificationService.java b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCaptureNotificationService.java
index ce8e8a9..89d1cc3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCaptureNotificationService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCaptureNotificationService.java
@@ -4,13 +4,16 @@
 
 package org.chromium.chrome.browser.media;
 
+import org.chromium.base.annotations.IdentifierNameString;
 import org.chromium.chrome.browser.base.SplitCompatService;
-import org.chromium.chrome.browser.base.SplitCompatUtils;
 
 /** See {@link MediaCaptureNotificationServiceImpl}. */
 public class MediaCaptureNotificationService extends SplitCompatService {
+    @IdentifierNameString
+    private static final String IMPL_CLASS_NAME =
+            "org.chromium.chrome.browser.media.MediaCaptureNotificationServiceImpl";
+
     public MediaCaptureNotificationService() {
-        super(SplitCompatUtils.getIdentifierName(
-                "org.chromium.chrome.browser.media.MediaCaptureNotificationServiceImpl"));
+        super(IMPL_CLASS_NAME);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/ChromeMediaNotificationControllerServices.java b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/ChromeMediaNotificationControllerServices.java
index d52f818..2a11095 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/ChromeMediaNotificationControllerServices.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/ChromeMediaNotificationControllerServices.java
@@ -4,32 +4,41 @@
 
 package org.chromium.chrome.browser.media.ui;
 
+import org.chromium.base.annotations.IdentifierNameString;
 import org.chromium.chrome.browser.base.SplitCompatService;
-import org.chromium.chrome.browser.base.SplitCompatUtils;
 
 /** Exposes services from {@link ChromeMediaNotificationControllerDelegate} in the base module. */
 public class ChromeMediaNotificationControllerServices {
     /** See {@link ChromeMediaNotificationControllerDelegate$PlaybackListenerServiceImpl}. */
     public static class PlaybackListenerService extends SplitCompatService {
+        @IdentifierNameString
+        private static final String IMPL_CLASS_NAME = "org.chromium.chrome.browser.media.ui."
+                + "ChromeMediaNotificationControllerDelegate$PlaybackListenerServiceImpl";
+
         public PlaybackListenerService() {
-            super(SplitCompatUtils.getIdentifierName("org.chromium.chrome.browser.media.ui."
-                    + "ChromeMediaNotificationControllerDelegate$PlaybackListenerServiceImpl"));
+            super(IMPL_CLASS_NAME);
         }
     }
 
     /** See {@link ChromeMediaNotificationControllerDelegate$PresentationListenerServiceImpl}. */
     public static class PresentationListenerService extends SplitCompatService {
+        @IdentifierNameString
+        private static final String IMPL_CLASS_NAME = "org.chromium.chrome.browser.media.ui."
+                + "ChromeMediaNotificationControllerDelegate$PresentationListenerServiceImpl";
+
         public PresentationListenerService() {
-            super(SplitCompatUtils.getIdentifierName("org.chromium.chrome.browser.media.ui."
-                    + "ChromeMediaNotificationControllerDelegate$PresentationListenerServiceImpl"));
+            super(IMPL_CLASS_NAME);
         }
     }
 
     /** See {@link ChromeMediaNotificationControllerDelegate$CastListenerServiceImpl}. */
     public static class CastListenerService extends SplitCompatService {
+        @IdentifierNameString
+        private static final String IMPL_CLASS_NAME = "org.chromium.chrome.browser.media.ui."
+                + "ChromeMediaNotificationControllerDelegate$CastListenerServiceImpl";
+
         public CastListenerService() {
-            super(SplitCompatUtils.getIdentifierName("org.chromium.chrome.browser.media.ui."
-                    + "ChromeMediaNotificationControllerDelegate$CastListenerServiceImpl"));
+            super(IMPL_CLASS_NAME);
         }
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationJobService.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationJobService.java
index d35fef1..a605574 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationJobService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationJobService.java
@@ -4,13 +4,16 @@
 
 package org.chromium.chrome.browser.notifications;
 
+import org.chromium.base.annotations.IdentifierNameString;
 import org.chromium.chrome.browser.base.SplitCompatJobService;
-import org.chromium.chrome.browser.base.SplitCompatUtils;
 
 /** See {@link NotificationJobServiceImpl}. */
 public class NotificationJobService extends SplitCompatJobService {
+    @IdentifierNameString
+    private static final String IMPL_CLASS_NAME =
+            "org.chromium.chrome.browser.notifications.NotificationJobServiceImpl";
+
     public NotificationJobService() {
-        super(SplitCompatUtils.getIdentifierName(
-                "org.chromium.chrome.browser.notifications.NotificationJobServiceImpl"));
+        super(IMPL_CLASS_NAME);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationService.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationService.java
index eec69fd..f53527d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationService.java
@@ -8,17 +8,20 @@
 import android.content.Context;
 import android.content.Intent;
 
+import org.chromium.base.BundleUtils;
+import org.chromium.base.annotations.IdentifierNameString;
 import org.chromium.chrome.browser.base.SplitCompatIntentService;
-import org.chromium.chrome.browser.base.SplitCompatUtils;
 
 /** See {@link NotificationServiceImpl}. */
 public class NotificationService extends SplitCompatIntentService {
     private static final String TAG = NotificationService.class.getSimpleName();
 
+    @IdentifierNameString
+    private static final String IMPL_CLASS_NAME =
+            "org.chromium.chrome.browser.notifications.NotificationServiceImpl";
+
     public NotificationService() {
-        super(SplitCompatUtils.getIdentifierName(
-                      "org.chromium.chrome.browser.notifications.NotificationServiceImpl"),
-                TAG);
+        super(IMPL_CLASS_NAME, TAG);
     }
 
     /**
@@ -28,7 +31,7 @@
     public static class Receiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
-            BroadcastReceiver receiver = (BroadcastReceiver) SplitCompatUtils.newInstance(context,
+            BroadcastReceiver receiver = (BroadcastReceiver) BundleUtils.newInstance(context,
                     "org.chromium.chrome.browser.notifications.NotificationServiceImpl$Receiver");
             receiver.onReceive(context, intent);
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaClient.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaClient.java
index 60eda73..20df6ae6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaClient.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaClient.java
@@ -4,16 +4,18 @@
 
 package org.chromium.chrome.browser.omaha;
 
+import org.chromium.base.annotations.IdentifierNameString;
 import org.chromium.chrome.browser.base.SplitCompatIntentService;
-import org.chromium.chrome.browser.base.SplitCompatUtils;
 
 /** See {@link OmahaClientImpl}. */
 public class OmahaClient extends SplitCompatIntentService {
     private static final String TAG = "omaha";
 
+    @IdentifierNameString
+    private static final String IMPL_CLASS_NAME =
+            "org.chromium.chrome.browser.omaha.OmahaClientImpl";
+
     public OmahaClient() {
-        super(SplitCompatUtils.getIdentifierName(
-                      "org.chromium.chrome.browser.omaha.OmahaClientImpl"),
-                TAG);
+        super(IMPL_CLASS_NAME, TAG);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderService.java b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderService.java
index d45afcd..cdee644 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderService.java
@@ -4,13 +4,16 @@
 
 package org.chromium.chrome.browser.photo_picker;
 
+import org.chromium.base.annotations.IdentifierNameString;
 import org.chromium.chrome.browser.base.SplitCompatService;
-import org.chromium.chrome.browser.base.SplitCompatUtils;
 
 /** See {@link DecoderServiceImpl}. */
 public class DecoderService extends SplitCompatService {
+    @IdentifierNameString
+    private static final String IMPL_CLASS_NAME =
+            "org.chromium.chrome.browser.photo_picker.DecoderServiceImpl";
+
     public DecoderService() {
-        super(SplitCompatUtils.getIdentifierName(
-                "org.chromium.chrome.browser.photo_picker.DecoderServiceImpl"));
+        super(IMPL_CLASS_NAME);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/prerender/ChromePrerenderService.java b/chrome/android/java/src/org/chromium/chrome/browser/prerender/ChromePrerenderService.java
index 0773d095..987c8675 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/prerender/ChromePrerenderService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/prerender/ChromePrerenderService.java
@@ -4,13 +4,16 @@
 
 package org.chromium.chrome.browser.prerender;
 
+import org.chromium.base.annotations.IdentifierNameString;
 import org.chromium.chrome.browser.base.SplitCompatService;
-import org.chromium.chrome.browser.base.SplitCompatUtils;
 
 /** See {@link ChromePrerenderServiceImpl}. */
 public class ChromePrerenderService extends SplitCompatService {
+    @IdentifierNameString
+    private static final String IMPL_CLASS_NAME =
+            "org.chromium.chrome.browser.prerender.ChromePrerenderServiceImpl";
+
     public ChromePrerenderService() {
-        super(SplitCompatUtils.getIdentifierName(
-                "org.chromium.chrome.browser.prerender.ChromePrerenderServiceImpl"));
+        super(IMPL_CLASS_NAME);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/provider/ChromeBrowserProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/provider/ChromeBrowserProvider.java
index b58d803..e773209 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/provider/ChromeBrowserProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/provider/ChromeBrowserProvider.java
@@ -4,13 +4,16 @@
 
 package org.chromium.chrome.browser.provider;
 
+import org.chromium.base.annotations.IdentifierNameString;
 import org.chromium.chrome.browser.base.SplitCompatContentProvider;
-import org.chromium.chrome.browser.base.SplitCompatUtils;
 
 /** See {@link ChromeBrowserProviderImpl}. */
 public class ChromeBrowserProvider extends SplitCompatContentProvider {
+    @IdentifierNameString
+    private static final String IMPL_CLASS_NAME =
+            "org.chromium.chrome.browser.provider.ChromeBrowserProviderImpl";
+
     public ChromeBrowserProvider() {
-        super(SplitCompatUtils.getIdentifierName(
-                "org.chromium.chrome.browser.provider.ChromeBrowserProviderImpl"));
+        super(IMPL_CLASS_NAME);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/services/gcm/ChromeGcmListenerService.java b/chrome/android/java/src/org/chromium/chrome/browser/services/gcm/ChromeGcmListenerService.java
index f114cc32..88cd42331 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/services/gcm/ChromeGcmListenerService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/services/gcm/ChromeGcmListenerService.java
@@ -6,8 +6,8 @@
 
 import android.annotation.SuppressLint;
 
+import org.chromium.base.annotations.IdentifierNameString;
 import org.chromium.chrome.browser.base.SplitCompatGcmListenerService;
-import org.chromium.chrome.browser.base.SplitCompatUtils;
 
 /**
  * See {@link ChromeGcmListenerServiceImpl}.
@@ -15,8 +15,11 @@
  */
 @SuppressLint("MissingFirebaseInstanceTokenRefresh")
 public class ChromeGcmListenerService extends SplitCompatGcmListenerService {
+    @IdentifierNameString
+    private static final String IMPL_CLASS_NAME =
+            "org.chromium.chrome.browser.services.gcm.ChromeGcmListenerServiceImpl";
+
     public ChromeGcmListenerService() {
-        super(SplitCompatUtils.getIdentifierName(
-                "org.chromium.chrome.browser.services.gcm.ChromeGcmListenerServiceImpl"));
+        super(IMPL_CLASS_NAME);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/services/gcm/GCMBackgroundService.java b/chrome/android/java/src/org/chromium/chrome/browser/services/gcm/GCMBackgroundService.java
index 2187839c..e3e5589 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/services/gcm/GCMBackgroundService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/services/gcm/GCMBackgroundService.java
@@ -4,16 +4,18 @@
 
 package org.chromium.chrome.browser.services.gcm;
 
+import org.chromium.base.annotations.IdentifierNameString;
 import org.chromium.chrome.browser.base.SplitCompatIntentService;
-import org.chromium.chrome.browser.base.SplitCompatUtils;
 
 /** See {@link GCMBackgroundServiceImpl}. */
 public class GCMBackgroundService extends SplitCompatIntentService {
     private static final String TAG = "GCMBackgroundService";
 
+    @IdentifierNameString
+    private static final String IMPL_CLASS_NAME =
+            "org.chromium.chrome.browser.services.gcm.GCMBackgroundServiceImpl";
+
     public GCMBackgroundService() {
-        super(SplitCompatUtils.getIdentifierName(
-                      "org.chromium.chrome.browser.services.gcm.GCMBackgroundServiceImpl"),
-                TAG);
+        super(IMPL_CLASS_NAME, TAG);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tracing/TracingNotificationService.java b/chrome/android/java/src/org/chromium/chrome/browser/tracing/TracingNotificationService.java
index 0d3e395..868c0fd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tracing/TracingNotificationService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tracing/TracingNotificationService.java
@@ -4,16 +4,18 @@
 
 package org.chromium.chrome.browser.tracing;
 
+import org.chromium.base.annotations.IdentifierNameString;
 import org.chromium.chrome.browser.base.SplitCompatIntentService;
-import org.chromium.chrome.browser.base.SplitCompatUtils;
 
 /** See {@link TracingNotificationServiceImpl}. */
 public class TracingNotificationService extends SplitCompatIntentService {
     private static final String TAG = "tracing_notification";
 
+    @IdentifierNameString
+    private static final String IMPL_CLASS_NAME =
+            "org.chromium.chrome.browser.tracing.TracingNotificationServiceImpl";
+
     public TracingNotificationService() {
-        super(SplitCompatUtils.getIdentifierName(
-                      "org.chromium.chrome.browser.tracing.TracingNotificationServiceImpl"),
-                TAG);
+        super(IMPL_CLASS_NAME, TAG);
     }
 }
diff --git a/chrome/android/proguard/main.flags b/chrome/android/proguard/main.flags
index 2ab835b5..6003204 100644
--- a/chrome/android/proguard/main.flags
+++ b/chrome/android/proguard/main.flags
@@ -36,8 +36,9 @@
   *** build() return null;
 }
 
+# TODO(b/214263216): Allow obfuscation once R8 is fixed.
 # Keep implementation classes needed for split compat. These will be accessed by
 # reflection.
--keep,allowobfuscation public class ** extends org.chromium.chrome.browser.base.SplitCompat*$Impl {
+-keep public class ** extends org.chromium.chrome.browser.base.SplitCompat*$Impl {
   public <init>();
 }
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 26238f5..47b70f1 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3028,10 +3028,6 @@
     {"vertical-snap", flag_descriptions::kVerticalSnapName,
      flag_descriptions::kVerticalSnapDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(chromeos::wm::features::kVerticalSnap)},
-    {"ash-advanced-screen-capture-settings",
-     flag_descriptions::kImprovedScreenCaptureSettingsName,
-     flag_descriptions::kImprovedScreenCaptureSettingsDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(ash::features::kImprovedScreenCaptureSettings)},
     {"ash-bento-bar", flag_descriptions::kBentoBarName,
      flag_descriptions::kBentoBarDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(ash::features::kBentoBar)},
@@ -7408,6 +7404,10 @@
 #endif  // defined(OS_WIN)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+    {"enable-holding-space-in-progress-animation-v2",
+     flag_descriptions::kHoldingSpaceInProgressAnimationV2Name,
+     flag_descriptions::kHoldingSpaceInProgressAnimationV2Description, kOsCrOS,
+     FEATURE_VALUE_TYPE(ash::features::kHoldingSpaceInProgressAnimationV2)},
     {"enable-holding-space-in-progress-downloads-integration",
      flag_descriptions::kHoldingSpaceInProgressDownloadsIntegrationName,
      flag_descriptions::kHoldingSpaceInProgressDownloadsIntegrationDescription,
diff --git a/chrome/browser/accessibility/accessibility_extension_api_chromeos.cc b/chrome/browser/accessibility/accessibility_extension_api_chromeos.cc
index efc4a13..4d9edd2 100644
--- a/chrome/browser/accessibility/accessibility_extension_api_chromeos.cc
+++ b/chrome/browser/accessibility/accessibility_extension_api_chromeos.cc
@@ -86,7 +86,7 @@
   // TODO(chrome-a11y-core): we can't open a settings page when you're on the
   // signin profile, but maybe we should notify the user and explain why?
   Profile* profile = AccessibilityManager::Get()->profile();
-  if (!chromeos::ProfileHelper::IsSigninProfile(profile) &&
+  if (!ash::ProfileHelper::IsSigninProfile(profile) &&
       chromeos::settings::IsOSSettingsSubPage(params->subpage)) {
     chrome::SettingsWindowManager::GetInstance()->ShowOSSettings(
         profile, params->subpage);
diff --git a/chrome/browser/apps/app_service/app_service_proxy_ash.cc b/chrome/browser/apps/app_service/app_service_proxy_ash.cc
index ddada5a..6f9e4b8 100644
--- a/chrome/browser/apps/app_service/app_service_proxy_ash.cc
+++ b/chrome/browser/apps/app_service/app_service_proxy_ash.cc
@@ -74,7 +74,7 @@
   }
 
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile_);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile_);
   if (user) {
     const AccountId& account_id = user->GetAccountId();
     app_registry_cache_.SetAccountId(account_id);
@@ -110,7 +110,7 @@
   publisher_host_ = std::make_unique<PublisherHost>(this);
 
   if (crosapi::browser_util::IsLacrosEnabled() &&
-      chromeos::ProfileHelper::IsPrimaryProfile(profile_) &&
+      ash::ProfileHelper::IsPrimaryProfile(profile_) &&
       web_app::IsWebAppsCrosapiEnabled()) {
     auto* browser_manager = crosapi::BrowserManager::Get();
     // In unit tests, it is possible that the browser manager is not created.
diff --git a/chrome/browser/apps/app_service/app_service_proxy_factory.cc b/chrome/browser/apps/app_service/app_service_proxy_factory.cc
index d6d2a6d..152d71b3 100644
--- a/chrome/browser/apps/app_service/app_service_proxy_factory.cc
+++ b/chrome/browser/apps/app_service/app_service_proxy_factory.cc
@@ -42,7 +42,7 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   // An exception on Chrome OS is the guest profile, which is incognito, but
   // can have apps within it.
-  return (!chromeos::ProfileHelper::IsSigninProfile(profile) &&
+  return (!ash::ProfileHelper::IsSigninProfile(profile) &&
           (!profile->IsOffTheRecord() || profile->IsGuestSession()));
 #else
   return !profile->IsOffTheRecord();
@@ -110,7 +110,7 @@
   }
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  if (chromeos::ProfileHelper::IsSigninProfile(profile)) {
+  if (ash::ProfileHelper::IsSigninProfile(profile)) {
     return nullptr;
   }
 
diff --git a/chrome/browser/apps/app_service/metrics/app_platform_metrics_service_unittest.cc b/chrome/browser/apps/app_service/metrics/app_platform_metrics_service_unittest.cc
index ab3b876..81986fe 100644
--- a/chrome/browser/apps/app_service/metrics/app_platform_metrics_service_unittest.cc
+++ b/chrome/browser/apps/app_service/metrics/app_platform_metrics_service_unittest.cc
@@ -151,7 +151,7 @@
                               SyncServiceFactory::GetDefaultFactory());
     testing_profile_ = builder.Build();
 
-    chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
+    ash::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
         user, testing_profile_.get());
 
     sync_service_ = static_cast<syncer::TestSyncService*>(
diff --git a/chrome/browser/apps/app_service/metrics/app_platform_metrics_utils.cc b/chrome/browser/apps/app_service/metrics/app_platform_metrics_utils.cc
index 30775e4..aafcf0b 100644
--- a/chrome/browser/apps/app_service/metrics/app_platform_metrics_utils.cc
+++ b/chrome/browser/apps/app_service/metrics/app_platform_metrics_utils.cc
@@ -257,8 +257,7 @@
       user_manager::UserManager::Get()->GetPrimaryUser();
   DCHECK(primary_user);
   DCHECK(primary_user->is_profile_created());
-  Profile* profile =
-      chromeos::ProfileHelper::Get()->GetProfileByUser(primary_user);
+  Profile* profile = ash::ProfileHelper::Get()->GetProfileByUser(primary_user);
   DCHECK(profile);
 
   UserTypeByDeviceTypeMetricsProvider::UserSegment user_segment =
diff --git a/chrome/browser/apps/app_service/publisher_host.cc b/chrome/browser/apps/app_service/publisher_host.cc
index 8afd500..d4d88b31 100644
--- a/chrome/browser/apps/app_service/publisher_host.cc
+++ b/chrome/browser/apps/app_service/publisher_host.cc
@@ -125,7 +125,7 @@
   // profile. This also avoids creating an instance for the lock screen app
   // profile and ensures there is only one instance of StandaloneBrowserApps.
   if (crosapi::browser_util::IsLacrosEnabled() &&
-      chromeos::ProfileHelper::IsPrimaryProfile(profile)) {
+      ash::ProfileHelper::IsPrimaryProfile(profile)) {
     standalone_browser_apps_ = std::make_unique<StandaloneBrowserApps>(proxy_);
     standalone_browser_apps_->Initialize();
   }
diff --git a/chrome/browser/apps/app_service/publishers/plugin_vm_apps.cc b/chrome/browser/apps/app_service/publishers/plugin_vm_apps.cc
index 9cbb945..689532a 100644
--- a/chrome/browser/apps/app_service/publishers/plugin_vm_apps.cc
+++ b/chrome/browser/apps/app_service/publishers/plugin_vm_apps.cc
@@ -136,7 +136,7 @@
   // `PluginVmFeatures::Get()->IsAllowed()` here because we still let the user
   // uninstall Plugin VM when it isn't allowed for some other reasons (e.g.
   // policy).
-  if (!chromeos::ProfileHelper::IsPrimaryProfile(profile_)) {
+  if (!ash::ProfileHelper::IsPrimaryProfile(profile_)) {
     return;
   }
 
diff --git a/chrome/browser/ash/account_manager/account_manager_util.cc b/chrome/browser/ash/account_manager/account_manager_util.cc
index ed0e024..5030275f 100644
--- a/chrome/browser/ash/account_manager/account_manager_util.cc
+++ b/chrome/browser/ash/account_manager/account_manager_util.cc
@@ -27,7 +27,7 @@
   // Signin Profile does not have any accounts associated with it,
   // LockScreenAppProfile and LockScreenProfile do not link to the user's
   // cryptohome.
-  if (!chromeos::ProfileHelper::IsRegularProfile(profile))
+  if (!ProfileHelper::IsRegularProfile(profile))
     return false;
 
   // Account Manager is unavailable on Guest (Incognito) Sessions.
diff --git a/chrome/browser/ash/app_restore/full_restore_service.cc b/chrome/browser/ash/app_restore/full_restore_service.cc
index e7b0bad0..ce8cff4 100644
--- a/chrome/browser/ash/app_restore/full_restore_service.cc
+++ b/chrome/browser/ash/app_restore/full_restore_service.cc
@@ -57,7 +57,7 @@
   const user_manager::User* user =
       user_manager::UserManager::Get()->GetPrimaryUser();
   DCHECK(user);
-  Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+  Profile* profile = ProfileHelper::Get()->GetProfileByUser(user);
   DCHECK(profile);
   return FullRestoreServiceFactory::IsFullRestoreAvailableForProfile(profile);
 }
diff --git a/chrome/browser/ash/app_restore/full_restore_service_unittest.cc b/chrome/browser/ash/app_restore/full_restore_service_unittest.cc
index 53d5c43..15b3c26 100644
--- a/chrome/browser/ash/app_restore/full_restore_service_unittest.cc
+++ b/chrome/browser/ash/app_restore/full_restore_service_unittest.cc
@@ -115,8 +115,8 @@
         AccountId::FromUserEmailGaiaId("usertest@gmail.com", "1234567890");
     const auto* user = GetFakeUserManager()->AddUser(account_id_);
     GetFakeUserManager()->LoginUser(account_id_);
-    chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
-        user, profile_.get());
+    ProfileHelper::Get()->SetUserToProfileMappingForTesting(user,
+                                                            profile_.get());
 
     // Reset the restore flag and pref as the default value.
     ::full_restore::FullRestoreInfo::GetInstance()->SetRestoreFlag(account_id_,
@@ -745,8 +745,8 @@
         profile2_->GetProfileUserName(), "111111");
     const auto* user = GetFakeUserManager()->AddUser(account_id2_);
     GetFakeUserManager()->LoginUser(account_id2_);
-    chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
-        user, profile2_.get());
+    ProfileHelper::Get()->SetUserToProfileMappingForTesting(user,
+                                                            profile2_.get());
 
     // Reset the restore flag and pref as the default value.
     ::full_restore::FullRestoreInfo::GetInstance()->SetRestoreFlag(account_id2_,
diff --git a/chrome/browser/ash/arc/arc_support_host.cc b/chrome/browser/ash/arc/arc_support_host.cc
index e34841d3ff..8657023 100644
--- a/chrome/browser/ash/arc/arc_support_host.cc
+++ b/chrome/browser/ash/arc/arc_support_host.cc
@@ -656,7 +656,7 @@
 
   loadtime_data.SetBoolean(kArcManaged, is_arc_managed_);
   loadtime_data.SetBoolean("isOwnerProfile",
-                           chromeos::ProfileHelper::IsOwnerProfile(profile_));
+                           ash::ProfileHelper::IsOwnerProfile(profile_));
 
   const std::string& country_code = base::CountryCodeForCurrentTimezone();
   loadtime_data.SetString("countryCode", country_code);
diff --git a/chrome/browser/ash/arc/arc_util.cc b/chrome/browser/ash/arc/arc_util.cc
index 86d300c..81a2ab3 100644
--- a/chrome/browser/ash/arc/arc_util.cc
+++ b/chrome/browser/ash/arc/arc_util.cc
@@ -172,7 +172,7 @@
     return false;
   }
 
-  if (!chromeos::ProfileHelper::IsPrimaryProfile(profile)) {
+  if (!ash::ProfileHelper::IsPrimaryProfile(profile)) {
     VLOG_IF(1, should_report_reason)
         << "Non-primary users are not supported in ARC.";
     return false;
@@ -190,7 +190,7 @@
   // different application install mechanism. ARC is not allowed otherwise
   // (e.g. in public sessions). cf) crbug.com/605545
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   if (!IsArcAllowedForUser(user)) {
     VLOG_IF(1, should_report_reason) << "ARC is not allowed for the user.";
     return false;
@@ -250,7 +250,7 @@
 
 bool IsRealUserProfile(const Profile* profile) {
   // Return false for signin, lock screen and incognito profiles.
-  return profile && chromeos::ProfileHelper::IsRegularProfile(profile) &&
+  return profile && ash::ProfileHelper::IsRegularProfile(profile) &&
          !profile->IsOffTheRecord();
 }
 
@@ -294,7 +294,7 @@
 
 bool IsArcBlockedDueToIncompatibleFileSystem(const Profile* profile) {
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
 
   // Return true for public accounts as they only have ext4 and
   // for ARC kiosk as migration to ext4 should always be triggered.
@@ -410,7 +410,7 @@
 
 bool IsActiveDirectoryUserForProfile(const Profile* profile) {
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   return user ? user->IsActiveDirectoryUser() : false;
 }
 
diff --git a/chrome/browser/ash/arc/arc_util_unittest.cc b/chrome/browser/ash/arc/arc_util_unittest.cc
index 50476d4..0781a14 100644
--- a/chrome/browser/ash/arc/arc_util_unittest.cc
+++ b/chrome/browser/ash/arc/arc_util_unittest.cc
@@ -288,9 +288,8 @@
       GetFakeUserManager(),
       AccountId::AdFromObjGuid("f04557de-5da2-40ce-ae9d-b8874d8da96e"),
       user_manager::USER_TYPE_ACTIVE_DIRECTORY);
-  EXPECT_FALSE(chromeos::ProfileHelper::Get()
-                   ->GetUserByProfile(profile())
-                   ->HasGaiaAccount());
+  EXPECT_FALSE(
+      ash::ProfileHelper::Get()->GetUserByProfile(profile())->HasGaiaAccount());
   EXPECT_TRUE(IsArcAllowedForProfileOnFirstCall(profile()));
 }
 
@@ -300,9 +299,8 @@
       GetFakeUserManager(),
       AccountId::AdFromObjGuid("f04557de-5da2-40ce-ae9d-b8874d8da96e"),
       user_manager::USER_TYPE_ACTIVE_DIRECTORY);
-  EXPECT_FALSE(chromeos::ProfileHelper::Get()
-                   ->GetUserByProfile(profile())
-                   ->HasGaiaAccount());
+  EXPECT_FALSE(
+      ash::ProfileHelper::Get()->GetUserByProfile(profile())->HasGaiaAccount());
   EXPECT_FALSE(IsArcAllowedForProfileOnFirstCall(profile()));
 }
 
@@ -311,9 +309,8 @@
   ScopedLogIn login(GetFakeUserManager(),
                     AccountId::FromUserEmail(profile()->GetProfileUserName()),
                     user_manager::USER_TYPE_ARC_KIOSK_APP);
-  EXPECT_FALSE(chromeos::ProfileHelper::Get()
-                   ->GetUserByProfile(profile())
-                   ->HasGaiaAccount());
+  EXPECT_FALSE(
+      ash::ProfileHelper::Get()->GetUserByProfile(profile())->HasGaiaAccount());
   EXPECT_FALSE(IsArcAllowedForProfileOnFirstCall(profile()));
 }
 
@@ -323,9 +320,8 @@
   ScopedLogIn login(GetFakeUserManager(),
                     AccountId::FromUserEmail(profile()->GetProfileUserName()),
                     user_manager::USER_TYPE_ARC_KIOSK_APP);
-  EXPECT_FALSE(chromeos::ProfileHelper::Get()
-                   ->GetUserByProfile(profile())
-                   ->HasGaiaAccount());
+  EXPECT_FALSE(
+      ash::ProfileHelper::Get()->GetUserByProfile(profile())->HasGaiaAccount());
   EXPECT_TRUE(IsArcAllowedForProfileOnFirstCall(profile()));
 }
 
@@ -335,9 +331,8 @@
   ScopedLogIn login(GetFakeUserManager(),
                     AccountId::FromUserEmail(profile()->GetProfileUserName()),
                     user_manager::USER_TYPE_ARC_KIOSK_APP);
-  EXPECT_FALSE(chromeos::ProfileHelper::Get()
-                   ->GetUserByProfile(profile())
-                   ->HasGaiaAccount());
+  EXPECT_FALSE(
+      ash::ProfileHelper::Get()->GetUserByProfile(profile())->HasGaiaAccount());
   EXPECT_TRUE(IsArcAllowedForProfileOnFirstCall(profile()));
 }
 
@@ -398,7 +393,7 @@
       profile()->GetProfileUserName(), kTestGaiaId));
   ScopedLogIn login(GetFakeUserManager(), id);
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile());
+      ash::ProfileHelper::Get()->GetUserByProfile(profile());
 
   // Unconfirmed
   EXPECT_FALSE(IsArcCompatibleFileSystemUsedForUser(user));
diff --git a/chrome/browser/ash/arc/auth/arc_auth_service.cc b/chrome/browser/ash/arc/auth/arc_auth_service.cc
index a938ae1..2ad6f88e 100644
--- a/chrome/browser/ash/arc/auth/arc_auth_service.cc
+++ b/chrome/browser/ash/arc/auth/arc_auth_service.cc
@@ -167,7 +167,7 @@
       // IdentityManager::GetPrimaryAccountInfo(
       //    signin::ConsentLevel::kSignin).email might be more appropriate
       // here, but this is what we have done historically.
-      return chromeos::ProfileHelper::Get()
+      return ash::ProfileHelper::Get()
           ->GetUserByProfile(profile)
           ->GetDisplayEmail();
     case mojom::ChromeAccountType::ROBOT_ACCOUNT:
diff --git a/chrome/browser/ash/arc/auth/arc_auth_service_browsertest.cc b/chrome/browser/ash/arc/auth/arc_auth_service_browsertest.cc
index 663576f3..5ce43b9 100644
--- a/chrome/browser/ash/arc/auth/arc_auth_service_browsertest.cc
+++ b/chrome/browser/ash/arc/auth/arc_auth_service_browsertest.cc
@@ -287,7 +287,7 @@
             base::BindRepeating(FakeArcSession::Create)));
     ExpandPropertyFilesForTesting(ArcSessionManager::Get());
 
-    chromeos::ProfileHelper::SetAlwaysReturnPrimaryUserForTesting(true);
+    ash::ProfileHelper::SetAlwaysReturnPrimaryUserForTesting(true);
   }
 
   void TearDownOnMainThread() override {
@@ -316,7 +316,7 @@
     identity_test_environment_adaptor_.reset();
     profile_.reset();
     user_manager_enabler_.reset();
-    chromeos::ProfileHelper::SetAlwaysReturnPrimaryUserForTesting(false);
+    ash::ProfileHelper::SetAlwaysReturnPrimaryUserForTesting(false);
   }
 
   ash::FakeChromeUserManager* GetFakeUserManager() const {
@@ -379,7 +379,7 @@
     identity_test_environment_adaptor_ =
         std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile_.get());
 
-    chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
+    ash::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
         user, profile_.get());
 
     auto* identity_test_env =
diff --git a/chrome/browser/ash/arc/bluetooth/arc_bluetooth_bridge.cc b/chrome/browser/ash/arc/bluetooth/arc_bluetooth_bridge.cc
index 53b4a5b9..24a31a6 100644
--- a/chrome/browser/ash/arc/bluetooth/arc_bluetooth_bridge.cc
+++ b/chrome/browser/ash/arc/bluetooth/arc_bluetooth_bridge.cc
@@ -2910,7 +2910,7 @@
     bool enabled) const {
   const user_manager::User* const user =
       user_manager::UserManager::Get()->GetPrimaryUser();
-  Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+  Profile* profile = ash::ProfileHelper::Get()->GetProfileByUser(user);
   DCHECK(profile);
   profile->GetPrefs()->SetBoolean(ash::prefs::kUserBluetoothAdapterEnabled,
                                   enabled);
diff --git a/chrome/browser/ash/arc/enterprise/cert_store/cert_store_service_browsertest.cc b/chrome/browser/ash/arc/enterprise/cert_store/cert_store_service_browsertest.cc
index 86548b78..f48c75bf 100644
--- a/chrome/browser/ash/arc/enterprise/cert_store/cert_store_service_browsertest.cc
+++ b/chrome/browser/ash/arc/enterprise/cert_store/cert_store_service_browsertest.cc
@@ -533,7 +533,7 @@
 }
 
 Profile* CertStoreServiceTest::profile() {
-  return chromeos::ProfileHelper::Get()->GetProfileByAccountId(
+  return ash::ProfileHelper::Get()->GetProfileByAccountId(
       affiliation_mixin_.account_id());
 }
 
diff --git a/chrome/browser/ash/arc/input_overlay/OWNERS b/chrome/browser/ash/arc/input_overlay/OWNERS
new file mode 100644
index 0000000..79325269
--- /dev/null
+++ b/chrome/browser/ash/arc/input_overlay/OWNERS
@@ -0,0 +1,2 @@
+cuicuiruan@google.com
+djacobo@chromium.org
diff --git a/chrome/browser/ash/arc/input_overlay/actions/action.cc b/chrome/browser/ash/arc/input_overlay/actions/action.cc
index 2ee8f6bf..de20dd7 100644
--- a/chrome/browser/ash/arc/input_overlay/actions/action.cc
+++ b/chrome/browser/ash/arc/input_overlay/actions/action.cc
@@ -4,7 +4,8 @@
 
 #include "chrome/browser/ash/arc/input_overlay/actions/action.h"
 
-#include "chrome/browser/ash/arc/input_overlay/input_overlay_resources_util.h"
+#include "chrome/browser/ash/arc/input_overlay/actions/dependent_position.h"
+#include "chrome/browser/ash/arc/input_overlay/actions/position.h"
 #include "chrome/browser/ash/arc/input_overlay/touch_id_manager.h"
 #include "ui/events/base_event_utils.h"
 #include "ui/events/keycodes/dom/dom_code.h"
@@ -14,11 +15,62 @@
 namespace arc {
 namespace input_overlay {
 namespace {
-// Key strings in Json file.
+// Strings for parsing positions.
 constexpr char kName[] = "name";
 constexpr char kLocation[] = "location";
+constexpr char kType[] = "type";
+constexpr char kPosition[] = "position";
+constexpr char kDependentPosition[] = "dependent_position";
+// Strings for parsing keyboard key.
+constexpr char kKey[] = "key";
+constexpr char kModifiers[] = "modifiers";
+constexpr char kCtrl[] = "ctrl";
+constexpr char kShift[] = "shift";
+constexpr char kAlt[] = "alt";
+
+std::vector<std::unique_ptr<Position>> ParseLocation(
+    const base::Value& position) {
+  std::vector<std::unique_ptr<Position>> positions;
+  for (const base::Value& val : position.GetList()) {
+    auto pos = ParsePosition(val);
+    if (!pos) {
+      LOG(ERROR) << "Failed to parse location.";
+      positions.clear();
+      return positions;
+    }
+    positions.emplace_back(std::move(pos));
+  }
+
+  return positions;
+}
+
 }  // namespace
 
+std::unique_ptr<Position> ParsePosition(const base::Value& value) {
+  auto* type = value.FindStringKey(kType);
+  if (!type) {
+    LOG(ERROR) << "There must be type for each position.";
+    return nullptr;
+  }
+
+  std::unique_ptr<Position> pos;
+  if (*type == kPosition) {
+    pos = std::make_unique<Position>();
+  } else if (*type == kDependentPosition) {
+    pos = std::make_unique<DependentPosition>();
+  } else {
+    LOG(ERROR) << "There is position with unknown type: " << *type;
+    return nullptr;
+  }
+
+  bool succeed = pos->ParseFromJson(value);
+  if (!succeed) {
+    LOG(ERROR) << "Position is parsed incorrectly on type: " << *type;
+    return nullptr;
+  }
+  return pos;
+}
+
 void LogEvent(const ui::Event& event) {
   if (event.IsKeyEvent()) {
     const ui::KeyEvent& key_event = static_cast<const ui::KeyEvent&>(event);
@@ -35,6 +87,9 @@
     VLOG(1) << "Touch event {" << touch_event.ToString()
             << "}. Pointer detail {" << touch_event.pointer_details().ToString()
             << "}, TouchID {" << touch_event.pointer_details().id << "}.";
+  } else if (event.IsMouseEvent()) {
+    auto* mouse_event = event.AsMouseEvent();
+    VLOG(1) << "MouseEvent {" << mouse_event->ToString() << "}.";
   }
   // TODO(cuicuiruan): Add logging other events as needed.
 }
@@ -57,6 +112,39 @@
   return lower;
 }
 
+absl::optional<std::pair<ui::DomCode, int>> ParseKeyboardKey(
+    const base::Value& value,
+    const base::StringPiece key_name) {
+  const std::string* key = value.FindStringKey(kKey);
+  if (!key) {
+    LOG(ERROR) << "No key-value for {" << key_name << "}.";
+    return absl::nullopt;
+  }
+  auto code = ui::KeycodeConverter::CodeStringToDomCode(*key);
+  if (code == ui::DomCode::NONE) {
+    LOG(ERROR)
+        << "Invalid key code string. It should be similar to {KeyA}, but got {"
+        << *key << "}.";
+    return absl::nullopt;
+  }
+  // "modifiers" is optional.
+  auto* modifier_list = value.FindListKey(kModifiers);
+  int modifiers = 0;
+  if (modifier_list) {
+    for (const base::Value& val : modifier_list->GetList()) {
+      if (base::ToLowerASCII(val.GetString()) == kCtrl)
+        modifiers |= ui::EF_CONTROL_DOWN;
+      else if (base::ToLowerASCII(val.GetString()) == kShift)
+        modifiers |= ui::EF_SHIFT_DOWN;
+      else if (base::ToLowerASCII(val.GetString()) == kAlt)
+        modifiers |= ui::EF_ALT_DOWN;
+      else
+        LOG(WARNING) << "Modifier {" << val.GetString() << "} not considered.";
+    }
+  }
+  return absl::make_optional<std::pair<ui::DomCode, int>>(code, modifiers);
+}
+
 Action::Action(aura::Window* window) : target_window_(window) {}
 
 Action::~Action() = default;
@@ -71,8 +159,8 @@
   const base::Value* position = value.FindListKey(kLocation);
   if (position) {
     auto parsed_pos = ParseLocation(*position);
-    if (parsed_pos) {
-      std::move(parsed_pos->begin(), parsed_pos->end(),
+    if (!parsed_pos.empty()) {
+      std::move(parsed_pos.begin(), parsed_pos.end(),
                 std::back_inserter(locations_));
     }
   }
@@ -102,7 +190,7 @@
   return absl::make_optional(root_location);
 }
 
-absl::optional<ui::TouchEvent> Action::GetTouchCancelEvent() {
+absl::optional<ui::TouchEvent> Action::GetTouchCanceledEvent() {
   if (!touch_id_)
     return absl::nullopt;
   auto touch_event = absl::make_optional<ui::TouchEvent>(
@@ -110,9 +198,21 @@
       last_touch_root_location_, ui::EventTimeForNow(),
       ui::PointerDetails(ui::EventPointerType::kTouch, touch_id_.value()));
   ui::Event::DispatcherApi(&*touch_event).set_target(target_window_);
-
+  LogEvent(*touch_event);
   OnTouchCancelled();
+  return touch_event;
+}
 
+absl::optional<ui::TouchEvent> Action::GetTouchReleasedEvent() {
+  if (!touch_id_)
+    return absl::nullopt;
+  auto touch_event = absl::make_optional<ui::TouchEvent>(
+      ui::EventType::ET_TOUCH_RELEASED, last_touch_root_location_,
+      last_touch_root_location_, ui::EventTimeForNow(),
+      ui::PointerDetails(ui::EventPointerType::kTouch, touch_id_.value()));
+  ui::Event::DispatcherApi(&*touch_event).set_target(target_window_);
+  LogEvent(*touch_event);
+  OnTouchReleased();
   return touch_event;
 }
 
diff --git a/chrome/browser/ash/arc/input_overlay/actions/action.h b/chrome/browser/ash/arc/input_overlay/actions/action.h
index d31c609..742fbe5 100644
--- a/chrome/browser/ash/arc/input_overlay/actions/action.h
+++ b/chrome/browser/ash/arc/input_overlay/actions/action.h
@@ -19,6 +19,8 @@
 namespace arc {
 namespace input_overlay {
 
+// Parse position from Json.
+std::unique_ptr<Position> ParsePosition(const base::Value& value);
 // Log events for debugging.
 void LogEvent(const ui::Event& event);
 void LogTouchEvents(const std::list<ui::TouchEvent>& events);
@@ -26,6 +28,14 @@
 // Will replace it with showing the result of dom_key / keyboard key depending
 // on different keyboard layout.
 std::string GetDisplayText(const std::string& dom_code_string);
+// Json format:
+// {
+//    "key": "KeyA",
+//    "modifiers": [""] // optional: "ctrl", "shift", "alt".
+// }
+absl::optional<std::pair<ui::DomCode, int>> ParseKeyboardKey(
+    const base::Value& value,
+    const base::StringPiece key_name);
 
 // This is the base touch action which converts other events to touch
 // events for input overlay.
@@ -44,8 +54,9 @@
   //    No need to rewrite the event, so call SendEvent with original event.
   // |content_bounds| is the window bounds excluding caption.
   virtual bool RewriteEvent(const ui::Event& origin,
-                            std::list<ui::TouchEvent>& touch_events,
-                            const gfx::RectF& content_bounds) = 0;
+                            const gfx::RectF& content_bounds,
+                            const bool is_mouse_locked,
+                            std::list<ui::TouchEvent>& touch_events) = 0;
   // Get the UI location in the content view.
   virtual gfx::PointF GetUIPosition(const gfx::RectF& content_bounds) = 0;
   virtual std::unique_ptr<ActionLabel> CreateView(
@@ -55,13 +66,15 @@
   const std::vector<std::unique_ptr<Position>>& locations() const {
     return locations_;
   }
+  bool require_mouse_locked() const { return require_mouse_locked_; }
   const aura::Window* target_window() const { return target_window_; }
   int current_position_index() const { return current_position_index_; }
   const absl::optional<int> touch_id() const { return touch_id_; }
 
   // Cancel event when the focus is leave or window is destroyed and the touch
   // event is still not released.
-  absl::optional<ui::TouchEvent> GetTouchCancelEvent();
+  absl::optional<ui::TouchEvent> GetTouchCanceledEvent();
+  absl::optional<ui::TouchEvent> GetTouchReleasedEvent();
   // TODO (b/200210666): Can remove this after the bug is fixed.
   bool IsKeyAlreadyPressed(ui::DomCode code) const;
 
@@ -71,14 +84,18 @@
   absl::optional<gfx::PointF> CalculateTouchPosition(
       const gfx::RectF& content_bounds);
   bool IsRepeatedKeyEvent(const ui::KeyEvent& key_event);
-  void OnTouchReleased();
-  void OnTouchCancelled();
+  virtual void OnTouchReleased();
+  virtual void OnTouchCancelled();
 
   // name_ is basically for debugging and not visible to users.
   std::string name_;
   // Location take turns for each key press if there are more than
   // one location.
   std::vector<std::unique_ptr<Position>> locations_;
+  // If |require_mouse_locked_| == true, the action takes effect when the mouse
+  // is locked. Once the mouse is unlocked, the active actions which need mouse
+  // lock will be released.
+  bool require_mouse_locked_ = false;
 
   aura::Window* target_window_;
   absl::optional<int> touch_id_;
diff --git a/chrome/browser/ash/arc/input_overlay/actions/action_move_key.cc b/chrome/browser/ash/arc/input_overlay/actions/action_move_key.cc
index c3bceae..5fa59244 100644
--- a/chrome/browser/ash/arc/input_overlay/actions/action_move_key.cc
+++ b/chrome/browser/ash/arc/input_overlay/actions/action_move_key.cc
@@ -80,8 +80,9 @@
 }
 
 bool ActionMoveKey::RewriteEvent(const ui::Event& origin,
-                                 std::list<ui::TouchEvent>& touch_events,
-                                 const gfx::RectF& content_bounds) {
+                                 const gfx::RectF& content_bounds,
+                                 const bool is_mouse_locked,
+                                 std::list<ui::TouchEvent>& touch_events) {
   if (!origin.IsKeyEvent())
     return false;
   LogEvent(origin);
diff --git a/chrome/browser/ash/arc/input_overlay/actions/action_move_key.h b/chrome/browser/ash/arc/input_overlay/actions/action_move_key.h
index c47da0d..0396e259 100644
--- a/chrome/browser/ash/arc/input_overlay/actions/action_move_key.h
+++ b/chrome/browser/ash/arc/input_overlay/actions/action_move_key.h
@@ -38,8 +38,9 @@
   // }
   bool ParseFromJson(const base::Value& value) override;
   bool RewriteEvent(const ui::Event& origin,
-                    std::list<ui::TouchEvent>& touch_events,
-                    const gfx::RectF& content_bounds) override;
+                    const gfx::RectF& content_bounds,
+                    const bool is_mouse_locked,
+                    std::list<ui::TouchEvent>& touch_events) override;
   gfx::PointF GetUIPosition(const gfx::RectF& content_bounds) override;
   std::unique_ptr<ActionLabel> CreateView(
       const gfx::RectF& content_bounds) override;
diff --git a/chrome/browser/ash/arc/input_overlay/actions/action_move_mouse.cc b/chrome/browser/ash/arc/input_overlay/actions/action_move_mouse.cc
new file mode 100644
index 0000000..3e2f249
--- /dev/null
+++ b/chrome/browser/ash/arc/input_overlay/actions/action_move_mouse.cc
@@ -0,0 +1,229 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ash/arc/input_overlay/actions/action_move_mouse.h"
+
+#include "ash/shell.h"
+#include "chrome/browser/ash/arc/input_overlay/touch_id_manager.h"
+#include "ui/events/keycodes/dom/keycode_converter.h"
+
+namespace arc {
+namespace input_overlay {
+namespace {
+// About Json strings.
+constexpr char kMouseAction[] = "mouse_action";
+constexpr char kHoverMove[] = "hover_move";
+constexpr char kPrimaryDragMove[] = "primary_drag_move";
+constexpr char kSecondaryDragMove[] = "secondary_drag_move";
+constexpr char kTargetArea[] = "target_area";
+constexpr char kTopLeft[] = "top_left";
+constexpr char kBottomRight[] = "bottom_right";
+
+std::unique_ptr<Position> ParseApplyAreaPosition(const base::Value& value,
+                                                 base::StringPiece key) {
+  auto* point = value.FindDictKey(key);
+  if (!point) {
+    LOG(ERROR) << "Apply area in mouse move action requires: " << key;
+    return nullptr;
+  }
+  auto pos = ParsePosition(*point);
+  if (!pos) {
+    LOG(ERROR) << "Not valid position for: " << key;
+    return nullptr;
+  }
+  return pos;
+}
+
+}  // namespace
+
+ActionMoveMouse::ActionMoveMouse(aura::Window* window) : Action(window) {}
+
+ActionMoveMouse::~ActionMoveMouse() = default;
+
+bool ActionMoveMouse::ParseFromJson(const base::Value& value) {
+  Action::ParseFromJson(value);
+
+  const auto* mouse_action = value.FindStringKey(kMouseAction);
+  if (!mouse_action) {
+    LOG(ERROR) << "Must include mouse action for mouse move action.";
+    return false;
+  }
+  require_mouse_locked_ = true;
+  target_mouse_action_ = *mouse_action;
+  if (target_mouse_action_ == kHoverMove) {
+    target_types_.emplace(ui::ET_MOUSE_ENTERED);
+    target_types_.emplace(ui::ET_MOUSE_MOVED);
+    target_types_.emplace(ui::ET_MOUSE_EXITED);
+  } else if (target_mouse_action_ == kPrimaryDragMove ||
+             target_mouse_action_ == kSecondaryDragMove) {
+    target_types_.emplace(ui::ET_MOUSE_PRESSED);
+    target_types_.emplace(ui::ET_MOUSE_DRAGGED);
+    target_types_.emplace(ui::ET_MOUSE_RELEASED);
+    if (target_mouse_action_ == kPrimaryDragMove)
+      target_flags_ = ui::EF_LEFT_MOUSE_BUTTON;
+    else
+      target_flags_ = ui::EF_RIGHT_MOUSE_BUTTON;
+  } else {
+    LOG(ERROR) << "Not supported mouse action: " << target_mouse_action_;
+    return false;
+  }
+
+  auto* target_area = value.FindDictKey(kTargetArea);
+  if (target_area) {
+    auto top_left = ParseApplyAreaPosition(*target_area, kTopLeft);
+    if (!top_left)
+      return false;
+    auto bottom_right = ParseApplyAreaPosition(*target_area, kBottomRight);
+    if (!bottom_right)
+      return false;
+
+    // Verify |top_left| is located on the top-left of the |bottom_right|. Use a
+    // random positive window content bounds to test it.
+    auto temp_rect = gfx::RectF(10, 10, 100, 100);
+    auto top_left_point = top_left->CalculatePosition(temp_rect);
+    auto bottom_right_point = bottom_right->CalculatePosition(temp_rect);
+    if (top_left_point.x() > bottom_right_point.x() - 1 ||
+        top_left_point.y() > bottom_right_point.y() - 1) {
+      LOG(ERROR) << "Apply area in mouse move action is not verified. For "
+                    "window content bounds "
+                 << temp_rect.ToString() << ", get top-left position "
+                 << top_left_point.ToString() << " and bottom-right position "
+                 << bottom_right_point.ToString()
+                 << ". Top-left position should be on the top-left of the "
+                    "bottom-right position.";
+      return false;
+    }
+
+    target_area_.emplace_back(std::move(top_left));
+    target_area_.emplace_back(std::move(bottom_right));
+  }
+
+  return true;
+}
+
+bool ActionMoveMouse::RewriteEvent(const ui::Event& origin,
+                                   const gfx::RectF& content_bounds,
+                                   const bool is_mouse_locked,
+                                   std::list<ui::TouchEvent>& touch_events) {
+  if (!origin.IsMouseEvent() || !is_mouse_locked)
+    return false;
+
+  LogEvent(origin);
+  auto* mouse_event = origin.AsMouseEvent();
+  auto rewritten = RewriteMouseEvent(mouse_event, content_bounds,
+                                     is_mouse_locked, touch_events);
+  LogTouchEvents(touch_events);
+  return rewritten;
+}
+
+gfx::PointF ActionMoveMouse::GetUIPosition(const gfx::RectF& content_bounds) {
+  if (locations().empty())
+    return gfx::PointF(content_bounds.width() / 2, content_bounds.height() / 2);
+  // Sometimes, the touch down position binds to a UI location. The action view
+  // shows on the UI location. If it's null, the touch down position is
+  // anywhere. The action view shows in the center of the window.
+  return locations().front().get()->CalculatePosition(content_bounds);
+}
+
+std::unique_ptr<ActionLabel> ActionMoveMouse::CreateView(
+    const gfx::RectF& content_bounds) {
+  auto view = std::make_unique<ActionLabel>(u"mouse cursor lock (esc)");
+  auto center_pos = GetUIPosition(content_bounds);
+  view->SetPositionFromCenterPosition(center_pos);
+  return view;
+}
+
+bool ActionMoveMouse::RewriteMouseEvent(
+    const ui::MouseEvent* mouse_event,
+    const gfx::RectF& content_bounds,
+    const bool is_mouse_locked,
+    std::list<ui::TouchEvent>& rewritten_events) {
+  DCHECK(mouse_event);
+
+  auto type = mouse_event->type();
+  if (!target_types_.contains(type) || target_flags_ != mouse_event->flags())
+    return false;
+
+  // float scale = target_window_->GetHost()->device_scale_factor();
+  auto mouse_location = gfx::Point(mouse_event->root_location());
+  target_window_->GetHost()->ConvertPixelsToDIP(&mouse_location);
+  auto mouse_location_f = gfx::PointF(mouse_location);
+  // DIscard mouse events outside of the app content bounds if the mouse is
+  // locked.
+  if (!content_bounds.Contains(mouse_location_f))
+    return true;
+
+  last_touch_root_location_ =
+      TransformLocationInPixels(content_bounds, mouse_location_f);
+
+  if (type == ui::ET_MOUSE_ENTERED || type == ui::ET_MOUSE_PRESSED)
+    DCHECK(!touch_id_);
+  // Mouse might be unlocked before ui::ET_MOUSE_EXITED, so no need to check
+  // ui::ET_MOUSE_EXITED.
+  if (type == ui::ET_MOUSE_RELEASED)
+    DCHECK(touch_id_);
+  if (!touch_id_) {
+    touch_id_ = TouchIdManager::GetInstance()->ObtainTouchID();
+    auto touch_down_pos = CalculateTouchPosition(content_bounds);
+    if (touch_down_pos)
+      last_touch_root_location_ = *touch_down_pos;
+    rewritten_events.emplace_back(
+        ui::EventType::ET_TOUCH_PRESSED, last_touch_root_location_,
+        last_touch_root_location_, mouse_event->time_stamp(),
+        ui::PointerDetails(ui::EventPointerType::kTouch, *touch_id_));
+  } else if (type == ui::ET_MOUSE_EXITED || type == ui::ET_MOUSE_RELEASED) {
+    rewritten_events.emplace_back(
+        ui::EventType::ET_TOUCH_RELEASED, last_touch_root_location_,
+        last_touch_root_location_, mouse_event->time_stamp(),
+        ui::PointerDetails(ui::EventPointerType::kTouch, *touch_id_));
+    OnTouchReleased();
+  } else {
+    DCHECK(type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED);
+    rewritten_events.emplace_back(
+        ui::EventType::ET_TOUCH_MOVED, last_touch_root_location_,
+        last_touch_root_location_, mouse_event->time_stamp(),
+        ui::PointerDetails(ui::EventPointerType::kTouch, *touch_id_));
+  }
+  ui::Event::DispatcherApi(&(rewritten_events.back()))
+      .set_target(target_window_);
+  return true;
+}
+
+absl::optional<gfx::RectF> ActionMoveMouse::CalculateApplyArea(
+    const gfx::RectF& content_bounds) {
+  if (target_area_.size() != 2)
+    return absl::nullopt;
+
+  auto top_left = target_area_[0]->CalculatePosition(content_bounds);
+  auto bottom_right = target_area_[1]->CalculatePosition(content_bounds);
+  return absl::make_optional<gfx::RectF>(
+      top_left.x() + content_bounds.x(), top_left.y() + content_bounds.y(),
+      bottom_right.x() - top_left.x(), bottom_right.y() - top_left.y());
+}
+
+gfx::PointF ActionMoveMouse::TransformLocationInPixels(
+    const gfx::RectF& content_bounds,
+    const gfx::PointF& root_location) {
+  auto target_area = CalculateApplyArea(content_bounds);
+  auto new_pos = gfx::PointF();
+  if (target_area) {
+    // auto content_bounds_pixels = gfx::RectF(content_bounds);
+    auto orig_point = root_location - content_bounds.origin();
+    float ratio = orig_point.x() / content_bounds.width();
+    float x = ratio * target_area->width() + target_area->x();
+    ratio = orig_point.y() / content_bounds.height();
+    float y = ratio * target_area->height() + target_area->y();
+    new_pos.SetPoint(x, y);
+    DCHECK(target_area->Contains(new_pos));
+  } else {
+    new_pos.SetPoint(root_location.x(), root_location.y());
+  }
+
+  float scale = target_window_->GetHost()->device_scale_factor();
+  new_pos.Scale(scale);
+  return new_pos;
+}
+
+}  // namespace input_overlay
+}  // namespace arc
diff --git a/chrome/browser/ash/arc/input_overlay/actions/action_move_mouse.h b/chrome/browser/ash/arc/input_overlay/actions/action_move_mouse.h
new file mode 100644
index 0000000..60c413cf
--- /dev/null
+++ b/chrome/browser/ash/arc/input_overlay/actions/action_move_mouse.h
@@ -0,0 +1,98 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ASH_ARC_INPUT_OVERLAY_ACTIONS_ACTION_MOVE_MOUSE_H_
+#define CHROME_BROWSER_ASH_ARC_INPUT_OVERLAY_ACTIONS_ACTION_MOVE_MOUSE_H_
+
+#include "chrome/browser/ash/arc/input_overlay/actions/action.h"
+
+namespace arc {
+namespace input_overlay {
+
+// ActionMoveMouse transforms mouse events to touch event to simulate touch move
+// events when the mouse is locked.
+// It supports below target mouse action.
+// 1. Mouse hover move. It requires mouse lock.
+// 2&3. Mouse left&right drag move.
+// When the mouse is locked, only the targeted mouse events with location inside
+// of window content bounds will be processed. The targeted mouse events outside
+// of the content bounds will be discarded.
+class ActionMoveMouse : public Action {
+ public:
+  explicit ActionMoveMouse(aura::Window* window);
+  ActionMoveMouse(const ActionMoveMouse&) = delete;
+  ActionMoveMouse& operator=(const ActionMoveMouse&) = delete;
+  ~ActionMoveMouse() override;
+
+  const std::string& target_mouse_action() const {
+    return target_mouse_action_;
+  }
+  const base::flat_set<ui::EventType>& target_types() const {
+    return target_types_;
+  }
+  int target_flags() const { return target_flags_; }
+
+  // Action:
+  //
+  // Json value format:
+  // {
+  //   "name": "camera move",
+  //   "mouse_action": "hover_move", // primary_drag_move, secondary_drag_move
+  //   "location": [ // optional
+  //     {
+  //       "type": "position",
+  //       ...
+  //     }
+  //   ],
+  //   "target_area": { // optional
+  //     "top_left": {
+  //         "type": "position",
+  //          ...
+  //       },
+  //     "bottom_right":
+  //       {}
+  //   }
+  // }
+  bool ParseFromJson(const base::Value& value) override;
+  bool RewriteEvent(const ui::Event& origin,
+                    const gfx::RectF& content_bounds,
+                    const bool is_mouse_locked,
+                    std::list<ui::TouchEvent>& touch_events) override;
+  gfx::PointF GetUIPosition(const gfx::RectF& content_bounds) override;
+  std::unique_ptr<ActionLabel> CreateView(
+      const gfx::RectF& content_bounds) override;
+
+ private:
+  bool RewriteMouseEvent(const ui::MouseEvent* mouse_event,
+                         const gfx::RectF& content_bounds,
+                         const bool is_mouse_locked,
+                         std::list<ui::TouchEvent>& rewritten_events);
+  // Return the bounds in the root window.
+  absl::optional<gfx::RectF> CalculateApplyArea(
+      const gfx::RectF& content_bound);
+  // Transform mouse location from app window to the |target_area_| if
+  // |target_area_| exists. Input values are in root window's coordinate system.
+  // Return the point pixel to the host window's.
+  gfx::PointF TransformLocationInPixels(const gfx::RectF& content_bounds,
+                                        const gfx::PointF& point);
+
+  // "hover_move", "left_drag_move" and "right_drag_move".
+  std::string target_mouse_action_;
+  // For mouse hover move: ET_MOUSE_ENTERED, ET_MOUSE_MOVED, ET_MOUSE_EXITED.
+  // For mouse left/right-click move: ET_MOUSE_PRESSED, ET_MOUSE_DRAGGED,
+  // ET_MOUSE_RELEASED.
+  base::flat_set<ui::EventType> target_types_;
+  // Mouse left button flag: EF_LEFT_MOUSE_BUTTON. Right button flag:
+  // EF_RIGHT_MOUSE_BUTTON.
+  int target_flags_ = 0;
+  // Some games defines a specific area with touch move effects, for example,
+  // left half window or right half window. If it is null, the whole window will
+  // be the apply area.
+  std::vector<std::unique_ptr<Position>> target_area_;
+};
+
+}  // namespace input_overlay
+}  // namespace arc
+
+#endif  // CHROME_BROWSER_ASH_ARC_INPUT_OVERLAY_ACTIONS_ACTION_MOVE_MOUSE_H_
diff --git a/chrome/browser/ash/arc/input_overlay/actions/action_tap_key.cc b/chrome/browser/ash/arc/input_overlay/actions/action_tap_key.cc
index 465085a..37c0e514 100644
--- a/chrome/browser/ash/arc/input_overlay/actions/action_tap_key.cc
+++ b/chrome/browser/ash/arc/input_overlay/actions/action_tap_key.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/ash/arc/input_overlay/actions/action_tap_key.h"
 
 #include "chrome/browser/ash/arc/input_overlay/actions/action.h"
-#include "chrome/browser/ash/arc/input_overlay/input_overlay_resources_util.h"
 #include "chrome/browser/ash/arc/input_overlay/touch_id_manager.h"
 #include "ui/events/base_event_utils.h"
 #include "ui/events/keycodes/dom/dom_code.h"
@@ -15,10 +14,6 @@
 
 namespace arc {
 namespace input_overlay {
-namespace {
-// Key strings in Json file.
-constexpr char kKey[] = "key";
-}  // namespace
 
 ActionTapKey::ActionTapKey(aura::Window* window) : Action(window) {}
 
@@ -31,24 +26,19 @@
                << "}.";
     return false;
   }
-  const std::string* key = value.FindStringKey(kKey);
+  auto key = ParseKeyboardKey(value, name_);
   if (!key) {
-    LOG(ERROR) << "Require key code for tap key action {" << name_ << "}.";
+    LOG(ERROR) << "No/invalid key code for key tap action {" << name_ << "}.";
     return false;
   }
-  key_ = ui::KeycodeConverter::CodeStringToDomCode(*key);
-  if (key_ == ui::DomCode::NONE) {
-    LOG(ERROR) << "Tap key code is invalid for tap key action {" << name_
-               << "}. It should be similar to {KeyA}, but got {" << *key
-               << "}.";
-    return false;
-  }
+  key_ = key->first;
   return true;
 }
 
 bool ActionTapKey::RewriteEvent(const ui::Event& origin,
-                                std::list<ui::TouchEvent>& touch_events,
-                                const gfx::RectF& content_bounds) {
+                                const gfx::RectF& content_bounds,
+                                const bool is_mouse_locked,
+                                std::list<ui::TouchEvent>& touch_events) {
   if (!origin.IsKeyEvent())
     return false;
   LogEvent(origin);
diff --git a/chrome/browser/ash/arc/input_overlay/actions/action_tap_key.h b/chrome/browser/ash/arc/input_overlay/actions/action_tap_key.h
index a627bdd3..a59e823 100644
--- a/chrome/browser/ash/arc/input_overlay/actions/action_tap_key.h
+++ b/chrome/browser/ash/arc/input_overlay/actions/action_tap_key.h
@@ -32,8 +32,9 @@
   // }
   bool ParseFromJson(const base::Value& value) override;
   bool RewriteEvent(const ui::Event& origin,
-                    std::list<ui::TouchEvent>& touch_events,
-                    const gfx::RectF& content_bounds) override;
+                    const gfx::RectF& content_bounds,
+                    const bool is_mouse_locked,
+                    std::list<ui::TouchEvent>& touch_events) override;
   gfx::PointF GetUIPosition(const gfx::RectF& content_bounds) override;
   std::unique_ptr<ActionLabel> CreateView(
       const gfx::RectF& content_bounds) override;
diff --git a/chrome/browser/ash/arc/input_overlay/actions/dependent_position.cc b/chrome/browser/ash/arc/input_overlay/actions/dependent_position.cc
index 874d3c9..6cc3dcfc 100644
--- a/chrome/browser/ash/arc/input_overlay/actions/dependent_position.cc
+++ b/chrome/browser/ash/arc/input_overlay/actions/dependent_position.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/ash/arc/input_overlay/actions/dependent_position.h"
 
-#include "chrome/browser/ash/arc/input_overlay/input_overlay_resources_util.h"
+#include "base/logging.h"
 
 namespace arc {
 namespace input_overlay {
diff --git a/chrome/browser/ash/arc/input_overlay/actions/position.cc b/chrome/browser/ash/arc/input_overlay/actions/position.cc
index d1d1716..681a673 100644
--- a/chrome/browser/ash/arc/input_overlay/actions/position.cc
+++ b/chrome/browser/ash/arc/input_overlay/actions/position.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/ash/arc/input_overlay/actions/position.h"
 
-#include "chrome/browser/ash/arc/input_overlay/input_overlay_resources_util.h"
+#include "base/logging.h"
 
 namespace arc {
 namespace input_overlay {
diff --git a/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager.cc b/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager.cc
index b039fec..d8b24302 100644
--- a/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager.cc
+++ b/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager.cc
@@ -107,8 +107,8 @@
     return;
 
   base::Value& root = result.value.value();
-  std::unique_ptr<TouchInjector> injector =
-      std::make_unique<TouchInjector>(top_level_window);
+  std::unique_ptr<input_overlay::TouchInjector> injector =
+      std::make_unique<input_overlay::TouchInjector>(top_level_window);
   injector->ParseActions(root);
   input_overlay_enabled_windows_.emplace(top_level_window, std::move(injector));
 }
@@ -181,7 +181,8 @@
   auto it = input_overlay_enabled_windows_.find(registered_top_level_window_);
   DCHECK(it != input_overlay_enabled_windows_.end());
   display_overlay_controller_ =
-      std::make_unique<DisplayOverlayController>(it->second.get());
+      std::make_unique<input_overlay::DisplayOverlayController>(
+          it->second.get());
 }
 
 void ArcInputOverlayManager::RemoveDisplayOverlayController() {
diff --git a/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager.h b/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager.h
index 4a3d678..8d1957a 100644
--- a/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager.h
+++ b/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager.h
@@ -80,7 +80,7 @@
   base::ScopedObservation<aura::client::FocusClient,
                           aura::client::FocusChangeObserver>
       focus_observation_{this};
-  base::flat_map<aura::Window*, std::unique_ptr<TouchInjector>>
+  base::flat_map<aura::Window*, std::unique_ptr<input_overlay::TouchInjector>>
       input_overlay_enabled_windows_;
   bool is_text_input_active_ = false;
   ui::InputMethod* input_method_ = nullptr;
@@ -89,7 +89,8 @@
   // each time.
   aura::Window* registered_top_level_window_ = nullptr;
   std::unique_ptr<KeyEventSourceRewriter> key_event_source_rewriter_;
-  std::unique_ptr<DisplayOverlayController> display_overlay_controller_;
+  std::unique_ptr<input_overlay::DisplayOverlayController>
+      display_overlay_controller_;
 
   void ReadData(const std::string& package_name,
                 aura::Window* top_level_window);
diff --git a/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager_unittest.cc b/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager_unittest.cc
index 0507d11..41a4471 100644
--- a/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager_unittest.cc
+++ b/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager_unittest.cc
@@ -39,7 +39,7 @@
         .size();
   }
 
-  TouchInjector* GetTouchInjector(aura::Window* window) {
+  input_overlay::TouchInjector* GetTouchInjector(aura::Window* window) {
     auto it =
         arc_test_input_overlay_manager_->input_overlay_enabled_windows_.find(
             window);
@@ -58,7 +58,7 @@
     return arc_test_input_overlay_manager_->key_event_source_rewriter_.get();
   }
 
-  DisplayOverlayController* GetDisplayOverlayController() {
+  input_overlay::DisplayOverlayController* GetDisplayOverlayController() {
     return arc_test_input_overlay_manager_->display_overlay_controller_.get();
   }
 
diff --git a/chrome/browser/ash/arc/input_overlay/display_overlay_controller.cc b/chrome/browser/ash/arc/input_overlay/display_overlay_controller.cc
index dda0ad4..face5a2 100644
--- a/chrome/browser/ash/arc/input_overlay/display_overlay_controller.cc
+++ b/chrome/browser/ash/arc/input_overlay/display_overlay_controller.cc
@@ -9,6 +9,7 @@
 #include "components/exo/shell_surface_util.h"
 
 namespace arc {
+namespace input_overlay {
 
 class DisplayOverlayController::InputMappingView : public views::View {
  public:
@@ -112,4 +113,5 @@
                             : nullptr;
 }
 
+}  // namespace input_overlay
 }  // namespace arc
diff --git a/chrome/browser/ash/arc/input_overlay/display_overlay_controller.h b/chrome/browser/ash/arc/input_overlay/display_overlay_controller.h
index 72ea946..8405b956 100644
--- a/chrome/browser/ash/arc/input_overlay/display_overlay_controller.h
+++ b/chrome/browser/ash/arc/input_overlay/display_overlay_controller.h
@@ -11,6 +11,7 @@
 #include "ui/views/widget/widget_observer.h"
 
 namespace arc {
+namespace input_overlay {
 // DisplayOverlayController manages the input mapping view, view and edit mode,
 // menu, and educational dialog.
 class DisplayOverlayController {
@@ -41,6 +42,7 @@
   InputMappingView* input_mapping_view_ = nullptr;
 };
 
+}  // namespace input_overlay
 }  // namespace arc
 
 #endif  // CHROME_BROWSER_ASH_ARC_INPUT_OVERLAY_DISPLAY_OVERLAY_CONTROLLER_H_
diff --git a/chrome/browser/ash/arc/input_overlay/display_overlay_controller_unittest.cc b/chrome/browser/ash/arc/input_overlay/display_overlay_controller_unittest.cc
index c0dbdd9..020cdaf 100644
--- a/chrome/browser/ash/arc/input_overlay/display_overlay_controller_unittest.cc
+++ b/chrome/browser/ash/arc/input_overlay/display_overlay_controller_unittest.cc
@@ -12,6 +12,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace arc {
+namespace input_overlay {
 namespace {
 
 constexpr const char kValidJson[] =
@@ -79,5 +80,5 @@
   auto updated_bounds = controller_->GetInputMappingViewBoundsForTesting();
   EXPECT_NE(original_bounds, updated_bounds);
 }
-
+}  // namespace input_overlay
 }  // namespace arc
diff --git a/chrome/browser/ash/arc/input_overlay/input_overlay_resources_util.cc b/chrome/browser/ash/arc/input_overlay/input_overlay_resources_util.cc
index b788fa6..e6f00830 100644
--- a/chrome/browser/ash/arc/input_overlay/input_overlay_resources_util.cc
+++ b/chrome/browser/ash/arc/input_overlay/input_overlay_resources_util.cc
@@ -6,26 +6,9 @@
 
 #include <map>
 
-#include "chrome/browser/ash/arc/input_overlay/actions/action_move_key.h"
-#include "chrome/browser/ash/arc/input_overlay/actions/action_tap_key.h"
-#include "chrome/browser/ash/arc/input_overlay/actions/dependent_position.h"
 #include "components/arc/grit/input_overlay_resources.h"
-#include "ui/aura/window.h"
 
 namespace arc {
-namespace {
-
-// Key strings in Json file about action.
-constexpr char kTapAction[] = "tap";
-constexpr char kKeyboard[] = "keyboard";
-constexpr char kMoveAction[] = "move";
-
-// Key strings in Json file about location.
-constexpr char kType[] = "type";
-constexpr char kPosition[] = "position";
-constexpr char kDependentPosition[] = "dependent_position";
-
-}  // namespace
 
 absl::optional<int> GetInputOverlayResourceId(const std::string& package_name) {
   std::map<std::string, int> resource_id_map = {
@@ -40,76 +23,4 @@
                                        : absl::optional<int>();
 }
 
-absl::optional<std::vector<std::unique_ptr<input_overlay::Action>>>
-ParseJsonToActions(aura::Window* window, const base::Value& root) {
-  std::vector<std::unique_ptr<input_overlay::Action>> actions;
-
-  // Parse tap actions if they exist.
-  const base::Value* tap_act_val = root.FindKey(kTapAction);
-  if (tap_act_val) {
-    const base::Value* keyboard_act_list = tap_act_val->FindListKey(kKeyboard);
-    if (keyboard_act_list && keyboard_act_list->is_list()) {
-      for (const base::Value& val : keyboard_act_list->GetList()) {
-        std::unique_ptr<input_overlay::Action> action =
-            std::make_unique<input_overlay::ActionTapKey>(window);
-        bool succeed = action->ParseFromJson(val);
-        if (succeed)
-          actions.emplace_back(std::move(action));
-      }
-    }
-  }
-
-  // Parse move actions if they exist.
-  const base::Value* move_act_val = root.FindKey(kMoveAction);
-  if (move_act_val) {
-    const base::Value* keyboard_act_list = move_act_val->FindListKey(kKeyboard);
-    if (keyboard_act_list && keyboard_act_list->is_list()) {
-      for (const base::Value& val : keyboard_act_list->GetList()) {
-        std::unique_ptr<input_overlay::Action> action =
-            std::make_unique<input_overlay::ActionMoveKey>(window);
-        bool succeed = action->ParseFromJson(val);
-        if (succeed)
-          actions.emplace_back(std::move(action));
-      }
-    }
-  }
-
-  // TODO(cuicuiruan): parse more actions.
-  return !actions.empty() ? absl::make_optional(std::move(actions))
-                          : absl::nullopt;
-}
-
-absl::optional<std::vector<std::unique_ptr<input_overlay::Position>>>
-ParseLocation(const base::Value& position) {
-  std::vector<std::unique_ptr<input_overlay::Position>> positions;
-  for (const base::Value& val : position.GetList()) {
-    auto* type = val.FindStringKey(kType);
-    if (!type) {
-      LOG(ERROR) << "There must be position type for each location.";
-      return absl::nullopt;
-    }
-    size_t size = positions.size();
-    if (*type == kPosition) {
-      positions.emplace_back(std::make_unique<input_overlay::Position>());
-    } else if (*type == kDependentPosition) {
-      positions.emplace_back(
-          std::make_unique<input_overlay::DependentPosition>());
-    }
-
-    if (positions.size() == size) {
-      LOG(ERROR) << "There is position with unknown type: " << *type;
-      return absl::nullopt;
-    }
-
-    bool succeed = positions.back()->ParseFromJson(val);
-    if (!succeed) {
-      LOG(ERROR) << "Position is parsed incorrectly on type: " << *type;
-      return absl::nullopt;
-    }
-  }
-
-  return !positions.empty() ? absl::make_optional(std::move(positions))
-                            : absl::nullopt;
-}
-
 }  // namespace arc
diff --git a/chrome/browser/ash/arc/input_overlay/input_overlay_resources_util.h b/chrome/browser/ash/arc/input_overlay/input_overlay_resources_util.h
index 30080a21..7eef603 100644
--- a/chrome/browser/ash/arc/input_overlay/input_overlay_resources_util.h
+++ b/chrome/browser/ash/arc/input_overlay/input_overlay_resources_util.h
@@ -5,35 +5,16 @@
 #ifndef CHROME_BROWSER_ASH_ARC_INPUT_OVERLAY_INPUT_OVERLAY_RESOURCES_UTIL_H_
 #define CHROME_BROWSER_ASH_ARC_INPUT_OVERLAY_INPUT_OVERLAY_RESOURCES_UTIL_H_
 
-#include <memory>
 #include <string>
-#include <vector>
 
-#include "base/strings/string_util.h"
-#include "base/values.h"
-#include "chrome/browser/ash/arc/input_overlay/actions/action.h"
-#include "chrome/browser/ash/arc/input_overlay/actions/position.h"
-#include "chrome/browser/ash/arc/input_overlay/touch_injector.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
-namespace aura {
-class Window;
-}  // namespace aura
-
 namespace arc {
 
 // Get the resource ID of the input overlay JSON file by the associated package
 // name.
 absl::optional<int> GetInputOverlayResourceId(const std::string& package_name);
 
-// Parse Json to different types of actions.
-absl::optional<std::vector<std::unique_ptr<input_overlay::Action>>>
-ParseJsonToActions(aura::Window* window, const base::Value& root);
-
-// Parse Json to different types of positions.
-absl::optional<std::vector<std::unique_ptr<input_overlay::Position>>>
-ParseLocation(const base::Value& position);
-
 }  // namespace arc
 
 #endif  // CHROME_BROWSER_ASH_ARC_INPUT_OVERLAY_INPUT_OVERLAY_RESOURCES_UTIL_H_
diff --git a/chrome/browser/ash/arc/input_overlay/input_overlay_resources_util_unittest.cc b/chrome/browser/ash/arc/input_overlay/input_overlay_resources_util_unittest.cc
deleted file mode 100644
index cfadb05..0000000
--- a/chrome/browser/ash/arc/input_overlay/input_overlay_resources_util_unittest.cc
+++ /dev/null
@@ -1,197 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ash/arc/input_overlay/input_overlay_resources_util.h"
-#include "base/json/json_reader.h"
-#include "chrome/browser/ash/arc/input_overlay/actions/action_tap_key.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/aura/test/test_window_delegate.h"
-#include "ui/aura/test/test_windows.h"
-#include "ui/events/keycodes/dom/dom_code.h"
-
-namespace arc {
-
-class InputOverlayResourcesUtilTest : public testing::Test {
- protected:
-  InputOverlayResourcesUtilTest() = default;
-};
-
-constexpr const char kValidJson[] =
-    R"json({
-      "tap": {
-        "keyboard": [
-          {
-            "name": "Fight",
-            "key": "KeyA",
-            "location": [
-              {
-                "type": "position",
-                "anchor": [
-                  0,
-                  0
-                ],
-                "anchor_to_target": [
-                  0.3,
-                  0.5
-                ]
-              },
-              {
-                "type": "position",
-                "anchor": [
-                  0,
-                  0
-                ],
-                "anchor_to_target": [
-                  0.5,
-                  0.5
-                ]
-              }
-            ]
-          },
-          {
-            "name": "Run",
-            "key": "KeyB",
-            "location": [
-              {
-                "type": "position",
-                "anchor_to_target": [
-                  0.8,
-                  0.8
-                ]
-              }
-            ]
-          }
-        ]
-      }
-    })json";
-
-constexpr const char kHalfValidJson[] =
-    R"json({
-      "tap": {
-        "keyboard": [
-          {
-            "name": "Fight",
-            "key": "KeyA",
-            "location": [
-              {
-                "type": "position",
-                "anchor": [
-                  0,
-                  0
-                ],
-                "anchor_to_target": [
-                  0.5,
-                  0.5
-                ]
-              }
-            ]
-          },
-          {
-            "name": "Run",
-            "key": "Key_B",
-            "location": [
-              {
-                "type": "position",
-                "anchor_to_target": [
-                  0.8,
-                  0.8
-                ]
-              }
-            ]
-          }
-        ]
-      }
-    })json";
-
-constexpr const char kLocationValidJson[] =
-    R"json([
-        {
-          "type": "dependent_position",
-          "anchor_to_target": [
-            0.5,
-            0.5
-          ],
-          "x_on_y": 1.8
-        },
-        {
-          "type": "position",
-          "anchor": [
-            0,
-            1
-          ],
-          "anchor_to_target": [
-            0.5,
-            -0.5
-          ]
-        }
-      ]
-    )json";
-
-constexpr const char kEmptyJson[] =
-    R"json({
-    })json";
-
-constexpr const char kEmptyJsonList[] =
-    R"json([
-    ])json";
-
-TEST(InputOverlayResourcesUtilTest, TestParseLocation) {
-  // Check whether Position is parsed correctly.
-  base::JSONReader::ValueWithError json_value =
-      base::JSONReader::ReadAndReturnValueWithError(kLocationValidJson);
-  EXPECT_FALSE(!json_value.value || !json_value.value->is_list());
-  auto result = ParseLocation(json_value.value.value());
-  EXPECT_TRUE(result && result->size() == 2);
-  auto* position = (*result)[0].get();
-  EXPECT_EQ(position->anchor(), gfx::PointF(0, 0));
-  position = (*result)[1].get();
-  EXPECT_EQ(position->anchor(), gfx::PointF(0, 1));
-
-  // Parse empty json.
-  json_value = base::JSONReader::ReadAndReturnValueWithError(kEmptyJsonList);
-  EXPECT_FALSE(!json_value.value || !json_value.value->is_list());
-  result = ParseLocation(json_value.value.value());
-  EXPECT_FALSE(result);
-}
-
-TEST(InputOverlayResourcesUtilTest, TestParseJsonToActions) {
-  // Check whether ActionTapKey is parsed correctly.
-  base::JSONReader::ValueWithError json_value =
-      base::JSONReader::ReadAndReturnValueWithError(kValidJson);
-  EXPECT_FALSE(!json_value.value || !json_value.value->is_dict());
-  aura::test::TestWindowDelegate dummy_delegate;
-  auto window = base::WrapUnique(aura::test::CreateTestWindowWithDelegate(
-      &dummy_delegate, 11, gfx::Rect(200, 400), nullptr));
-  auto result = ParseJsonToActions(window.get(), json_value.value.value());
-  EXPECT_TRUE(result && result->size() == 2);
-  auto* action = (input_overlay::ActionTapKey*)result->at(0).get();
-  EXPECT_EQ(ui::DomCode::US_A, action->key());
-  EXPECT_TRUE(result->at(0)->locations().size() == 2);
-  auto* pos = result->at(0)->locations().at(0).get();
-  EXPECT_TRUE(std::abs(0 - pos->anchor().x()) < 0.000001);
-  EXPECT_TRUE(std::abs(0 - pos->anchor().y()) < 0.000001);
-  EXPECT_TRUE(std::abs(0.3 - pos->anchor_to_target().x()) < 0.0000001);
-  EXPECT_TRUE(std::abs(0.5 - pos->anchor_to_target().y()) < 0.0000001);
-  pos = result->at(0)->locations().at(1).get();
-  EXPECT_TRUE(std::abs(0 - pos->anchor().x()) < 0.000001);
-  EXPECT_TRUE(std::abs(0 - pos->anchor().y()) < 0.000001);
-  EXPECT_TRUE(std::abs(0.5 - pos->anchor_to_target().x()) < 0.0000001);
-  EXPECT_TRUE(std::abs(0.5 - pos->anchor_to_target().y()) < 0.0000001);
-  action = (input_overlay::ActionTapKey*)result->at(1).get();
-  EXPECT_EQ(ui::DomCode::US_B, action->key());
-
-  // Parse half valid Json, so only one action is parsed correctly.
-  json_value = base::JSONReader::ReadAndReturnValueWithError(kHalfValidJson);
-  EXPECT_FALSE(!json_value.value || !json_value.value->is_dict());
-  result = ParseJsonToActions(window.get(), json_value.value.value());
-  EXPECT_TRUE(result && result->size() == 1);
-
-  // Parse empty Json, it should receive empty result.
-  json_value = base::JSONReader::ReadAndReturnValueWithError(kEmptyJson);
-  EXPECT_FALSE(!json_value.value || !json_value.value->is_dict());
-  result = ParseJsonToActions(window.get(), json_value.value.value());
-  EXPECT_FALSE(result);
-}
-
-}  // namespace arc
diff --git a/chrome/browser/ash/arc/input_overlay/test/event_capturer.cc b/chrome/browser/ash/arc/input_overlay/test/event_capturer.cc
index d8e01f5..2be4d7e 100644
--- a/chrome/browser/ash/arc/input_overlay/test/event_capturer.cc
+++ b/chrome/browser/ash/arc/input_overlay/test/event_capturer.cc
@@ -13,6 +13,7 @@
 void EventCapturer::Clear() {
   key_events_.clear();
   touch_events_.clear();
+  mouse_events_.clear();
 }
 
 void EventCapturer::OnKeyEvent(ui::KeyEvent* event) {
@@ -22,6 +23,11 @@
 void EventCapturer::OnTouchEvent(ui::TouchEvent* event) {
   touch_events_.emplace_back(std::make_unique<ui::TouchEvent>(*event));
 }
+
+void EventCapturer::OnMouseEvent(ui::MouseEvent* event) {
+  mouse_events_.emplace_back(std::make_unique<ui::MouseEvent>(*event));
+}
+
 }  // namespace test
 }  // namespace input_overlay
 }  // namespace arc
diff --git a/chrome/browser/ash/arc/input_overlay/test/event_capturer.h b/chrome/browser/ash/arc/input_overlay/test/event_capturer.h
index ebfa6cd..e3b5405 100644
--- a/chrome/browser/ash/arc/input_overlay/test/event_capturer.h
+++ b/chrome/browser/ash/arc/input_overlay/test/event_capturer.h
@@ -28,14 +28,19 @@
   std::vector<std::unique_ptr<ui::TouchEvent>>& touch_events() {
     return touch_events_;
   }
+  std::vector<std::unique_ptr<ui::MouseEvent>>& mouse_events() {
+    return mouse_events_;
+  }
 
  private:
   // EventHandler overrides:
   void OnKeyEvent(ui::KeyEvent* event) override;
   void OnTouchEvent(ui::TouchEvent* event) override;
+  void OnMouseEvent(ui::MouseEvent* event) override;
 
   std::vector<std::unique_ptr<ui::KeyEvent>> key_events_;
   std::vector<std::unique_ptr<ui::TouchEvent>> touch_events_;
+  std::vector<std::unique_ptr<ui::MouseEvent>> mouse_events_;
 };
 }  // namespace test
 }  // namespace input_overlay
diff --git a/chrome/browser/ash/arc/input_overlay/touch_injector.cc b/chrome/browser/ash/arc/input_overlay/touch_injector.cc
index 690b471..a4445e2d 100644
--- a/chrome/browser/ash/arc/input_overlay/touch_injector.cc
+++ b/chrome/browser/ash/arc/input_overlay/touch_injector.cc
@@ -8,16 +8,80 @@
 
 #include "base/bind.h"
 #include "base/task/thread_pool.h"
-#include "chrome/browser/ash/arc/input_overlay/input_overlay_resources_util.h"
+#include "chrome/browser/ash/arc/input_overlay/actions/action_move_key.h"
+#include "chrome/browser/ash/arc/input_overlay/actions/action_move_mouse.h"
+#include "chrome/browser/ash/arc/input_overlay/actions/action_tap_key.h"
 #include "ui/aura/window.h"
+#include "ui/events/event_constants.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/window/non_client_view.h"
 
 namespace arc {
+namespace input_overlay {
+namespace {
+// Strings for parsing actions.
+constexpr char kTapAction[] = "tap";
+constexpr char kKeyboard[] = "keyboard";
+constexpr char kMoveAction[] = "move";
+constexpr char kMouse[] = "mouse";
+constexpr char kMouseLock[] = "mouse_lock";
+// Mask for interesting modifiers.
+const int kInterestingFlagsMask =
+    ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN;
+
+// Parse Json to different types of actions.
+std::vector<std::unique_ptr<Action>> ParseJsonToActions(
+    aura::Window* window,
+    const base::Value& root) {
+  std::vector<std::unique_ptr<Action>> actions;
+
+  // Parse tap actions if they exist.
+  const base::Value* tap_act_val = root.FindKey(kTapAction);
+  if (tap_act_val) {
+    const base::Value* keyboard_act_list = tap_act_val->FindListKey(kKeyboard);
+    if (keyboard_act_list && keyboard_act_list->is_list()) {
+      for (const base::Value& val : keyboard_act_list->GetList()) {
+        std::unique_ptr<Action> action = std::make_unique<ActionTapKey>(window);
+        bool succeed = action->ParseFromJson(val);
+        if (succeed)
+          actions.emplace_back(std::move(action));
+      }
+    }
+  }
+
+  // Parse move actions if they exist.
+  const base::Value* move_act_val = root.FindKey(kMoveAction);
+  if (move_act_val) {
+    const base::Value* keyboard_act_list = move_act_val->FindListKey(kKeyboard);
+    if (keyboard_act_list && keyboard_act_list->is_list()) {
+      for (const base::Value& val : keyboard_act_list->GetList()) {
+        std::unique_ptr<Action> action =
+            std::make_unique<ActionMoveKey>(window);
+        bool succeed = action->ParseFromJson(val);
+        if (succeed)
+          actions.emplace_back(std::move(action));
+      }
+    }
+    const auto* mouse_act_list = move_act_val->FindListKey(kMouse);
+    if (mouse_act_list && mouse_act_list->is_list()) {
+      for (const auto& val : mouse_act_list->GetList()) {
+        auto action = std::make_unique<ActionMoveMouse>(window);
+        bool succeed = action->ParseFromJson(val);
+        if (succeed)
+          actions.emplace_back(std::move(action));
+      }
+    }
+  }
+
+  // TODO(cuicuiruan): parse more actions.
+  return actions;
+}
+}  // namespace
+
 // Calculate the window content bounds (excluding caption if it exists) in the
 // root window.
-gfx::RectF input_overlay::CalculateWindowContentBounds(aura::Window* window) {
+gfx::RectF CalculateWindowContentBounds(aura::Window* window) {
   DCHECK(window);
   auto* widget = views::Widget::GetWidgetForNativeView(window);
   DCHECK(widget->non_client_view());
@@ -29,6 +93,33 @@
   return bounds;
 }
 
+class TouchInjector::MouseLock {
+ public:
+  MouseLock(TouchInjector* owner, ui::DomCode key, int modifiers)
+      : owner_(owner),
+        key_(key),
+        modifiers_(modifiers & kInterestingFlagsMask) {}
+  ~MouseLock() = default;
+  bool Process(const ui::Event& event) {
+    if (!event.IsKeyEvent())
+      return false;
+    auto* key_event = event.AsKeyEvent();
+    if (key_ == key_event->code() &&
+        modifiers_ == (key_event->flags() & kInterestingFlagsMask)) {
+      if (key_event->type() == ui::ET_KEY_PRESSED) {
+        owner_->FlipMouseLockFlag();
+      }
+      return true;
+    }
+    return false;
+  }
+
+ private:
+  TouchInjector* const owner_;
+  ui::DomCode key_;
+  int modifiers_;
+};
+
 TouchInjector::TouchInjector(aura::Window* top_level_window)
     : target_window_(top_level_window) {}
 
@@ -37,11 +128,12 @@
 }
 
 void TouchInjector::ParseActions(const base::Value& root) {
+  ParseMouseLock(root);
   auto parsed_actions = ParseJsonToActions(target_window_, root);
-  if (!parsed_actions)
-    return;
-  std::move(parsed_actions->begin(), parsed_actions->end(),
-            std::back_inserter(actions_));
+  if (!parsed_actions.empty()) {
+    std::move(parsed_actions.begin(), parsed_actions.end(),
+              std::back_inserter(actions_));
+  }
 }
 
 void TouchInjector::NotifyTextInputState(bool active) {
@@ -65,7 +157,7 @@
 
 void TouchInjector::DispatchTouchCancelEvent() {
   for (auto& action : actions_) {
-    auto cancel = action->GetTouchCancelEvent();
+    auto cancel = action->GetTouchCanceledEvent();
     if (!cancel)
       continue;
     if (SendEventFinally(continuation_, &*cancel).dispatcher_destroyed) {
@@ -75,6 +167,21 @@
   }
 }
 
+void TouchInjector::DispatchTouchReleaseEventOnMouseUnLock() {
+  for (auto& action : actions_) {
+    if (action->require_mouse_locked()) {
+      auto release = action->GetTouchReleasedEvent();
+      if (!release)
+        continue;
+      if (SendEventFinally(continuation_, &*release).dispatcher_destroyed) {
+        VLOG(0)
+            << "Undispatched event due to destroyed dispatcher for releasing "
+               "touch event when unlocking mouse.";
+      }
+    }
+  }
+}
+
 void TouchInjector::SendTouchMoveEvent(
     const ui::EventRewriter::Continuation continuation,
     const ui::TouchEvent& event) {
@@ -84,6 +191,20 @@
   }
 }
 
+void TouchInjector::ParseMouseLock(const base::Value& value) {
+  auto* mouse_lock = value.FindKey(kMouseLock);
+  if (!mouse_lock)
+    return;
+  auto key = ParseKeyboardKey(*mouse_lock, kMouseLock);
+  if (!key)
+    return;
+  mouse_lock_ = std::make_unique<MouseLock>(this, key->first, key->second);
+}
+
+void TouchInjector::FlipMouseLockFlag() {
+  is_mouse_locked_ = !is_mouse_locked_;
+}
+
 ui::EventDispatchDetails TouchInjector::RewriteEvent(
     const ui::Event& event,
     const ui::EventRewriter::Continuation continuation) {
@@ -91,11 +212,17 @@
   if (text_input_active_)
     return SendEvent(continuation, &event);
 
-  auto bounds = input_overlay::CalculateWindowContentBounds(target_window_);
+  if (mouse_lock_ && mouse_lock_->Process(event)) {
+    if (!is_mouse_locked_)
+      DispatchTouchReleaseEventOnMouseUnLock();
+    return DiscardEvent(continuation);
+  }
 
+  auto bounds = CalculateWindowContentBounds(target_window_);
   std::list<ui::TouchEvent> touch_events;
   for (auto& action : actions_) {
-    bool rewritten = action->RewriteEvent(event, touch_events, bounds);
+    bool rewritten =
+        action->RewriteEvent(event, bounds, is_mouse_locked_, touch_events);
     if (!rewritten)
       continue;
     if (touch_events.empty())
@@ -111,11 +238,17 @@
           base::BindOnce(&TouchInjector::SendTouchMoveEvent,
                          weak_ptr_factory_.GetWeakPtr(), continuation,
                          touch_events.back()),
-          input_overlay::kSendTouchMoveDelay);
+          kSendTouchMoveDelay);
       return SendEventFinally(continuation, &touch_events.front());
     }
   }
+
+  // Discard other mouse events if the mouse is locked.
+  if (is_mouse_locked_ && event.IsMouseEvent())
+    return DiscardEvent(continuation);
+
   return SendEvent(continuation, &event);
 }
 
+}  // namespace input_overlay
 }  // namespace arc
diff --git a/chrome/browser/ash/arc/input_overlay/touch_injector.h b/chrome/browser/ash/arc/input_overlay/touch_injector.h
index 60747f3..b2aaf637 100644
--- a/chrome/browser/ash/arc/input_overlay/touch_injector.h
+++ b/chrome/browser/ash/arc/input_overlay/touch_injector.h
@@ -26,8 +26,6 @@
 
 gfx::RectF CalculateWindowContentBounds(aura::Window* window);
 
-}  // namespace input_overlay
-
 // TouchInjector includes all the touch actions related to the specific window
 // and performs as a bridge between the ArcInputOverlayManager and the touch
 // actions. It implements EventRewriter to transform input events to touch
@@ -43,6 +41,9 @@
   const std::vector<std::unique_ptr<input_overlay::Action>>& actions() const {
     return actions_;
   }
+  bool is_mouse_locked() const { return is_mouse_locked_; }
+
+  void FlipMouseLockFlag();
 
   // Parse Json to actions.
   // Json value format:
@@ -71,12 +72,20 @@
       const Continuation continuation) override;
 
  private:
+  class MouseLock;
+
   // If the window is destroying or focusing out, releasing the active touch
   // event.
   void DispatchTouchCancelEvent();
-
-  void SendTouchMoveEvent(const ui::EventRewriter::Continuation,
+  void SendTouchMoveEvent(const ui::EventRewriter::Continuation continuation,
                           const ui::TouchEvent& event);
+  void DispatchTouchReleaseEventOnMouseUnLock();
+  // Json format:
+  // "mouse_lock": {
+  //   "key": "KeyA",
+  //   "modifier": [""]
+  // }
+  void ParseMouseLock(const base::Value& value);
 
   aura::Window* target_window_;
   base::WeakPtr<ui::EventRewriterContinuation> continuation_;
@@ -86,11 +95,15 @@
                           &ui::EventSource::AddEventRewriter,
                           &ui::EventSource::RemoveEventRewriter>
       observation_{this};
+  std::unique_ptr<MouseLock> mouse_lock_;
   bool text_input_active_ = false;
+  // The mouse is unlocked by default.
+  bool is_mouse_locked_ = false;
 
   base::WeakPtrFactory<TouchInjector> weak_ptr_factory_{this};
 };
 
+}  // namespace input_overlay
 }  // namespace arc
 
 #endif  // CHROME_BROWSER_ASH_ARC_INPUT_OVERLAY_TOUCH_INJECTOR_H_
diff --git a/chrome/browser/ash/arc/input_overlay/touch_injector_unittest.cc b/chrome/browser/ash/arc/input_overlay/touch_injector_unittest.cc
index fdb1315e..a5db293e 100644
--- a/chrome/browser/ash/arc/input_overlay/touch_injector_unittest.cc
+++ b/chrome/browser/ash/arc/input_overlay/touch_injector_unittest.cc
@@ -7,8 +7,7 @@
 #include "ash/constants/app_types.h"
 #include "ash/public/cpp/window_properties.h"
 #include "base/json/json_reader.h"
-#include "chrome/browser/ash/arc/input_overlay/actions/action_tap_key.h"
-#include "chrome/browser/ash/arc/input_overlay/input_overlay_resources_util.h"
+#include "chrome/browser/ash/arc/input_overlay/actions/action_move_mouse.h"
 #include "chrome/browser/ash/arc/input_overlay/test/event_capturer.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/aura/client/aura_constants.h"
@@ -23,9 +22,10 @@
 #include "ui/views/widget/widget_delegate.h"
 
 namespace arc {
+namespace input_overlay {
 namespace {
 
-constexpr float kScaleFactor = 1.5f;
+// TODO(cuicuiruan): Create test for other device scale.
 
 constexpr const char kValidJsonActionTapKey[] =
     R"json({
@@ -106,6 +106,41 @@
         ]
       }
     })json";
+
+constexpr const char kValidJsonActionMoveMouse[] =
+    R"json({
+      "mouse_lock": {
+        "key": "KeyA"
+      },
+      "move": {
+        "mouse": [
+          {
+            "name": "camera move",
+            "mouse_action": "hover_move",
+            "target_area": {
+              "top_left": {
+                "type": "position",
+                "anchor_to_target": [
+                  0.5,
+                  0
+                ]
+              },
+              "bottom_right": {
+                "type": "position",
+                "anchor_to_target": [
+                  0.9999,
+                  0.9999
+                ]
+              }
+            }
+          },
+          {
+            "name": "test name",
+            "mouse_action": "secondary_drag_move"
+          }
+        ]
+      }
+    })json";
 }  // namespace
 
 class TouchInjectorTest : public views::ViewsTestBase {
@@ -114,16 +149,6 @@
       : views::ViewsTestBase(
             base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
 
-  std::unique_ptr<input_overlay::ActionTapKey> CreateActionTapKey(
-      base::StringPiece json,
-      aura::Window* window) {
-    base::JSONReader::ValueWithError json_value =
-        base::JSONReader::ReadAndReturnValueWithError(json);
-    auto action = std::make_unique<input_overlay::ActionTapKey>(window);
-    action->ParseFromJson(json_value.value.value());
-    return action;
-  }
-
   std::unique_ptr<views::Widget> CreateArcWindow() {
     views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
     params.bounds = gfx::Rect(200, 100, 200, 400);
@@ -144,8 +169,8 @@
   }
 
   bool IsPointsEqual(gfx::PointF& point_a, const gfx::PointF& point_b) {
-    if (std::abs(point_a.x() - point_b.x()) < 0.0001 &&
-        std::abs(point_a.y() - point_b.y()) < 0.0001) {
+    if (std::abs(point_a.x() - point_b.x()) < 1 &&
+        std::abs(point_a.y() - point_b.y()) < 1) {
       return true;
     }
     return false;
@@ -170,7 +195,6 @@
     event_generator_ =
         std::make_unique<ui::test::EventGenerator>(root_window());
 
-    test_screen()->SetDeviceScaleFactor(kScaleFactor);
     root_window()->SetBounds(gfx::Rect(800, 600));
     root_window()->AddPostTargetHandler(&event_capturer_);
 
@@ -350,8 +374,7 @@
   base::JSONReader::ValueWithError json_value =
       base::JSONReader::ReadAndReturnValueWithError(kValidJsonActionMoveKey);
   injector_->ParseActions(json_value.value.value());
-
-  EXPECT_TRUE(injector_->actions().size() == 1);
+  EXPECT_EQ(1, injector_->actions().size());
   auto* action = injector_->actions()[0].get();
   injector_->RegisterEventRewriter();
 
@@ -439,4 +462,85 @@
   event_generator_->ReleaseKey(ui::VKEY_A, ui::EF_NONE, 1);
   event_capturer_.Clear();
 }
+
+TEST_F(TouchInjectorTest, TestEventRewriterActionMoveMouse) {
+  base::JSONReader::ValueWithError json_value =
+      base::JSONReader::ReadAndReturnValueWithError(kValidJsonActionMoveMouse);
+  EXPECT_FALSE(!json_value.value || !json_value.value->is_dict());
+  injector_->ParseActions(json_value.value.value());
+  EXPECT_EQ(2, injector_->actions().size());
+  injector_->RegisterEventRewriter();
+  auto* hover_action = static_cast<input_overlay::ActionMoveMouse*>(
+      injector_->actions()[0].get());
+  EXPECT_EQ(hover_action->target_mouse_action(), "hover_move");
+  EXPECT_TRUE(hover_action->target_types().contains(ui::ET_MOUSE_ENTERED));
+  EXPECT_TRUE(hover_action->target_types().contains(ui::ET_MOUSE_MOVED));
+  EXPECT_TRUE(hover_action->target_types().contains(ui::ET_MOUSE_EXITED));
+  EXPECT_EQ(0, hover_action->target_flags());
+
+  auto* right_action = static_cast<input_overlay::ActionMoveMouse*>(
+      injector_->actions()[1].get());
+  EXPECT_EQ(right_action->target_mouse_action(), "secondary_drag_move");
+  EXPECT_TRUE(right_action->target_types().contains(ui::ET_MOUSE_PRESSED));
+  EXPECT_TRUE(right_action->target_types().contains(ui::ET_MOUSE_DRAGGED));
+  EXPECT_TRUE(right_action->target_types().contains(ui::ET_MOUSE_RELEASED));
+  EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, right_action->target_flags());
+
+  // When the mouse is unlocked and test target action mouse hover move. Mouse
+  // events are received as mouse events.
+  event_generator_->SendMouseEnter();
+  EXPECT_FALSE(hover_action->touch_id());
+  EXPECT_EQ(1, event_capturer_.mouse_events().size());
+  event_generator_->MoveMouseTo(gfx::Point(250, 150));
+  EXPECT_EQ(3, event_capturer_.mouse_events().size());
+  event_capturer_.Clear();
+
+  // Lock mouse.
+  EXPECT_FALSE(injector_->is_mouse_locked());
+  event_generator_->PressAndReleaseKey(ui::VKEY_A, ui::EF_NONE,
+                                       1 /* keyboard id */);
+  EXPECT_TRUE(event_capturer_.key_events().empty());
+  EXPECT_TRUE(injector_->is_mouse_locked());
+  // Mouse hover events are transformed to touch events.
+  event_generator_->MoveMouseTo(gfx::Point(300, 200), 1);
+  EXPECT_TRUE(hover_action->touch_id() && *(hover_action->touch_id()) == 0);
+  EXPECT_TRUE(event_capturer_.mouse_events().empty());
+  EXPECT_EQ(1, event_capturer_.touch_events().size());
+  auto* event = event_capturer_.touch_events()[0].get();
+  EXPECT_EQ(ui::EventType::ET_TOUCH_PRESSED, event->type());
+  auto expect = gfx::PointF(350, 200);
+  EXPECT_TRUE(IsPointsEqual(expect, event->root_location_f()));
+  event_generator_->MoveMouseTo(gfx::Point(350, 250), 1);
+  EXPECT_EQ(2, event_capturer_.touch_events().size());
+  event = event_capturer_.touch_events()[1].get();
+  EXPECT_EQ(ui::EventType::ET_TOUCH_MOVED, event->type());
+  expect = gfx::PointF(375, 250);
+  EXPECT_TRUE(IsPointsEqual(expect, event->root_location_f()));
+  // Send mouse hover move outside of window content bounds when mouse is
+  // locked. The mouse event will be discarded.
+  event_generator_->MoveMouseTo(gfx::Point(500, 200), 1);
+  EXPECT_EQ(2, event_capturer_.touch_events().size());
+  EXPECT_TRUE(event_capturer_.mouse_events().empty());
+  // Send other mouse events when the mouse is locked and events will be
+  // discarded.
+  event_generator_->PressLeftButton();
+  event_generator_->ReleaseLeftButton();
+  EXPECT_TRUE(event_capturer_.mouse_events().empty());
+  EXPECT_EQ(2, event_capturer_.touch_events().size());
+
+  // Unlock the mouse and the mouse events received
+  // as mouse events.
+  event_generator_->PressAndReleaseKey(ui::VKEY_A, ui::EF_NONE,
+                                       1 /* keyboard id */);
+  EXPECT_TRUE(event_capturer_.key_events().empty());
+  EXPECT_EQ(3, event_capturer_.touch_events().size());
+  event = event_capturer_.touch_events()[2].get();
+  EXPECT_EQ(ui::EventType::ET_TOUCH_RELEASED, event->type());
+  EXPECT_FALSE(hover_action->touch_id());
+  event_generator_->MoveMouseTo(gfx::Point(330, 220), 1);
+  EXPECT_FALSE(event_capturer_.mouse_events().empty());
+  event_capturer_.Clear();
+}
+
+}  // namespace input_overlay
 }  // namespace arc
diff --git a/chrome/browser/ash/arc/policy/arc_policy_bridge.cc b/chrome/browser/ash/arc/policy/arc_policy_bridge.cc
index ad0c33a0..9ebedd2 100644
--- a/chrome/browser/ash/arc/policy/arc_policy_bridge.cc
+++ b/chrome/browser/ash/arc/policy/arc_policy_bridge.cc
@@ -313,7 +313,7 @@
   }
 
   if (profile->IsChild() &&
-      chromeos::ProfileHelper::Get()->IsPrimaryProfile(profile)) {
+      ash::ProfileHelper::Get()->IsPrimaryProfile(profile)) {
     // Adds "playStoreMode" policy. The policy value is used to restrict the
     // user from being able to toggle between different accounts in ARC++.
     filtered_policies.SetStringKey("playStoreMode", "SUPERVISED");
@@ -636,7 +636,7 @@
     return std::string();
   const Profile* const profile = Profile::FromBrowserContext(context_);
   const user_manager::User* const user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   const CertStoreService* cert_store_service =
       CertStoreService::GetForBrowserContext(context_);
 
diff --git a/chrome/browser/ash/arc/session/arc_service_launcher.cc b/chrome/browser/ash/arc/session/arc_service_launcher.cc
index e0b925e..0d18655 100644
--- a/chrome/browser/ash/arc/session/arc_service_launcher.cc
+++ b/chrome/browser/ash/arc/session/arc_service_launcher.cc
@@ -235,7 +235,7 @@
   ArcPipBridge::GetForBrowserContext(profile);
   ArcPolicyBridge::GetForBrowserContext(profile);
   ArcPowerBridge::GetForBrowserContext(profile)->SetUserIdHash(
-      chromeos::ProfileHelper::GetUserIdHashFromProfile(profile));
+      ash::ProfileHelper::GetUserIdHashFromProfile(profile));
   ArcPrintSpoolerBridge::GetForBrowserContext(profile);
   ArcProcessService::GetForBrowserContext(profile);
   ArcPropertyBridge::GetForBrowserContext(profile);
diff --git a/chrome/browser/ash/arc/session/arc_session_manager.cc b/chrome/browser/ash/arc/session/arc_session_manager.cc
index ee623d46..eb0820da 100644
--- a/chrome/browser/ash/arc/session/arc_session_manager.cc
+++ b/chrome/browser/ash/arc/session/arc_session_manager.cc
@@ -811,7 +811,7 @@
   const AccountId account(multi_user_util::GetAccountIdFromProfile(profile_));
   const cryptohome::Identification cryptohome_id(account);
   const std::string user_id_hash =
-      chromeos::ProfileHelper::GetUserIdHashFromProfile(profile_);
+      ash::ProfileHelper::GetUserIdHashFromProfile(profile_);
 
   std::string serialno = GetSerialNumber();
   arc_session_runner_->SetUserInfo(cryptohome_id, user_id_hash, serialno);
@@ -827,7 +827,7 @@
 
   const AccountId account(multi_user_util::GetAccountIdFromProfile(profile_));
   const std::string user_id_hash =
-      chromeos::ProfileHelper::GetUserIdHashFromProfile(profile_);
+      ash::ProfileHelper::GetUserIdHashFromProfile(profile_);
 
   std::string serialno;
   // ARC container doesn't need the serial number.
diff --git a/chrome/browser/ash/arc/session/arc_session_manager_browsertest.cc b/chrome/browser/ash/arc/session/arc_session_manager_browsertest.cc
index be8d7ca..8c23785b 100644
--- a/chrome/browser/ash/arc/session/arc_session_manager_browsertest.cc
+++ b/chrome/browser/ash/arc/session/arc_session_manager_browsertest.cc
@@ -138,7 +138,7 @@
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     ExpandPropertyFilesForTesting(ArcSessionManager::Get());
 
-    chromeos::ProfileHelper::SetAlwaysReturnPrimaryUserForTesting(true);
+    ash::ProfileHelper::SetAlwaysReturnPrimaryUserForTesting(true);
 
     const AccountId account_id(
         AccountId::FromUserEmailGaiaId(kFakeUserName, kFakeGaiaId));
@@ -154,7 +154,7 @@
 
     identity_test_environment_adaptor_ =
         std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile_.get());
-    chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
+    ash::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
         GetFakeUserManager()->GetPrimaryUser(), profile_.get());
 
     // Seed account info properly.
@@ -200,7 +200,7 @@
     profile_.reset();
     base::RunLoop().RunUntilIdle();
     user_manager_enabler_.reset();
-    chromeos::ProfileHelper::SetAlwaysReturnPrimaryUserForTesting(false);
+    ash::ProfileHelper::SetAlwaysReturnPrimaryUserForTesting(false);
     MixinBasedInProcessBrowserTest::TearDownOnMainThread();
   }
 
diff --git a/chrome/browser/ash/assistant/assistant_util.cc b/chrome/browser/ash/assistant/assistant_util.cc
index b4979f6..be517c7 100644
--- a/chrome/browser/ash/assistant/assistant_util.cc
+++ b/chrome/browser/ash/assistant/assistant_util.cc
@@ -41,7 +41,7 @@
 }
 
 const user_manager::User* GetUser(const Profile* profile) {
-  return chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+  return ash::ProfileHelper::Get()->GetUserByProfile(profile);
 }
 
 bool IsAssistantAllowedForUserType(const Profile* profile) {
@@ -136,7 +136,7 @@
   if (!HasPrimaryAccount(profile))
     return AssistantAllowedState::DISALLOWED_BY_NONPRIMARY_USER;
 
-  if (!chromeos::ProfileHelper::IsPrimaryProfile(profile))
+  if (!ash::ProfileHelper::IsPrimaryProfile(profile))
     return AssistantAllowedState::DISALLOWED_BY_NONPRIMARY_USER;
 
   if (profile->IsOffTheRecord())
diff --git a/chrome/browser/ash/borealis/borealis_app_launcher.cc b/chrome/browser/ash/borealis/borealis_app_launcher.cc
index bcb580b..a09fccf 100644
--- a/chrome/browser/ash/borealis/borealis_app_launcher.cc
+++ b/chrome/browser/ash/borealis/borealis_app_launcher.cc
@@ -45,7 +45,7 @@
 
   vm_tools::cicerone::LaunchContainerApplicationRequest request;
   request.set_owner_id(
-      chromeos::ProfileHelper::GetUserIdHashFromProfile(ctx.profile()));
+      ash::ProfileHelper::GetUserIdHashFromProfile(ctx.profile()));
   request.set_vm_name(ctx.vm_name());
   request.set_container_name(ctx.container_name());
   request.set_desktop_file_id(reg->DesktopFileId());
diff --git a/chrome/browser/ash/borealis/borealis_context_manager_impl.cc b/chrome/browser/ash/borealis/borealis_context_manager_impl.cc
index 46d95c7..7183535 100644
--- a/chrome/browser/ash/borealis/borealis_context_manager_impl.cc
+++ b/chrome/browser/ash/borealis/borealis_context_manager_impl.cc
@@ -108,8 +108,7 @@
     return;
   }
   vm_tools::concierge::GetVmInfoRequest request;
-  request.set_owner_id(
-      chromeos::ProfileHelper::GetUserIdHashFromProfile(profile_));
+  request.set_owner_id(ash::ProfileHelper::GetUserIdHashFromProfile(profile_));
   request.set_name(kBorealisVmName);
   chromeos::ConciergeClient::Get()->GetVmInfo(
       std::move(request),
@@ -130,8 +129,7 @@
   // TODO(b/172178036): This could have been a task-sequence but that
   // abstraction is proving insufficient.
   vm_tools::concierge::StopVmRequest request;
-  request.set_owner_id(
-      chromeos::ProfileHelper::GetUserIdHashFromProfile(profile_));
+  request.set_owner_id(ash::ProfileHelper::GetUserIdHashFromProfile(profile_));
   request.set_name(vm_name);
   chromeos::ConciergeClient::Get()->StopVm(
       std::move(request),
@@ -256,7 +254,7 @@
     const vm_tools::concierge::VmStoppedSignal& signal) {
   if (context_ && context_->vm_name() == signal.name() &&
       signal.owner_id() ==
-          chromeos::ProfileHelper::GetUserIdHashFromProfile(profile_)) {
+          ash::ProfileHelper::GetUserIdHashFromProfile(profile_)) {
     CloseBorealisSplashScreenView();
     // If |context_| exists, it's a "running" Borealis instance which we didn't
     // request to shut down.
diff --git a/chrome/browser/ash/borealis/borealis_installer_impl.cc b/chrome/browser/ash/borealis/borealis_installer_impl.cc
index d10d690..8f7df8db 100644
--- a/chrome/browser/ash/borealis/borealis_installer_impl.cc
+++ b/chrome/browser/ash/borealis/borealis_installer_impl.cc
@@ -252,7 +252,7 @@
 
     vm_tools::concierge::DestroyDiskImageRequest request;
     request.set_cryptohome_id(
-        chromeos::ProfileHelper::GetUserIdHashFromProfile(profile_));
+        ash::ProfileHelper::GetUserIdHashFromProfile(profile_));
     request.set_vm_name(uninstall_info_->vm_name);
     chromeos::ConciergeClient::Get()->DestroyDiskImage(
         std::move(request), base::BindOnce(&Uninstallation::OnDiskRemoved,
diff --git a/chrome/browser/ash/borealis/borealis_launch_watcher.cc b/chrome/browser/ash/borealis/borealis_launch_watcher.cc
index 230bd508..0fa7e114 100644
--- a/chrome/browser/ash/borealis/borealis_launch_watcher.cc
+++ b/chrome/browser/ash/borealis/borealis_launch_watcher.cc
@@ -11,7 +11,7 @@
 
 BorealisLaunchWatcher::BorealisLaunchWatcher(Profile* profile,
                                              std::string vm_name)
-    : owner_id_(chromeos::ProfileHelper::GetUserIdHashFromProfile(profile)),
+    : owner_id_(ash::ProfileHelper::GetUserIdHashFromProfile(profile)),
       vm_name_(vm_name) {
   chromeos::CiceroneClient::Get()->AddObserver(this);
 }
diff --git a/chrome/browser/ash/borealis/borealis_launch_watcher_unittest.cc b/chrome/browser/ash/borealis/borealis_launch_watcher_unittest.cc
index 5c85a345..b58cd74 100644
--- a/chrome/browser/ash/borealis/borealis_launch_watcher_unittest.cc
+++ b/chrome/browser/ash/borealis/borealis_launch_watcher_unittest.cc
@@ -34,8 +34,7 @@
   CallbackFactory callback_expectation;
   BorealisLaunchWatcher watcher(profile_, "FooVm");
   vm_tools::cicerone::ContainerStartedSignal signal;
-  signal.set_owner_id(
-      chromeos::ProfileHelper::GetUserIdHashFromProfile(profile_));
+  signal.set_owner_id(ash::ProfileHelper::GetUserIdHashFromProfile(profile_));
   signal.set_vm_name("FooVm");
   signal.set_container_name("FooContainer");
 
@@ -63,8 +62,7 @@
   CallbackFactory callback_expectation;
   BorealisLaunchWatcher watcher(profile_, "FooVm");
   vm_tools::cicerone::ContainerStartedSignal signal;
-  signal.set_owner_id(
-      chromeos::ProfileHelper::GetUserIdHashFromProfile(profile_));
+  signal.set_owner_id(ash::ProfileHelper::GetUserIdHashFromProfile(profile_));
   signal.set_vm_name("FooVm");
   signal.set_container_name("FooContainer");
 
@@ -80,8 +78,7 @@
   CallbackFactory callback_expectation;
   BorealisLaunchWatcher watcher(profile_, "FooVm");
   vm_tools::cicerone::ContainerStartedSignal signal;
-  signal.set_owner_id(
-      chromeos::ProfileHelper::GetUserIdHashFromProfile(profile_));
+  signal.set_owner_id(ash::ProfileHelper::GetUserIdHashFromProfile(profile_));
   signal.set_vm_name("FooVm");
   signal.set_container_name("FooContainer");
 
@@ -117,8 +114,7 @@
   signal1.set_owner_id("not-the-owner");
   signal1.set_vm_name("FooVm");
   vm_tools::cicerone::ContainerStartedSignal signal2;
-  signal2.set_owner_id(
-      chromeos::ProfileHelper::GetUserIdHashFromProfile(profile_));
+  signal2.set_owner_id(ash::ProfileHelper::GetUserIdHashFromProfile(profile_));
   signal2.set_vm_name("not-FooVm");
 
   EXPECT_CALL(callback_expectation,
diff --git a/chrome/browser/ash/borealis/borealis_task.cc b/chrome/browser/ash/borealis/borealis_task.cc
index d1a4dde..822cd7d 100644
--- a/chrome/browser/ash/borealis/borealis_task.cc
+++ b/chrome/browser/ash/borealis/borealis_task.cc
@@ -85,7 +85,7 @@
   vm_tools::concierge::CreateDiskImageRequest request;
   request.set_vm_name(context->vm_name());
   request.set_cryptohome_id(
-      chromeos::ProfileHelper::GetUserIdHashFromProfile(context->profile()));
+      ash::ProfileHelper::GetUserIdHashFromProfile(context->profile()));
   request.set_image_type(vm_tools::concierge::DISK_IMAGE_AUTO);
   request.set_storage_location(vm_tools::concierge::STORAGE_CRYPTOHOME_ROOT);
   request.set_disk_size(0);
@@ -194,7 +194,7 @@
       context->wayland_path().AsUTF8Unsafe());
   request.set_start_termina(false);
   request.set_owner_id(
-      chromeos::ProfileHelper::GetUserIdHashFromProfile(context->profile()));
+      ash::ProfileHelper::GetUserIdHashFromProfile(context->profile()));
   request.set_enable_gpu(true);
   request.set_software_tpm(false);
   request.set_enable_audio_capture(false);
diff --git a/chrome/browser/ash/borealis/borealis_task_unittest.cc b/chrome/browser/ash/borealis/borealis_task_unittest.cc
index 368ad258..2e756eb 100644
--- a/chrome/browser/ash/borealis/borealis_task_unittest.cc
+++ b/chrome/browser/ash/borealis/borealis_task_unittest.cc
@@ -180,7 +180,7 @@
        AwaitBorealisStartupSucceedsAndCallbackRanWithResults) {
   vm_tools::cicerone::ContainerStartedSignal signal;
   signal.set_owner_id(
-      chromeos::ProfileHelper::GetUserIdHashFromProfile(context_->profile()));
+      ash::ProfileHelper::GetUserIdHashFromProfile(context_->profile()));
   signal.set_vm_name(context_->vm_name());
   signal.set_container_name("penguin");
 
@@ -198,7 +198,7 @@
        AwaitBorealisStartupContainerAlreadyStartedAndCallbackRanWithResults) {
   vm_tools::cicerone::ContainerStartedSignal signal;
   signal.set_owner_id(
-      chromeos::ProfileHelper::GetUserIdHashFromProfile(context_->profile()));
+      ash::ProfileHelper::GetUserIdHashFromProfile(context_->profile()));
   signal.set_vm_name(context_->vm_name());
   signal.set_container_name("penguin");
 
diff --git a/chrome/browser/ash/crosapi/browser_manager.cc b/chrome/browser/ash/crosapi/browser_manager.cc
index d38dffd..2660148 100644
--- a/chrome/browser/ash/crosapi/browser_manager.cc
+++ b/chrome/browser/ash/crosapi/browser_manager.cc
@@ -771,9 +771,8 @@
 
   // TODO(ythjkt): After M92 cherry-pick, clean up the following code by moving
   // the data wipe check logic from `BrowserDataMigrator` to browser_util.
-  const std::string user_id_hash =
-      chromeos::ProfileHelper::GetUserIdHashFromProfile(
-          ProfileManager::GetPrimaryUserProfile());
+  const std::string user_id_hash = ash::ProfileHelper::GetUserIdHashFromProfile(
+      ProfileManager::GetPrimaryUserProfile());
   // Check if user data directory needs to be wiped for a backward incompatible
   // update.
   bool cleared_user_data_dir = !browser_util::IsDataWipeRequired(user_id_hash);
@@ -809,9 +808,8 @@
     return;
   }
 
-  const std::string user_id_hash =
-      chromeos::ProfileHelper::GetUserIdHashFromProfile(
-          ProfileManager::GetPrimaryUserProfile());
+  const std::string user_id_hash = ash::ProfileHelper::GetUserIdHashFromProfile(
+      ProfileManager::GetPrimaryUserProfile());
   crosapi::browser_util::RecordDataVer(g_browser_process->local_state(),
                                        user_id_hash,
                                        version_info::GetVersion());
@@ -1128,7 +1126,7 @@
 
   switch (user->GetType()) {
     case user_manager::USER_TYPE_REGULAR: {
-      Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+      Profile* profile = ash::ProfileHelper::Get()->GetProfileByUser(user);
       DCHECK(profile);
       policy::CloudPolicyManager* user_cloud_policy_manager =
           profile->GetUserCloudPolicyManagerAsh();
diff --git a/chrome/browser/ash/crosapi/browser_manager_unittest.cc b/chrome/browser/ash/crosapi/browser_manager_unittest.cc
index 58df936a..6d5df7c 100644
--- a/chrome/browser/ash/crosapi/browser_manager_unittest.cc
+++ b/chrome/browser/ash/crosapi/browser_manager_unittest.cc
@@ -103,7 +103,7 @@
     fake_user_manager_->UserLoggedIn(account_id, user->username_hash(),
                                      /*browser_restart=*/false,
                                      /*is_child=*/false);
-    chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
+    ash::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
         user, &testing_profile_);
   }
 
@@ -127,7 +127,7 @@
 TEST_F(BrowserManagerTest, LacrosKeepAlive) {
   AddRegularUser("user@test.com");
   browser_util::SetProfileMigrationCompletedForUser(
-      local_state_.Get(), chromeos::ProfileHelper::Get()
+      local_state_.Get(), ash::ProfileHelper::Get()
                               ->GetUserByProfile(&testing_profile_)
                               ->username_hash());
   EXPECT_TRUE(browser_util::IsLacrosEnabled());
@@ -171,7 +171,7 @@
 TEST_F(BrowserManagerTest, LacrosKeepAliveReloadsWhenUpdateAvailable) {
   AddRegularUser("user@test.com");
   browser_util::SetProfileMigrationCompletedForUser(
-      local_state_.Get(), chromeos::ProfileHelper::Get()
+      local_state_.Get(), ash::ProfileHelper::Get()
                               ->GetUserByProfile(&testing_profile_)
                               ->username_hash());
   EXPECT_TRUE(browser_util::IsLacrosEnabled());
@@ -216,7 +216,7 @@
 TEST_F(BrowserManagerTest, NewWindowReloadsWhenUpdateAvailable) {
   AddRegularUser("user@test.com");
   browser_util::SetProfileMigrationCompletedForUser(
-      local_state_.Get(), chromeos::ProfileHelper::Get()
+      local_state_.Get(), ash::ProfileHelper::Get()
                               ->GetUserByProfile(&testing_profile_)
                               ->username_hash());
   EXPECT_TRUE(browser_util::IsLacrosEnabled());
diff --git a/chrome/browser/ash/crosapi/browser_util_unittest.cc b/chrome/browser/ash/crosapi/browser_util_unittest.cc
index a981edd..5d40f88 100644
--- a/chrome/browser/ash/crosapi/browser_util_unittest.cc
+++ b/chrome/browser/ash/crosapi/browser_util_unittest.cc
@@ -84,7 +84,7 @@
     fake_user_manager_->UserLoggedIn(account_id, user->username_hash(),
                                      /*browser_restart=*/false,
                                      /*is_child=*/false);
-    chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
+    ash::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
         user, &testing_profile_);
   }
 
@@ -130,7 +130,7 @@
   // non-googlers, add a @test.com account instead.
   AddRegularUser("user@google.com");
   const user_manager::User* const user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(&testing_profile_);
+      ash::ProfileHelper::Get()->GetUserByProfile(&testing_profile_);
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(chromeos::features::kLacrosSupport);
 
diff --git a/chrome/browser/ash/crosapi/crosapi_util.cc b/chrome/browser/ash/crosapi/crosapi_util.cc
index fd2906c..ed87d93 100644
--- a/chrome/browser/ash/crosapi/crosapi_util.cc
+++ b/chrome/browser/ash/crosapi/crosapi_util.cc
@@ -294,7 +294,7 @@
   // the long term fix is made in ash-chrome, atomically.
   params->exo_ime_support =
       crosapi::mojom::ExoImeSupport::kConsumedByImeWorkaround;
-  params->cros_user_id_hash = chromeos::ProfileHelper::GetUserIdHashFromProfile(
+  params->cros_user_id_hash = ash::ProfileHelper::GetUserIdHashFromProfile(
       ProfileManager::GetPrimaryUserProfile());
   params->device_account_policy = GetDeviceAccountPolicy(environment_provider);
   params->idle_info = IdleServiceAsh::ReadIdleInfoFromSystem();
@@ -420,14 +420,14 @@
 }
 
 bool IsSigninProfileOrBelongsToAffiliatedUser(Profile* profile) {
-  if (chromeos::ProfileHelper::IsSigninProfile(profile))
+  if (ash::ProfileHelper::IsSigninProfile(profile))
     return true;
 
   if (profile->IsOffTheRecord())
     return false;
 
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   if (!user)
     return false;
   return user->IsAffiliated();
diff --git a/chrome/browser/ash/crosapi/crosapi_util_unittest.cc b/chrome/browser/ash/crosapi/crosapi_util_unittest.cc
index 234d9b44..0f04d05 100644
--- a/chrome/browser/ash/crosapi/crosapi_util_unittest.cc
+++ b/chrome/browser/ash/crosapi/crosapi_util_unittest.cc
@@ -38,7 +38,7 @@
     fake_user_manager_->UserLoggedIn(account_id, user->username_hash(),
                                      /*browser_restart=*/false,
                                      /*is_child=*/false);
-    chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
+    ash::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
         user, &testing_profile_);
   }
 
@@ -91,7 +91,7 @@
   fake_user_manager_->UserLoggedIn(account_id, user->username_hash(),
                                    /*browser_restart=*/false,
                                    /*is_child=*/false);
-  chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
+  ash::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
       user, &testing_profile_);
 
   EXPECT_TRUE(browser_util::IsSigninProfileOrBelongsToAffiliatedUser(
diff --git a/chrome/browser/ash/crosapi/environment_provider.cc b/chrome/browser/ash/crosapi/environment_provider.cc
index ef3c7c6..84d62cf 100644
--- a/chrome/browser/ash/crosapi/environment_provider.cc
+++ b/chrome/browser/ash/crosapi/environment_provider.cc
@@ -31,7 +31,7 @@
   const user_manager::User* const user =
       user_manager::UserManager::Get()->GetPrimaryUser();
   const Profile* const profile =
-      chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+      ash::ProfileHelper::Get()->GetProfileByUser(user);
   if (profile->IsGuestSession()) {
     return mojom::SessionType::kGuestSession;
   }
@@ -74,7 +74,7 @@
   // support multi-signin.
   const user_manager::User* user =
       user_manager::UserManager::Get()->GetPrimaryUser();
-  Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+  Profile* profile = ash::ProfileHelper::Get()->GetProfileByUser(user);
 
   default_paths->user_nss_database =
       crypto::GetSoftwareNSSDBPath(profile->GetPath());
diff --git a/chrome/browser/ash/crosapi/feedback_ash.cc b/chrome/browser/ash/crosapi/feedback_ash.cc
index 18af7dfe..510d4cc 100644
--- a/chrome/browser/ash/crosapi/feedback_ash.cc
+++ b/chrome/browser/ash/crosapi/feedback_ash.cc
@@ -39,7 +39,7 @@
     LOG(ERROR) << "Cannot invoke feedback for lacros: No primary user found!";
     return;
   }
-  Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+  Profile* profile = ash::ProfileHelper::Get()->GetProfileByUser(user);
   if (!profile) {
     LOG(ERROR)
         << "Cannot invoke feedback for lacros: No primary profile found!";
diff --git a/chrome/browser/ash/crosapi/local_printer_ash_unittest.cc b/chrome/browser/ash/crosapi/local_printer_ash_unittest.cc
index 91ecb514..efbe2f4 100644
--- a/chrome/browser/ash/crosapi/local_printer_ash_unittest.cc
+++ b/chrome/browser/ash/crosapi/local_printer_ash_unittest.cc
@@ -229,7 +229,7 @@
   }
 
   void SetUp() override {
-    chromeos::ProfileHelper::Get()->SetProfileToUserMappingForTesting(&user_);
+    ash::ProfileHelper::Get()->SetProfileToUserMappingForTesting(&user_);
 
 #if BUILDFLAG(ENABLE_OOP_PRINTING)
     // Choose between running with local test runner or via a service.
@@ -282,7 +282,7 @@
 #if BUILDFLAG(ENABLE_OOP_PRINTING)
     PrintBackendServiceManager::ResetForTesting();
 #endif
-    chromeos::ProfileHelper::Get()->RemoveUserFromListForTesting(
+    ash::ProfileHelper::Get()->RemoveUserFromListForTesting(
         user_.GetAccountId());
   }
 
diff --git a/chrome/browser/ash/crosapi/networking_attributes_ash_unittest.cc b/chrome/browser/ash/crosapi/networking_attributes_ash_unittest.cc
index 120e744..ef9df41 100644
--- a/chrome/browser/ash/crosapi/networking_attributes_ash_unittest.cc
+++ b/chrome/browser/ash/crosapi/networking_attributes_ash_unittest.cc
@@ -107,8 +107,8 @@
         user_manager->AddUserWithAffiliation(account_id, is_affiliated);
     user_manager->UserLoggedIn(account_id, user->username_hash(),
                                /*browser_restart=*/false, /*is_child=*/false);
-    chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
-        user, &profile_);
+    ash::ProfileHelper::Get()->SetUserToProfileMappingForTesting(user,
+                                                                 &profile_);
   }
 
   void SetUpShillState() {
diff --git a/chrome/browser/ash/crosapi/test_mojo_connection_manager_unittest.cc b/chrome/browser/ash/crosapi/test_mojo_connection_manager_unittest.cc
index 9aa136f..4ed25111 100644
--- a/chrome/browser/ash/crosapi/test_mojo_connection_manager_unittest.cc
+++ b/chrome/browser/ash/crosapi/test_mojo_connection_manager_unittest.cc
@@ -194,8 +194,7 @@
   TestingProfile* profile =
       testing_profile_manager.CreateTestingProfile(account.GetUserEmail());
   profile->set_profile_name(account.GetUserEmail());
-  chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(user,
-                                                                    profile);
+  ash::ProfileHelper::Get()->SetUserToProfileMappingForTesting(user, profile);
 
   auto crosapi_manager = std::make_unique<CrosapiManager>();
 
diff --git a/chrome/browser/ash/crostini/crostini_export_import.cc b/chrome/browser/ash/crostini/crostini_export_import.cc
index df071d9..867af69 100644
--- a/chrome/browser/ash/crostini/crostini_export_import.cc
+++ b/chrome/browser/ash/crostini/crostini_export_import.cc
@@ -428,31 +428,6 @@
 
 void CrostiniExportImport::OnExportContainerProgress(
     const ContainerId& container_id,
-    ExportContainerProgressStatus status,
-    int progress_percent,
-    uint64_t progress_speed) {
-  auto it = status_trackers_.find(container_id);
-  if (it == status_trackers_.end()) {
-    NOTREACHED() << container_id << " has no status_tracker to update";
-    return;
-  }
-
-  switch (status) {
-    // Rescale PACK:1-100 => 0-50.
-    case ExportContainerProgressStatus::PACK:
-      it->second->SetStatusRunning(progress_percent / 2);
-      break;
-    // Rescale DOWNLOAD:1-100 => 50-100.
-    case ExportContainerProgressStatus::DOWNLOAD:
-      it->second->SetStatusRunning(50 + progress_percent / 2);
-      break;
-    default:
-      LOG(WARNING) << "Unknown Export progress status " << int(status);
-  }
-}
-
-void CrostiniExportImport::OnExportContainerProgress(
-    const ContainerId& container_id,
     const StreamingExportStatus& status) {
   auto it = status_trackers_.find(container_id);
   if (it == status_trackers_.end()) {
diff --git a/chrome/browser/ash/crostini/crostini_export_import.h b/chrome/browser/ash/crostini/crostini_export_import.h
index 8a1cc79..a4162afa 100644
--- a/chrome/browser/ash/crostini/crostini_export_import.h
+++ b/chrome/browser/ash/crostini/crostini_export_import.h
@@ -185,13 +185,6 @@
              base::FilePath path,
              CrostiniManager::CrostiniResultCallback callback);
 
-  // DEPRECATED crostini::ExportContainerProgressObserver implementation.
-  // TODO(juwa): delete this once the new version of tremplin has shipped.
-  void OnExportContainerProgress(const ContainerId& container_id,
-                                 crostini::ExportContainerProgressStatus status,
-                                 int progress_percent,
-                                 uint64_t progress_speed) override;
-
   // crostini::ExportContainerProgressObserver implementation.
   void OnExportContainerProgress(const ContainerId& container_id,
                                  const StreamingExportStatus& status) override;
diff --git a/chrome/browser/ash/crostini/crostini_features.cc b/chrome/browser/ash/crostini/crostini_features.cc
index 4bc81f5..114a104 100644
--- a/chrome/browser/ash/crostini/crostini_features.cc
+++ b/chrome/browser/ash/crostini/crostini_features.cc
@@ -192,15 +192,15 @@
     return false;
   }
 
-  if (!chromeos::ProfileHelper::IsPrimaryProfile(profile)) {
+  if (!ash::ProfileHelper::IsPrimaryProfile(profile)) {
     VLOG(1) << "Crostini UI is not allowed on non-primary profiles.";
     *reason = "Crostini is only allowed in primary user sessions";
     return false;
   }
 
   if (!profile || profile->IsChild() || profile->IsOffTheRecord() ||
-      chromeos::ProfileHelper::IsEphemeralUserProfile(profile) ||
-      chromeos::ProfileHelper::IsLockScreenAppProfile(profile)) {
+      ash::ProfileHelper::IsEphemeralUserProfile(profile) ||
+      ash::ProfileHelper::IsLockScreenAppProfile(profile)) {
     VLOG(1) << "Profile is not allowed to run crostini.";
     *reason = "This user session is not allowed to run crostini";
     return false;
@@ -234,7 +234,7 @@
   }
 
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   if (!IsUnaffiliatedCrostiniAllowedByPolicy() && !user->IsAffiliated()) {
     VLOG(1) << "Policy blocks unaffiliated user from running Crostini.";
     *reason = "Crostini for unaffiliated users is disabled by policy";
@@ -310,15 +310,14 @@
   bool is_device_enterprise_managed = connector->IsDeviceEnterpriseManaged();
   bool is_profile_enterprise_managed =
       profile->GetProfilePolicyConnector()->IsManaged();
-  bool is_owner_profile = chromeos::ProfileHelper::IsOwnerProfile(profile);
+  bool is_owner_profile = ash::ProfileHelper::IsOwnerProfile(profile);
   if (is_device_enterprise_managed || is_profile_enterprise_managed) {
     auto user_policy =
         static_cast<crostini::CrostiniArcAdbSideloadingUserAllowanceMode>(
             profile->GetPrefs()->GetInteger(
                 crostini::prefs::kCrostiniArcAdbSideloadingUserPref));
 
-    const auto* user =
-        chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+    const auto* user = ash::ProfileHelper::Get()->GetUserByProfile(profile);
     bool is_affiliated_user = user && user->IsAffiliated();
 
     CanChangeManagedAdbSideloading(
diff --git a/chrome/browser/ash/crostini/crostini_manager.cc b/chrome/browser/ash/crostini/crostini_manager.cc
index 8dae741e..d33babf 100644
--- a/chrome/browser/ash/crostini/crostini_manager.cc
+++ b/chrome/browser/ash/crostini/crostini_manager.cc
@@ -3291,21 +3291,6 @@
 
   CrostiniResult result;
   switch (signal.status()) {
-    // TODO(juwa): Remove EXPORTING_[PACK|DOWNLOAD] once a new version of
-    // tremplin has shipped.
-    case ProgressSignal::EXPORTING_PACK:
-    case ProgressSignal::EXPORTING_DOWNLOAD: {
-      // If we are still exporting, call progress observers.
-      const auto status = signal.status() == ProgressSignal::EXPORTING_PACK
-                              ? ExportContainerProgressStatus::PACK
-                              : ExportContainerProgressStatus::DOWNLOAD;
-      for (auto& observer : export_container_progress_observers_) {
-        observer.OnExportContainerProgress(container_id, status,
-                                           signal.progress_percent(),
-                                           signal.progress_speed());
-      }
-      return;
-    }
     case ProgressSignal::EXPORTING_STREAMING: {
       const StreamingExportStatus status{
           .total_files = signal.total_input_files(),
diff --git a/chrome/browser/ash/crostini/crostini_manager.h b/chrome/browser/ash/crostini/crostini_manager.h
index 833c038b..549c877 100644
--- a/chrome/browser/ash/crostini/crostini_manager.h
+++ b/chrome/browser/ash/crostini/crostini_manager.h
@@ -80,14 +80,6 @@
 
 class ExportContainerProgressObserver {
  public:
-  // DEPCRECATED. A successfully started container export will continually fire
-  // progress events until the original callback from ExportLxdContainer is
-  // invoked with a status of SUCCESS or CONTAINER_EXPORT_FAILED.
-  virtual void OnExportContainerProgress(const ContainerId& container_id,
-                                         ExportContainerProgressStatus status,
-                                         int progress_percent,
-                                         uint64_t progress_speed) = 0;
-
   // A successfully started container export will continually fire progress
   // events until the original callback from ExportLxdContainer is invoked with
   // a status of SUCCESS or CONTAINER_EXPORT_FAILED.
diff --git a/chrome/browser/ash/crostini/crostini_manager_unittest.cc b/chrome/browser/ash/crostini/crostini_manager_unittest.cc
index cbc0c0eb..7e1295c2 100644
--- a/chrome/browser/ash/crostini/crostini_manager_unittest.cc
+++ b/chrome/browser/ash/crostini/crostini_manager_unittest.cc
@@ -1846,18 +1846,14 @@
       base::BindOnce(&ExpectCrostiniExportResult, run_loop()->QuitClosure(),
                      CrostiniResult::SUCCESS, 123, 456));
 
-  // Send signals, PACK, DOWNLOAD, DONE.
+  // Send signals, STREAMING, DONE.
   vm_tools::cicerone::ExportLxdContainerProgressSignal signal;
   signal.set_owner_id(CryptohomeIdForProfile(profile()));
   signal.set_vm_name(kVmName);
   signal.set_container_name(kContainerName);
-  signal.set_status(vm_tools::cicerone::
-                        ExportLxdContainerProgressSignal_Status_EXPORTING_PACK);
-  fake_cicerone_client_->NotifyExportLxdContainerProgress(signal);
-
   signal.set_status(
       vm_tools::cicerone::
-          ExportLxdContainerProgressSignal_Status_EXPORTING_DOWNLOAD);
+          ExportLxdContainerProgressSignal_Status_EXPORTING_STREAMING);
   fake_cicerone_client_->NotifyExportLxdContainerProgress(signal);
 
   signal.set_status(
diff --git a/chrome/browser/ash/crostini/crostini_simple_types.h b/chrome/browser/ash/crostini/crostini_simple_types.h
index 74f77abe..4d6bfcc1 100644
--- a/chrome/browser/ash/crostini/crostini_simple_types.h
+++ b/chrome/browser/ash/crostini/crostini_simple_types.h
@@ -123,15 +123,6 @@
   UNINSTALLING,  // In progress
 };
 
-// TODO(juwa): delete this once the new version of tremplin has shipped.
-enum class ExportContainerProgressStatus {
-  // Deprecated. Has been replaced by STREAMING.
-  PACK,
-  // Deprecated. Has been replaced by STREAMING.
-  DOWNLOAD,
-  STREAMING,
-};
-
 enum class ImportContainerProgressStatus {
   UPLOAD,
   UNPACK,
diff --git a/chrome/browser/ash/crostini/crostini_test_helper.cc b/chrome/browser/ash/crostini/crostini_test_helper.cc
index a6e1c9c..af368b9 100644
--- a/chrome/browser/ash/crostini/crostini_test_helper.cc
+++ b/chrome/browser/ash/crostini/crostini_test_helper.cc
@@ -31,7 +31,7 @@
     : profile_(profile) {
   scoped_feature_list_.InitAndEnableFeature(features::kCrostini);
 
-  chromeos::ProfileHelper::SetAlwaysReturnPrimaryUserForTesting(true);
+  ash::ProfileHelper::SetAlwaysReturnPrimaryUserForTesting(true);
   scoped_user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
       std::make_unique<ash::FakeChromeUserManager>());
   auto* fake_user_manager = static_cast<ash::FakeChromeUserManager*>(
@@ -49,7 +49,7 @@
 }
 
 CrostiniTestHelper::~CrostiniTestHelper() {
-  chromeos::ProfileHelper::SetAlwaysReturnPrimaryUserForTesting(false);
+  ash::ProfileHelper::SetAlwaysReturnPrimaryUserForTesting(false);
   DisableCrostini(profile_);
 }
 
diff --git a/chrome/browser/ash/crostini/crostini_util.cc b/chrome/browser/ash/crostini/crostini_util.cc
index 626989339..3e7014c7 100644
--- a/chrome/browser/ash/crostini/crostini_util.cc
+++ b/chrome/browser/ash/crostini/crostini_util.cc
@@ -420,14 +420,14 @@
 }
 
 std::string CryptohomeIdForProfile(Profile* profile) {
-  std::string id = chromeos::ProfileHelper::GetUserIdHashFromProfile(profile);
+  std::string id = ash::ProfileHelper::GetUserIdHashFromProfile(profile);
   // Empty id means we're running in a test.
   return id.empty() ? "test" : id;
 }
 
 std::string DefaultContainerUserNameForProfile(Profile* profile) {
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   if (!user) {
     return kCrostiniDefaultUsername;
   }
diff --git a/chrome/browser/ash/dbus/vm/vm_permission_service_provider.cc b/chrome/browser/ash/dbus/vm/vm_permission_service_provider.cc
index 408fa9a..f2ea751c 100644
--- a/chrome/browser/ash/dbus/vm/vm_permission_service_provider.cc
+++ b/chrome/browser/ash/dbus/vm/vm_permission_service_provider.cc
@@ -357,8 +357,8 @@
 
 void VmPermissionServiceProvider::UpdateBorealisPermissions(VmInfo* vm) {
   Profile* profile = ProfileManager::GetPrimaryUserProfile();
-  if (!profile || chromeos::ProfileHelper::GetUserIdHashFromProfile(profile) !=
-                      vm->owner_id) {
+  if (!profile ||
+      ProfileHelper::GetUserIdHashFromProfile(profile) != vm->owner_id) {
     return;
   }
 
diff --git a/chrome/browser/ash/drive/drive_integration_service.cc b/chrome/browser/ash/drive/drive_integration_service.cc
index 7a0e8f0ee..373d940 100644
--- a/chrome/browser/ash/drive/drive_integration_service.cc
+++ b/chrome/browser/ash/drive/drive_integration_service.cc
@@ -499,7 +499,7 @@
   }
 
   const AccountId& GetAccountId() override {
-    return chromeos::ProfileHelper::Get()
+    return ash::ProfileHelper::Get()
         ->GetUserByProfile(profile_)
         ->GetAccountId();
   }
@@ -1024,7 +1024,7 @@
 bool DriveIntegrationService::DownloadDirectoryPreferenceIsInDrive() {
   const auto downloads_path =
       profile_->GetPrefs()->GetFilePath(::prefs::kDownloadDefaultDirectory);
-  const auto* user = chromeos::ProfileHelper::Get()->GetUserByProfile(profile_);
+  const auto* user = ash::ProfileHelper::Get()->GetUserByProfile(profile_);
   return user && user->GetAccountId().HasAccountIdKey() &&
          GetMountPointPath().IsParent(downloads_path);
 }
diff --git a/chrome/browser/ash/drive/drive_integration_service_unittest.cc b/chrome/browser/ash/drive/drive_integration_service_unittest.cc
index dd32d69d..f5539f3 100644
--- a/chrome/browser/ash/drive/drive_integration_service_unittest.cc
+++ b/chrome/browser/ash/drive/drive_integration_service_unittest.cc
@@ -24,7 +24,7 @@
   content::BrowserTaskEnvironment task_environment_;
   // DriveIntegrationService depends on DriveNotificationManager which depends
   // on InvalidationService. On Chrome OS, the InvalidationServiceFactory
-  // uses chromeos::ProfileHelper, which needs the ProfileManager or a
+  // uses ash::ProfileHelper, which needs the ProfileManager or a
   // TestProfileManager to be running.
   TestingProfileManager profile_manager_;
 };
diff --git a/chrome/browser/ash/drive/drivefs_test_support.cc b/chrome/browser/ash/drive/drivefs_test_support.cc
index 6a92a15..e9c1a7c 100644
--- a/chrome/browser/ash/drive/drivefs_test_support.cc
+++ b/chrome/browser/ash/drive/drivefs_test_support.cc
@@ -32,7 +32,7 @@
       drive::FakeDriveFsHelper::kPredefinedProfileSalt);
   fake_drivefs_.RegisterMountingForAccountId(
       base::BindLambdaForTesting([profile]() {
-        auto* user = chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+        auto* user = ash::ProfileHelper::Get()->GetUserByProfile(profile);
         if (!user)
           return std::string();
 
diff --git a/chrome/browser/ash/drive/file_system_util.cc b/chrome/browser/ash/drive/file_system_util.cc
index b578a48..4f73277 100644
--- a/chrome/browser/ash/drive/file_system_util.cc
+++ b/chrome/browser/ash/drive/file_system_util.cc
@@ -86,7 +86,7 @@
   if (profile->IsOffTheRecord())
     return false;
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   if (!user || !user->HasGaiaAccount())
     return false;
 
diff --git a/chrome/browser/ash/file_manager/arc_file_tasks.cc b/chrome/browser/ash/file_manager/arc_file_tasks.cc
index 9942417e..6c3657d 100644
--- a/chrome/browser/ash/file_manager/arc_file_tasks.cc
+++ b/chrome/browser/ash/file_manager/arc_file_tasks.cc
@@ -205,7 +205,7 @@
 
   arc::mojom::IntentHelperInstance* arc_intent_helper = nullptr;
   // File manager in secondary profile cannot access ARC.
-  if (chromeos::ProfileHelper::IsPrimaryProfile(profile)) {
+  if (ash::ProfileHelper::IsPrimaryProfile(profile)) {
     auto* arc_service_manager = arc::ArcServiceManager::Get();
     if (arc_service_manager) {
       arc_intent_helper = ARC_GET_INSTANCE_FOR_METHOD(
@@ -268,7 +268,7 @@
   }
 
   // File manager in secondary profile cannot access ARC.
-  if (!chromeos::ProfileHelper::IsPrimaryProfile(profile)) {
+  if (!ash::ProfileHelper::IsPrimaryProfile(profile)) {
     std::move(done).Run(
         extensions::api::file_manager_private::TASK_RESULT_FAILED,
         "Not primary profile");
diff --git a/chrome/browser/ash/file_manager/external_filesystem_apitest.cc b/chrome/browser/ash/file_manager/external_filesystem_apitest.cc
index 2d9c5445..8ef25c2 100644
--- a/chrome/browser/ash/file_manager/external_filesystem_apitest.cc
+++ b/chrome/browser/ash/file_manager/external_filesystem_apitest.cc
@@ -491,9 +491,9 @@
   drive::DriveIntegrationService* CreateDriveIntegrationService(
       Profile* profile) {
     // Ignore signin and lock screen apps profile.
-    if (profile->GetPath() == chromeos::ProfileHelper::GetSigninProfileDir() ||
+    if (profile->GetPath() == ash::ProfileHelper::GetSigninProfileDir() ||
         profile->GetPath() ==
-            chromeos::ProfileHelper::GetLockScreenAppProfilePath()) {
+            ash::ProfileHelper::GetLockScreenAppProfilePath()) {
       return nullptr;
     }
 
@@ -541,10 +541,8 @@
                                        kSecondProfileGiaId),
         kSecondProfileHash, false);
     // Set up the secondary profile.
-    base::FilePath profile_dir =
-        user_data_directory.Append(
-            chromeos::ProfileHelper::GetUserProfileDir(
-                kSecondProfileHash).BaseName());
+    base::FilePath profile_dir = user_data_directory.Append(
+        ash::ProfileHelper::GetUserProfileDir(kSecondProfileHash).BaseName());
     second_profile_ =
         g_browser_process->profile_manager()->GetProfile(profile_dir);
 
@@ -574,9 +572,9 @@
   drive::DriveIntegrationService* CreateDriveIntegrationService(
       Profile* profile) {
     // Ignore signin and lock screen apps profile.
-    if (profile->GetPath() == chromeos::ProfileHelper::GetSigninProfileDir() ||
+    if (profile->GetPath() == ash::ProfileHelper::GetSigninProfileDir() ||
         profile->GetPath() ==
-            chromeos::ProfileHelper::GetLockScreenAppProfilePath()) {
+            ash::ProfileHelper::GetLockScreenAppProfilePath()) {
       return nullptr;
     }
 
@@ -660,9 +658,9 @@
   drive::DriveIntegrationService* CreateDriveIntegrationService(
       Profile* profile) {
     // Ignore signin and lock screen apps profile.
-    if (profile->GetPath() == chromeos::ProfileHelper::GetSigninProfileDir() ||
+    if (profile->GetPath() == ash::ProfileHelper::GetSigninProfileDir() ||
         profile->GetPath() ==
-            chromeos::ProfileHelper::GetLockScreenAppProfilePath()) {
+            ash::ProfileHelper::GetLockScreenAppProfilePath()) {
       return nullptr;
     }
 
diff --git a/chrome/browser/ash/file_manager/file_manager_test_util.cc b/chrome/browser/ash/file_manager/file_manager_test_util.cc
index 1e84e89..591ee9d 100644
--- a/chrome/browser/ash/file_manager/file_manager_test_util.cc
+++ b/chrome/browser/ash/file_manager/file_manager_test_util.cc
@@ -128,7 +128,7 @@
               ->component_loader()
               ->Exists(kFileManagerAppId));
     CHECK(!extensions::ExtensionSystem::Get(
-               chromeos::ProfileHelper::GetSigninProfile())
+               ash::ProfileHelper::GetSigninProfile())
                ->extension_service()
                ->component_loader()
                ->Exists(kFileManagerAppId));
diff --git a/chrome/browser/ash/file_manager/open_with_browser_browsertest.cc b/chrome/browser/ash/file_manager/open_with_browser_browsertest.cc
new file mode 100644
index 0000000..e5e88326
--- /dev/null
+++ b/chrome/browser/ash/file_manager/open_with_browser_browsertest.cc
@@ -0,0 +1,153 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/constants/ash_features.h"
+#include "base/path_service.h"
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/ash/file_manager/open_with_browser.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/web_applications/test/profile_test_helper.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/test_navigation_observer.h"
+#include "net/base/filename_util.h"
+
+namespace file_manager {
+namespace util {
+
+namespace {
+
+// Returns full test file path to the given |file_name|.
+base::FilePath GetTestFilePath(const std::string& file_name) {
+  // Get the path to file manager's test data directory.
+  base::FilePath source_dir;
+  CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &source_dir));
+  base::FilePath test_data_dir = source_dir.AppendASCII("chrome")
+                                     .AppendASCII("test")
+                                     .AppendASCII("data")
+                                     .AppendASCII("chromeos")
+                                     .AppendASCII("file_manager");
+  return test_data_dir.Append(base::FilePath::FromUTF8Unsafe(file_name));
+}
+
+}  // namespace
+
+// Profile type to test. Provided to OpenWithBrowserBrowserTest via
+// profile_type().
+enum class TestProfileType {
+  kRegular,
+  kIncognito,
+  kGuest,
+};
+
+struct TestCase {
+  explicit TestCase(const TestProfileType profile_type)
+      : profile_type(profile_type) {}
+
+  // Show the startup browser. Navigating to a URL should work whether a browser
+  // window is already opened or not. Provided to OpenWithBrowserBrowserTest via
+  // startup_browser().
+  TestCase& WithStartupBrowser() {
+    startup_browser = true;
+    return *this;
+  }
+
+  TestProfileType profile_type;
+  bool startup_browser = false;
+};
+
+std::string PostTestCaseName(const ::testing::TestParamInfo<TestCase>& test) {
+  std::string result;
+  switch (test.param.profile_type) {
+    case TestProfileType::kRegular:
+      result = "Regular";
+      break;
+    case TestProfileType::kIncognito:
+      result = "Incognito";
+      break;
+    case TestProfileType::kGuest:
+      result = "Guest";
+      break;
+  }
+
+  if (test.param.startup_browser) {
+    result += "_WithStartupBrowser";
+  }
+
+  return result;
+}
+
+class OpenWithBrowserBrowserTest
+    : public InProcessBrowserTest,
+      public ::testing::WithParamInterface<TestCase> {
+ public:
+  OpenWithBrowserBrowserTest() {
+    scoped_feature_list_.InitWithFeatures(
+        {}, /*disabled_features=*/{ash::features::kLacrosPrimary});
+  }
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    if (profile_type() == TestProfileType::kGuest) {
+      ConfigureCommandLineForGuestMode(command_line);
+    } else if (profile_type() == TestProfileType::kIncognito) {
+      command_line->AppendSwitch(::switches::kIncognito);
+    }
+    if (!startup_browser()) {
+      command_line->AppendSwitch(::switches::kNoStartupWindow);
+    }
+    InProcessBrowserTest::SetUpCommandLine(command_line);
+  }
+
+  TestProfileType profile_type() const { return GetParam().profile_type; }
+
+  bool startup_browser() const { return GetParam().startup_browser; }
+
+  Profile* profile() const {
+    if (browser())
+      return browser()->profile();
+    return ProfileManager::GetActiveUserProfile();
+  }
+
+ protected:
+  storage::FileSystemURL PathToFileSystemURL(base::FilePath path) {
+    return storage::FileSystemURL::CreateForTest(
+        kTestStorageKey, storage::kFileSystemTypeExternal, path);
+  }
+
+  const blink::StorageKey kTestStorageKey =
+      blink::StorageKey::CreateFromStringForTesting("chrome://file-manager");
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_P(OpenWithBrowserBrowserTest, OpenTextFile) {
+  // For a given txt file, generate its FileSystemURL.
+  const base::FilePath test_file_path = GetTestFilePath("text.txt");
+  storage::FileSystemURL test_file_url = PathToFileSystemURL(test_file_path);
+
+  // file: URL of the test file, as opened in the browser.
+  GURL page_url = net::FilePathToFileURL(test_file_url.path());
+  content::TestNavigationObserver navigation_observer(page_url);
+  navigation_observer.StartWatchingNewWebContents();
+  OpenFileWithBrowser(profile(), test_file_url, "view-in-browser");
+  navigation_observer.Wait();
+  ASSERT_TRUE(navigation_observer.last_navigation_succeeded());
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    OpenWithBrowserBrowserTest,
+    ::testing::Values(
+        TestCase(TestProfileType::kRegular),
+        TestCase(TestProfileType::kRegular).WithStartupBrowser(),
+        TestCase(TestProfileType::kIncognito),
+        TestCase(TestProfileType::kIncognito).WithStartupBrowser(),
+        TestCase(TestProfileType::kGuest),
+        TestCase(TestProfileType::kGuest).WithStartupBrowser()),
+    &PostTestCaseName);
+
+}  // namespace util
+}  // namespace file_manager
diff --git a/chrome/browser/ash/file_manager/path_util.cc b/chrome/browser/ash/file_manager/path_util.cc
index 6f3a7fdd..90a1dbc 100644
--- a/chrome/browser/ash/file_manager/path_util.cc
+++ b/chrome/browser/ash/file_manager/path_util.cc
@@ -117,7 +117,7 @@
   if (!base::SysInfo::IsRunningOnChromeOS() &&
       user_manager::UserManager::IsInitialized()) {
     const user_manager::User* const user =
-        chromeos::ProfileHelper::Get()->GetUserByProfile(
+        ash::ProfileHelper::Get()->GetUserByProfile(
             profile->GetOriginalProfile());
     const user_manager::User* const primary_user =
         user_manager::UserManager::Get()->GetPrimaryUser();
@@ -306,7 +306,7 @@
 bool MigrateToDriveFs(Profile* profile,
                       const base::FilePath& old_path,
                       base::FilePath* new_path) {
-  const auto* user = chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+  const auto* user = ash::ProfileHelper::Get()->GetUserByProfile(profile);
   auto* integration_service =
       drive::DriveIntegrationServiceFactory::FindForProfile(profile);
   if (!integration_service || !integration_service->is_enabled() || !user ||
@@ -325,7 +325,7 @@
   // because such a profile never belongs to a multi-profile session.
   const user_manager::User* const user =
       user_manager::UserManager::IsInitialized()
-          ? chromeos::ProfileHelper::Get()->GetUserByProfile(
+          ? ash::ProfileHelper::Get()->GetUserByProfile(
                 profile->GetOriginalProfile())
           : nullptr;
   const std::string id = user ? "-" + user->username_hash() : "";
diff --git a/chrome/browser/ash/file_manager/path_util_unittest.cc b/chrome/browser/ash/file_manager/path_util_unittest.cc
index 709dd9f1..3305136 100644
--- a/chrome/browser/ash/file_manager/path_util_unittest.cc
+++ b/chrome/browser/ash/file_manager/path_util_unittest.cc
@@ -707,7 +707,7 @@
   GURL url;
   bool requires_sharing = false;
   const base::FilePath myfiles = GetMyFilesFolderForProfile(
-      chromeos::ProfileHelper::Get()->GetProfileByUserIdHashForTest(
+      ash::ProfileHelper::Get()->GetProfileByUserIdHashForTest(
           "user@gmail.com-hash"));
   EXPECT_TRUE(ConvertPathToArcUrl(myfiles.AppendASCII("a/b/c"), &url,
                                   &requires_sharing));
@@ -734,7 +734,7 @@
   GURL url;
   bool requires_sharing = false;
   const base::FilePath downloads2 = GetDownloadsFolderForProfile(
-      chromeos::ProfileHelper::Get()->GetProfileByUserIdHashForTest(
+      ash::ProfileHelper::Get()->GetProfileByUserIdHashForTest(
           "user2@gmail.com-hash"));
   EXPECT_FALSE(ConvertPathToArcUrl(downloads2.AppendASCII("a/b/c"), &url,
                                    &requires_sharing));
@@ -843,7 +843,7 @@
 TEST_F(FileManagerPathUtilConvertUrlTest, ConvertToContentUrls_MyFiles) {
   base::test::ScopedRunningOnChromeOS running_on_chromeos;
   const base::FilePath myfiles = GetMyFilesFolderForProfile(
-      chromeos::ProfileHelper::Get()->GetProfileByUserIdHashForTest(
+      ash::ProfileHelper::Get()->GetProfileByUserIdHashForTest(
           "user@gmail.com-hash"));
   base::RunLoop run_loop;
   ConvertToContentUrls(
@@ -884,7 +884,7 @@
 
 TEST_F(FileManagerPathUtilConvertUrlTest, ConvertToContentUrls_Downloads) {
   const base::FilePath downloads = GetDownloadsFolderForProfile(
-      chromeos::ProfileHelper::Get()->GetProfileByUserIdHashForTest(
+      ash::ProfileHelper::Get()->GetProfileByUserIdHashForTest(
           "user@gmail.com-hash"));
   base::RunLoop run_loop;
   ConvertToContentUrls(
@@ -908,7 +908,7 @@
 TEST_F(FileManagerPathUtilConvertUrlTest,
        ConvertToContentUrls_InvalidDownloads) {
   const base::FilePath downloads = GetDownloadsFolderForProfile(
-      chromeos::ProfileHelper::Get()->GetProfileByUserIdHashForTest(
+      ash::ProfileHelper::Get()->GetProfileByUserIdHashForTest(
           "user2@gmail.com-hash"));
   base::RunLoop run_loop;
   ConvertToContentUrls(
diff --git a/chrome/browser/ash/file_manager/volume_manager.cc b/chrome/browser/ash/file_manager/volume_manager.cc
index c27db79..4cc55a0 100644
--- a/chrome/browser/ash/file_manager/volume_manager.cc
+++ b/chrome/browser/ash/file_manager/volume_manager.cc
@@ -537,7 +537,7 @@
 void VolumeManager::Initialize() {
   // If in the Sign in profile or the lock screen app profile or lock screen
   // profile, skip mounting and listening for mount events.
-  if (!chromeos::ProfileHelper::IsRegularProfile(profile_)) {
+  if (!ash::ProfileHelper::IsRegularProfile(profile_)) {
     return;
   }
 
diff --git a/chrome/browser/ash/file_manager/volume_manager_unittest.cc b/chrome/browser/ash/file_manager/volume_manager_unittest.cc
index e445cd1..d8603b2 100644
--- a/chrome/browser/ash/file_manager/volume_manager_unittest.cc
+++ b/chrome/browser/ash/file_manager/volume_manager_unittest.cc
@@ -252,8 +252,8 @@
               AccountId::FromUserEmailGaiaId(profile_->GetProfileUserName(),
                                              "id")),
           user_(account_id_) {
-      chromeos::ProfileHelper::Get()->SetProfileToUserMappingForTesting(&user_);
-      chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
+      ash::ProfileHelper::Get()->SetProfileToUserMappingForTesting(&user_);
+      ash::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
           &user_, profile_.get());
     }
 
diff --git a/chrome/browser/ash/lock_screen_apps/app_manager_impl.cc b/chrome/browser/ash/lock_screen_apps/app_manager_impl.cc
index c40a907..3edea077 100644
--- a/chrome/browser/ash/lock_screen_apps/app_manager_impl.cc
+++ b/chrome/browser/ash/lock_screen_apps/app_manager_impl.cc
@@ -206,7 +206,7 @@
   lock_screen_profile_ =
       lock_screen_profile_creator_->lock_screen_profile()->GetOriginalProfile();
 
-  CHECK(!chromeos::ProfileHelper::Get()->GetUserByProfile(lock_screen_profile_))
+  CHECK(!ash::ProfileHelper::Get()->GetUserByProfile(lock_screen_profile_))
       << "Lock screen profile should not be associated with any users.";
 
   UpdateLockScreenAppState();
diff --git a/chrome/browser/ash/lock_screen_apps/fake_lock_screen_profile_creator.cc b/chrome/browser/ash/lock_screen_apps/fake_lock_screen_profile_creator.cc
index 774608b..2425d75 100644
--- a/chrome/browser/ash/lock_screen_apps/fake_lock_screen_profile_creator.cc
+++ b/chrome/browser/ash/lock_screen_apps/fake_lock_screen_profile_creator.cc
@@ -24,7 +24,7 @@
   OnLockScreenProfileCreateStarted();
 
   Profile* profile = profile_manager_->CreateTestingProfile(
-      chromeos::ProfileHelper::GetLockScreenAppProfileName());
+      ash::ProfileHelper::GetLockScreenAppProfileName());
 
   extensions::TestExtensionSystem* extension_system =
       static_cast<extensions::TestExtensionSystem*>(
diff --git a/chrome/browser/ash/lock_screen_apps/lock_screen_profile_creator_impl.cc b/chrome/browser/ash/lock_screen_apps/lock_screen_profile_creator_impl.cc
index 8d0e223..43e3652 100644
--- a/chrome/browser/ash/lock_screen_apps/lock_screen_profile_creator_impl.cc
+++ b/chrome/browser/ash/lock_screen_apps/lock_screen_profile_creator_impl.cc
@@ -55,7 +55,7 @@
   OnLockScreenProfileCreateStarted();
 
   g_browser_process->profile_manager()->CreateProfileAsync(
-      chromeos::ProfileHelper::GetLockScreenAppProfilePath(),
+      ash::ProfileHelper::GetLockScreenAppProfilePath(),
       base::BindRepeating(&LockScreenProfileCreatorImpl::OnProfileReady,
                           weak_ptr_factory_.GetWeakPtr(),
                           tick_clock_->NowTicks()));
diff --git a/chrome/browser/ash/lock_screen_apps/lock_screen_profile_creator_impl_unittest.cc b/chrome/browser/ash/lock_screen_apps/lock_screen_profile_creator_impl_unittest.cc
index 16def46..74d2d83 100644
--- a/chrome/browser/ash/lock_screen_apps/lock_screen_profile_creator_impl_unittest.cc
+++ b/chrome/browser/ash/lock_screen_apps/lock_screen_profile_creator_impl_unittest.cc
@@ -47,7 +47,7 @@
 
 namespace {
 
-using chromeos::ProfileHelper;
+using ::ash::ProfileHelper;
 using extensions::DictionaryBuilder;
 using extensions::ListBuilder;
 using lock_screen_apps::LockScreenProfileCreator;
diff --git a/chrome/browser/ash/lock_screen_apps/state_controller.cc b/chrome/browser/ash/lock_screen_apps/state_controller.cc
index 2dc31e8..143fd37 100644
--- a/chrome/browser/ash/lock_screen_apps/state_controller.cc
+++ b/chrome/browser/ash/lock_screen_apps/state_controller.cc
@@ -138,7 +138,7 @@
 
 void StateController::SetPrimaryProfile(Profile* profile) {
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   if (!user || !user->HasGaiaAccount()) {
     if (!ready_callback_.is_null())
       std::move(ready_callback_).Run();
@@ -156,8 +156,8 @@
     base::FilePath base_path;
     base::PathService::Get(chrome::DIR_USER_DATA, &base_path);
     base_path = base_path.AppendASCII("web_lock_screen_api_data");
-    base_path = base_path.Append(
-        chromeos::ProfileHelper::GetUserIdHashFromProfile(profile));
+    base_path =
+        base_path.Append(ash::ProfileHelper::GetUserIdHashFromProfile(profile));
     content::LockScreenStorage::GetInstance()->Init(profile, base_path);
   }
 }
diff --git a/chrome/browser/ash/login/demo_mode/demo_setup_browsertest.cc b/chrome/browser/ash/login/demo_mode/demo_setup_browsertest.cc
index 51cc3d5..8f5549e 100644
--- a/chrome/browser/ash/login/demo_mode/demo_setup_browsertest.cc
+++ b/chrome/browser/ash/login/demo_mode/demo_setup_browsertest.cc
@@ -520,7 +520,9 @@
 
   AcceptTermsAndExpectDemoSetupProgress();
 
-  EXPECT_TRUE(DemoSetupController::GetSubOrganizationEmail().empty());
+  // Verify the email corresponds to US.
+  EXPECT_EQ("admin-us@cros-demo-mode.com",
+            DemoSetupController::GetSubOrganizationEmail());
 
   OobeScreenWaiter(GetFirstSigninScreen()).Wait();
 
diff --git a/chrome/browser/ash/login/demo_mode/demo_setup_controller.cc b/chrome/browser/ash/login/demo_mode/demo_setup_controller.cc
index 0c10387..e3953cf 100644
--- a/chrome/browser/ash/login/demo_mode/demo_setup_controller.cc
+++ b/chrome/browser/ash/login/demo_mode/demo_setup_controller.cc
@@ -506,11 +506,10 @@
   std::string country_lowercase = base::ToLowerASCII(country);
 
   // Exclude US as it is the default country.
-  if (country_uppercase != "US" &&
-      std::find(std::begin(DemoSession::kSupportedCountries),
+  if (std::find(std::begin(DemoSession::kSupportedCountries),
                 std::end(DemoSession::kSupportedCountries),
                 country_uppercase) !=
-          std::end(DemoSession::kSupportedCountries)) {
+      std::end(DemoSession::kSupportedCountries)) {
     return "admin-" + country_lowercase + "@" + policy::kDemoModeDomain;
   }
   return std::string();
diff --git a/chrome/browser/ash/login/demo_mode/demo_setup_controller_unittest.cc b/chrome/browser/ash/login/demo_mode/demo_setup_controller_unittest.cc
index 273cf65f..fa90a0cb 100644
--- a/chrome/browser/ash/login/demo_mode/demo_setup_controller_unittest.cc
+++ b/chrome/browser/ash/login/demo_mode/demo_setup_controller_unittest.cc
@@ -399,13 +399,13 @@
 TEST_F(DemoSetupControllerTest, GetSubOrganizationEmail) {
   std::string email = DemoSetupController::GetSubOrganizationEmail();
 
-  // kDemoModeCountry defaults to "US" which is the root organisation.
-  EXPECT_EQ(email, "");
+  // kDemoModeCountry defaults to "US".
+  EXPECT_EQ(email, "admin-us@cros-demo-mode.com");
 
   // Test other supported countries.
   const std::string testing_supported_countries[] = {
-      "BE", "CA", "DK", "FI", "FR", "DE", "IE", "IT",
-      "JP", "LU", "NL", "NO", "ES", "SE", "GB"};
+      "US", "BE", "CA", "DK", "FI", "FR", "DE", "IE",
+      "IT", "JP", "LU", "NL", "NO", "ES", "SE", "GB"};
 
   for (auto country : testing_supported_countries) {
     g_browser_process->local_state()->SetString(prefs::kDemoModeCountry,
@@ -437,13 +437,13 @@
 TEST_F(DemoSetupControllerTest, GetSubOrganizationEmailWithLowercase) {
   std::string email = DemoSetupController::GetSubOrganizationEmail();
 
-  // kDemoModeCountry defaults to "US" which is the root organisation.
-  EXPECT_EQ(email, "");
+  // kDemoModeCountry defaults to "US".
+  EXPECT_EQ(email, "admin-us@cros-demo-mode.com");
 
   // Test other supported countries.
   const std::string testing_supported_countries[] = {
-      "be", "ca", "dk", "fi", "fr", "de", "ie", "it",
-      "jp", "lu", "nl", "no", "es", "se", "gb"};
+      "us", "be", "ca", "dk", "fi", "fr", "de", "ie",
+      "it", "jp", "lu", "nl", "no", "es", "se", "gb"};
 
   for (auto country : testing_supported_countries) {
     g_browser_process->local_state()->SetString(prefs::kDemoModeCountry,
diff --git a/chrome/browser/ash/login/existing_user_controller.cc b/chrome/browser/ash/login/existing_user_controller.cc
index 8079f64..2cbe7e1 100644
--- a/chrome/browser/ash/login/existing_user_controller.cc
+++ b/chrome/browser/ash/login/existing_user_controller.cc
@@ -260,7 +260,7 @@
   const user_manager::User* user =
       user_manager::UserManager::Get()->FindUser(account_id);
   DCHECK(user);
-  Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+  Profile* profile = ProfileHelper::Get()->GetProfileByUser(user);
   DCHECK(profile);
   PrefService* prefs = profile->GetPrefs();
   prefs->SetString(::prefs::kLoginExtensionApiLaunchExtensionId, extension_id);
diff --git a/chrome/browser/ash/login/reporting/login_logout_reporter.cc b/chrome/browser/ash/login/reporting/login_logout_reporter.cc
index 4b57d25..0416af21 100644
--- a/chrome/browser/ash/login/reporting/login_logout_reporter.cc
+++ b/chrome/browser/ash/login/reporting/login_logout_reporter.cc
@@ -128,8 +128,7 @@
 }
 
 void LoginLogoutReporter::OnLogin(Profile* profile) {
-  user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+  user_manager::User* user = ProfileHelper::Get()->GetUserByProfile(profile);
   if (user->IsKioskType()) {
     return;
   }
diff --git a/chrome/browser/ash/login/session/user_session_manager.cc b/chrome/browser/ash/login/session/user_session_manager.cc
index e92c5e4d..1a9ac8fc 100644
--- a/chrome/browser/ash/login/session/user_session_manager.cc
+++ b/chrome/browser/ash/login/session/user_session_manager.cc
@@ -2188,7 +2188,7 @@
     return;
 
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ProfileHelper::Get()->GetUserByProfile(profile);
   if (ash::BrowserDataMigratorImpl::MaybeRestartToMigrate(
           user->GetAccountId(), user->username_hash())) {
     LOG(WARNING) << "Restarting chrome to run profile migration.";
diff --git a/chrome/browser/ash/login/users/chrome_user_manager_impl.cc b/chrome/browser/ash/login/users/chrome_user_manager_impl.cc
index 897b2960..ebb19f08 100644
--- a/chrome/browser/ash/login/users/chrome_user_manager_impl.cc
+++ b/chrome/browser/ash/login/users/chrome_user_manager_impl.cc
@@ -283,7 +283,7 @@
   // Confirm that we hadn't loaded the new profile previously.
   base::FilePath user_profile_dir =
       g_browser_process->profile_manager()->user_data_dir().Append(
-          chromeos::ProfileHelper::Get()->GetActiveUserProfileDir());
+          ProfileHelper::Get()->GetActiveUserProfileDir());
   CHECK(
       !g_browser_process->profile_manager()->GetProfileByPath(user_profile_dir))
       << "The user profile was loaded before we mounted the cryptohome.";
diff --git a/chrome/browser/ash/login/users/fake_chrome_user_manager.cc b/chrome/browser/ash/login/users/fake_chrome_user_manager.cc
index bff9b02..7884088 100644
--- a/chrome/browser/ash/login/users/fake_chrome_user_manager.cc
+++ b/chrome/browser/ash/login/users/fake_chrome_user_manager.cc
@@ -115,7 +115,7 @@
               IDR_LOGIN_DEFAULT_USER)),
       user_manager::User::USER_IMAGE_PROFILE, false);
   users_.push_back(user);
-  chromeos::ProfileHelper::Get()->SetProfileToUserMappingForTesting(user);
+  ProfileHelper::Get()->SetProfileToUserMappingForTesting(user);
 
   if (profile) {
     ProfileHelper::Get()->SetUserToProfileMappingForTesting(user, profile);
@@ -173,7 +173,7 @@
               IDR_LOGIN_DEFAULT_USER)),
       user_manager::User::USER_IMAGE_PROFILE, false);
   users_.push_back(user);
-  chromeos::ProfileHelper::Get()->SetProfileToUserMappingForTesting(user);
+  ProfileHelper::Get()->SetProfileToUserMappingForTesting(user);
   return user;
 }
 
@@ -285,7 +285,7 @@
   // `wallpaper_client` could be nullptr in tests.
   if (wallpaper_client)
     wallpaper_client->RemoveUserWallpaper(account_id);
-  chromeos::ProfileHelper::Get()->RemoveUserFromListForTesting(account_id);
+  ProfileHelper::Get()->RemoveUserFromListForTesting(account_id);
 
   const user_manager::UserList::iterator it =
       std::find_if(users_.begin(), users_.end(),
diff --git a/chrome/browser/ash/note_taking_helper_unittest.cc b/chrome/browser/ash/note_taking_helper_unittest.cc
index a95d69e..1eef9e7 100644
--- a/chrome/browser/ash/note_taking_helper_unittest.cc
+++ b/chrome/browser/ash/note_taking_helper_unittest.cc
@@ -1604,8 +1604,7 @@
       kSecondProfileName, std::move(prefs),
       base::UTF8ToUTF16(kSecondProfileName), 1 /*avatar_id*/,
       std::string() /*supervised_user_id*/, TestingProfile::TestingFactories());
-  chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
-      user, second_profile);
+  ProfileHelper::Get()->SetUserToProfileMappingForTesting(user, second_profile);
   InitExtensionService(second_profile);
 
   // Add test apps to secondary profile.
diff --git a/chrome/browser/ash/plugin_vm/plugin_vm_diagnostics.cc b/chrome/browser/ash/plugin_vm/plugin_vm_diagnostics.cc
index cf4b4a6..58517536 100644
--- a/chrome/browser/ash/plugin_vm/plugin_vm_diagnostics.cc
+++ b/chrome/browser/ash/plugin_vm/plugin_vm_diagnostics.cc
@@ -184,7 +184,7 @@
 
     vm_tools::concierge::ListVmDisksRequest request;
     request.set_cryptohome_id(
-        chromeos::ProfileHelper::GetUserIdHashFromProfile(active_profile_));
+        ash::ProfileHelper::GetUserIdHashFromProfile(active_profile_));
     request.set_storage_location(
         vm_tools::concierge::STORAGE_CRYPTOHOME_PLUGINVM);
 
diff --git a/chrome/browser/ash/plugin_vm/plugin_vm_features.cc b/chrome/browser/ash/plugin_vm/plugin_vm_features.cc
index b454b971..011c26e 100644
--- a/chrome/browser/ash/plugin_vm/plugin_vm_features.cc
+++ b/chrome/browser/ash/plugin_vm/plugin_vm_features.cc
@@ -30,7 +30,7 @@
     return ProfileSupported::kErrorNotSupported;
   }
 
-  if (!chromeos::ProfileHelper::IsPrimaryProfile(profile)) {
+  if (!ash::ProfileHelper::IsPrimaryProfile(profile)) {
     return ProfileSupported::kErrorNonPrimary;
   }
 
@@ -42,11 +42,11 @@
     return ProfileSupported::kErrorOffTheRecord;
   }
 
-  if (chromeos::ProfileHelper::IsEphemeralUserProfile(profile)) {
+  if (ash::ProfileHelper::IsEphemeralUserProfile(profile)) {
     return ProfileSupported::kErrorEphemeral;
   }
 
-  if (!chromeos::ProfileHelper::IsRegularProfile(profile)) {
+  if (!ash::ProfileHelper::IsRegularProfile(profile)) {
     VLOG(1) << "non-regular profile is not supported";
     // If this happens, the profile is for something like the sign in screen or
     // lock screen. Return a generic error code because the user will not be
@@ -75,7 +75,7 @@
 
   // Check that the user is affiliated.
   const user_manager::User* const user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   if (user == nullptr || !user->IsAffiliated()) {
     return PolicyConfigured::kErrorUserNotAffiliated;
   }
diff --git a/chrome/browser/ash/plugin_vm/plugin_vm_files.cc b/chrome/browser/ash/plugin_vm/plugin_vm_files.cc
index 8dbda9f6..076aa4a 100644
--- a/chrome/browser/ash/plugin_vm/plugin_vm_files.cc
+++ b/chrome/browser/ash/plugin_vm/plugin_vm_files.cc
@@ -98,8 +98,7 @@
   }
 
   vm_tools::cicerone::LaunchContainerApplicationRequest request;
-  request.set_owner_id(
-      chromeos::ProfileHelper::GetUserIdHashFromProfile(profile));
+  request.set_owner_id(ash::ProfileHelper::GetUserIdHashFromProfile(profile));
   request.set_vm_name(registration->VmName());
   request.set_container_name(registration->ContainerName());
   request.set_desktop_file_id(registration->DesktopFileId());
diff --git a/chrome/browser/ash/plugin_vm/plugin_vm_installer.cc b/chrome/browser/ash/plugin_vm/plugin_vm_installer.cc
index 5119113..840b6448 100644
--- a/chrome/browser/ash/plugin_vm/plugin_vm_installer.cc
+++ b/chrome/browser/ash/plugin_vm/plugin_vm_installer.cc
@@ -392,7 +392,7 @@
 
   vm_tools::concierge::ListVmDisksRequest request;
   request.set_cryptohome_id(
-      chromeos::ProfileHelper::GetUserIdHashFromProfile(profile_));
+      ash::ProfileHelper::GetUserIdHashFromProfile(profile_));
   request.set_storage_location(
       vm_tools::concierge::STORAGE_CRYPTOHOME_PLUGINVM);
   request.set_vm_name(kPluginVmName);
@@ -664,7 +664,7 @@
   if (creating_new_vm_) {
     vm_tools::concierge::CreateDiskImageRequest request;
     request.set_cryptohome_id(
-        chromeos::ProfileHelper::GetUserIdHashFromProfile(profile_));
+        ash::ProfileHelper::GetUserIdHashFromProfile(profile_));
     request.set_vm_name(kPluginVmName);
     request.set_storage_location(
         vm_tools::concierge::STORAGE_CRYPTOHOME_PLUGINVM);
@@ -680,7 +680,7 @@
   } else {
     vm_tools::concierge::ImportDiskImageRequest request;
     request.set_cryptohome_id(
-        chromeos::ProfileHelper::GetUserIdHashFromProfile(profile_));
+        ash::ProfileHelper::GetUserIdHashFromProfile(profile_));
     request.set_vm_name(kPluginVmName);
     request.set_storage_location(
         vm_tools::concierge::STORAGE_CRYPTOHOME_PLUGINVM);
diff --git a/chrome/browser/ash/plugin_vm/plugin_vm_manager_impl.cc b/chrome/browser/ash/plugin_vm/plugin_vm_manager_impl.cc
index 1c92fe8c..030a41fd 100644
--- a/chrome/browser/ash/plugin_vm/plugin_vm_manager_impl.cc
+++ b/chrome/browser/ash/plugin_vm/plugin_vm_manager_impl.cc
@@ -120,7 +120,7 @@
 
 PluginVmManagerImpl::PluginVmManagerImpl(Profile* profile)
     : profile_(profile),
-      owner_id_(chromeos::ProfileHelper::GetUserIdHashFromProfile(profile)) {
+      owner_id_(ash::ProfileHelper::GetUserIdHashFromProfile(profile)) {
   chromeos::DBusThreadManager::Get()
       ->GetVmPluginDispatcherClient()
       ->AddObserver(this);
diff --git a/chrome/browser/ash/plugin_vm/plugin_vm_manager_impl_unittest.cc b/chrome/browser/ash/plugin_vm/plugin_vm_manager_impl_unittest.cc
index 03b9220..842f90a 100644
--- a/chrome/browser/ash/plugin_vm/plugin_vm_manager_impl_unittest.cc
+++ b/chrome/browser/ash/plugin_vm/plugin_vm_manager_impl_unittest.cc
@@ -113,8 +113,7 @@
       vm_tools::plugin_dispatcher::VmToolsState state) {
     vm_tools::plugin_dispatcher::VmToolsStateChangedSignal state_changed_signal;
     state_changed_signal.set_owner_id(
-        chromeos::ProfileHelper::GetUserIdHashFromProfile(
-            testing_profile_.get()));
+        ash::ProfileHelper::GetUserIdHashFromProfile(testing_profile_.get()));
     state_changed_signal.set_vm_name(kPluginVmName);
     state_changed_signal.set_vm_tools_state(state);
     VmPluginDispatcherClient().NotifyVmToolsStateChanged(state_changed_signal);
@@ -123,8 +122,7 @@
   void NotifyVmStateChanged(vm_tools::plugin_dispatcher::VmState state) {
     vm_tools::plugin_dispatcher::VmStateChangedSignal state_changed_signal;
     state_changed_signal.set_owner_id(
-        chromeos::ProfileHelper::GetUserIdHashFromProfile(
-            testing_profile_.get()));
+        ash::ProfileHelper::GetUserIdHashFromProfile(testing_profile_.get()));
     state_changed_signal.set_vm_name(kPluginVmName);
     state_changed_signal.set_vm_state(state);
     VmPluginDispatcherClient().NotifyVmStateChanged(state_changed_signal);
diff --git a/chrome/browser/ash/policy/arc/unaffiliated_arc_allowed_browsertest.cc b/chrome/browser/ash/policy/arc/unaffiliated_arc_allowed_browsertest.cc
index 9364609..832fcdb 100644
--- a/chrome/browser/ash/policy/arc/unaffiliated_arc_allowed_browsertest.cc
+++ b/chrome/browser/ash/policy/arc/unaffiliated_arc_allowed_browsertest.cc
@@ -96,8 +96,7 @@
   AffiliationTestHelper::LoginUser(affiliation_mixin_.account_id());
   const user_manager::User* user = user_manager::UserManager::Get()->FindUser(
       affiliation_mixin_.account_id());
-  const Profile* profile =
-      chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+  const Profile* profile = ash::ProfileHelper::Get()->GetProfileByUser(user);
   const bool affiliated = GetParam().affiliated;
 
   EXPECT_EQ(affiliated, user->IsAffiliated());
diff --git a/chrome/browser/ash/policy/core/device_local_account_browsertest.cc b/chrome/browser/ash/policy/core/device_local_account_browsertest.cc
index 6afd459..467631a 100644
--- a/chrome/browser/ash/policy/core/device_local_account_browsertest.cc
+++ b/chrome/browser/ash/policy/core/device_local_account_browsertest.cc
@@ -797,7 +797,7 @@
   // ProfileManagerObserver:
   void OnProfileAdded(Profile* profile) override {
     // Ignore lock screen apps profile.
-    if (chromeos::ProfileHelper::IsLockScreenAppProfile(profile))
+    if (ash::ProfileHelper::IsLockScreenAppProfile(profile))
       return;
     registry_ = extensions::ExtensionRegistry::Get(profile);
     profile_manager_observer_.Reset();
diff --git a/chrome/browser/ash/policy/core/user_cloud_policy_manager_ash_unittest.cc b/chrome/browser/ash/policy/core/user_cloud_policy_manager_ash_unittest.cc
index cea52dd6..f483049 100644
--- a/chrome/browser/ash/policy/core/user_cloud_policy_manager_ash_unittest.cc
+++ b/chrome/browser/ash/policy/core/user_cloud_policy_manager_ash_unittest.cc
@@ -185,7 +185,7 @@
     // the signin Profile is an OTR Profile then for this test it suffices to
     // attach it to the main Profile.
     signin_profile_ = TestingProfile::Builder().BuildIncognito(profile_);
-    ASSERT_EQ(signin_profile_, chromeos::ProfileHelper::GetSigninProfile());
+    ASSERT_EQ(signin_profile_, ash::ProfileHelper::GetSigninProfile());
 
     RegisterLocalState(prefs_.registry());
 
@@ -407,7 +407,7 @@
     external_data_manager_->SetPolicyStore(store_);
     const user_manager::User* active_user = user_manager_->GetActiveUser();
     manager_ = std::make_unique<UserCloudPolicyManagerAsh>(
-        chromeos::ProfileHelper::Get()->GetProfileByUser(active_user),
+        ash::ProfileHelper::Get()->GetProfileByUser(active_user),
         std::move(store),
         base::WrapUnique<MockCloudExternalDataManager>(external_data_manager_),
         base::FilePath(), enforcement_type, fetch_timeout,
diff --git a/chrome/browser/ash/policy/core/user_policy_manager_builder_ash.cc b/chrome/browser/ash/policy/core/user_policy_manager_builder_ash.cc
index 966734e..55e4377e 100644
--- a/chrome/browser/ash/policy/core/user_policy_manager_builder_ash.cc
+++ b/chrome/browser/ash/policy/core/user_policy_manager_builder_ash.cc
@@ -92,7 +92,7 @@
   *active_directory_policy_manager_out = nullptr;
 
   // Don't initialize cloud policy for the signin and the lock screen profile.
-  if (!chromeos::ProfileHelper::IsRegularProfile(profile)) {
+  if (!ash::ProfileHelper::IsRegularProfile(profile)) {
     return;
   }
 
@@ -101,7 +101,7 @@
   // happens right after sign-in. The just-signed-in User is the active user
   // during that time.
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   CHECK(user);
 
   // User policy exists for enterprise accounts:
diff --git a/chrome/browser/ash/policy/external_data/cloud_external_data_policy_observer.cc b/chrome/browser/ash/policy/external_data/cloud_external_data_policy_observer.cc
index a257148..4923217 100644
--- a/chrome/browser/ash/policy/external_data/cloud_external_data_policy_observer.cc
+++ b/chrome/browser/ash/policy/external_data/cloud_external_data_policy_observer.cc
@@ -151,9 +151,9 @@
 void CloudExternalDataPolicyObserver::OnUserProfileLoaded(
     const AccountId& account_id) {
   Profile* profile =
-      chromeos::ProfileHelper::Get()->GetProfileByAccountId(account_id);
+      ash::ProfileHelper::Get()->GetProfileByAccountId(account_id);
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   if (!user) {
     NOTREACHED();
     return;
diff --git a/chrome/browser/ash/policy/external_data/cloud_external_data_policy_observer_unittest.cc b/chrome/browser/ash/policy/external_data/cloud_external_data_policy_observer_unittest.cc
index a93a406..28bee799 100644
--- a/chrome/browser/ash/policy/external_data/cloud_external_data_policy_observer_unittest.cc
+++ b/chrome/browser/ash/policy/external_data/cloud_external_data_policy_observer_unittest.cc
@@ -339,8 +339,8 @@
   std::unique_ptr<PolicyServiceImpl> policy_service =
       std::make_unique<PolicyServiceImpl>(std::move(providers));
   builder.SetPolicyService(std::move(policy_service));
-  builder.SetPath(chromeos::ProfileHelper::Get()->GetProfilePathByUserIdHash(
-      chromeos::ProfileHelper::GetUserIdHashByUserIdForTesting(
+  builder.SetPath(ash::ProfileHelper::Get()->GetProfilePathByUserIdHash(
+      ash::ProfileHelper::GetUserIdHashByUserIdForTesting(
           account_id.GetUserEmail())));
 
   profile_ = builder.Build();
@@ -373,9 +373,8 @@
   std::unique_ptr<PolicyServiceImpl> policy_service =
       std::make_unique<PolicyServiceImpl>(std::move(providers));
   builder.SetPolicyService(std::move(policy_service));
-  builder.SetPath(chromeos::ProfileHelper::Get()->GetProfilePathByUserIdHash(
-      chromeos::ProfileHelper::GetUserIdHashByUserIdForTesting(
-          kRegularUserID)));
+  builder.SetPath(ash::ProfileHelper::Get()->GetProfilePathByUserIdHash(
+      ash::ProfileHelper::GetUserIdHashByUserIdForTesting(kRegularUserID)));
 
   profile_ = builder.Build();
   profile_->set_profile_name(kRegularUserID);
diff --git a/chrome/browser/ash/policy/external_data/handlers/crostini_ansible_playbook_external_data_handler.cc b/chrome/browser/ash/policy/external_data/handlers/crostini_ansible_playbook_external_data_handler.cc
index 771d714..cb58d81f 100644
--- a/chrome/browser/ash/policy/external_data/handlers/crostini_ansible_playbook_external_data_handler.cc
+++ b/chrome/browser/ash/policy/external_data/handlers/crostini_ansible_playbook_external_data_handler.cc
@@ -31,8 +31,8 @@
 void CrostiniAnsiblePlaybookExternalDataHandler::OnExternalDataCleared(
     const std::string& policy,
     const std::string& user_id) {
-  Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByAccountId(
-      GetAccountId(user_id));
+  Profile* profile =
+      ash::ProfileHelper::Get()->GetProfileByAccountId(GetAccountId(user_id));
   if (!profile) {
     LOG(ERROR) << "No profile for user is specified";
     return;
@@ -48,8 +48,8 @@
     const std::string& user_id,
     std::unique_ptr<std::string> data,
     const base::FilePath& file_path) {
-  Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByAccountId(
-      GetAccountId(user_id));
+  Profile* profile =
+      ash::ProfileHelper::Get()->GetProfileByAccountId(GetAccountId(user_id));
   if (!profile) {
     LOG(ERROR) << "No profile for user is specified";
     return;
@@ -63,7 +63,7 @@
 void CrostiniAnsiblePlaybookExternalDataHandler::RemoveForAccountId(
     const AccountId& account_id) {
   Profile* profile =
-      chromeos::ProfileHelper::Get()->GetProfileByAccountId(account_id);
+      ash::ProfileHelper::Get()->GetProfileByAccountId(account_id);
   if (!profile) {
     LOG(ERROR) << "No profile for user is specified";
     return;
diff --git a/chrome/browser/ash/policy/handlers/lock_to_single_user_manager.cc b/chrome/browser/ash/policy/handlers/lock_to_single_user_manager.cc
index 27813d3..1e7ca2e 100644
--- a/chrome/browser/ash/policy/handlers/lock_to_single_user_manager.cc
+++ b/chrome/browser/ash/policy/handlers/lock_to_single_user_manager.cc
@@ -124,7 +124,7 @@
 }
 
 void LockToSingleUserManager::AddVmStartingObservers(user_manager::User* user) {
-  Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+  Profile* profile = ash::ProfileHelper::Get()->GetProfileByUser(user);
 
   crostini::CrostiniManager::GetForProfile(profile)->AddVmStartingObserver(
       this);
diff --git a/chrome/browser/ash/policy/handlers/power_policy_browsertest.cc b/chrome/browser/ash/policy/handlers/power_policy_browsertest.cc
index 2b83e683..fc2834a 100644
--- a/chrome/browser/ash/policy/handlers/power_policy_browsertest.cc
+++ b/chrome/browser/ash/policy/handlers/power_policy_browsertest.cc
@@ -231,7 +231,7 @@
 
 void PowerPolicyBrowserTestBase::
     StoreAndReloadDevicePolicyAndWaitForLoginProfileChange() {
-  Profile* profile = chromeos::ProfileHelper::GetSigninProfile();
+  Profile* profile = ash::ProfileHelper::GetSigninProfile();
   ASSERT_TRUE(profile);
 
   // Install the new device policy blob in session manager client, reload device
diff --git a/chrome/browser/ash/policy/handlers/powerwash_requirements_checker.cc b/chrome/browser/ash/policy/handlers/powerwash_requirements_checker.cc
index 117cbb4..db2a4728 100644
--- a/chrome/browser/ash/policy/handlers/powerwash_requirements_checker.cc
+++ b/chrome/browser/ash/policy/handlers/powerwash_requirements_checker.cc
@@ -162,7 +162,7 @@
 
 bool PowerwashRequirementsChecker::IsUserAffiliated() const {
   user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile_);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile_);
   return user->IsAffiliated();
 }
 
diff --git a/chrome/browser/ash/policy/handlers/site_isolation_flag_handling_browsertest.cc b/chrome/browser/ash/policy/handlers/site_isolation_flag_handling_browsertest.cc
index 7eed0fc..54a2810 100644
--- a/chrome/browser/ash/policy/handlers/site_isolation_flag_handling_browsertest.cc
+++ b/chrome/browser/ash/policy/handlers/site_isolation_flag_handling_browsertest.cc
@@ -291,7 +291,7 @@
   LogIn();
 
   if (!GetParam().user_flag_internal_names.empty()) {
-    Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUserUnsafe(
+    Profile* profile = ash::ProfileHelper::Get()->GetProfileByUserUnsafe(
         user_manager::UserManager::Get()->GetActiveUser());
     ASSERT_TRUE(profile);
     flags_ui::PrefServiceFlagsStorage flags_storage(profile->GetPrefs());
diff --git a/chrome/browser/ash/policy/invalidation/affiliated_invalidation_service_provider_impl.cc b/chrome/browser/ash/policy/invalidation/affiliated_invalidation_service_provider_impl.cc
index 621cd70..6124060 100644
--- a/chrome/browser/ash/policy/invalidation/affiliated_invalidation_service_provider_impl.cc
+++ b/chrome/browser/ash/policy/invalidation/affiliated_invalidation_service_provider_impl.cc
@@ -152,7 +152,7 @@
     const AccountId& account_id) {
   DCHECK(!is_shut_down_);
   Profile* profile =
-      chromeos::ProfileHelper::Get()->GetProfileByAccountId(account_id);
+      ash::ProfileHelper::Get()->GetProfileByAccountId(account_id);
   invalidation::ProfileInvalidationProvider* invalidation_provider =
       GetInvalidationProvider(profile);
   if (!invalidation_provider) {
@@ -161,7 +161,7 @@
     return;
   }
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   if (!user || !user->IsAffiliated()) {
     // If the Profile belongs to a user who is not affiliated on the device,
     // ignore it.
diff --git a/chrome/browser/ash/policy/login/blocking_login_browsertest.cc b/chrome/browser/ash/policy/login/blocking_login_browsertest.cc
index 26ab1bd6..008ffeac 100644
--- a/chrome/browser/ash/policy/login/blocking_login_browsertest.cc
+++ b/chrome/browser/ash/policy/login/blocking_login_browsertest.cc
@@ -120,7 +120,7 @@
                const content::NotificationSource& source,
                const content::NotificationDetails& details) override {
     ASSERT_EQ(chrome::NOTIFICATION_PROFILE_ADDED, type);
-    if (chromeos::ProfileHelper::IsLockScreenAppProfile(
+    if (ash::ProfileHelper::IsLockScreenAppProfile(
             content::Source<Profile>(source).ptr())) {
       return;
     }
diff --git a/chrome/browser/ash/policy/login/device_login_screen_policy_browsertest.cc b/chrome/browser/ash/policy/login/device_login_screen_policy_browsertest.cc
index ca8660e..2844c33 100644
--- a/chrome/browser/ash/policy/login/device_login_screen_policy_browsertest.cc
+++ b/chrome/browser/ash/policy/login/device_login_screen_policy_browsertest.cc
@@ -114,18 +114,18 @@
 
 void DeviceLoginScreenPolicyBrowsertest::SetUpOnMainThread() {
   DevicePolicyCrosBrowserTest::SetUpOnMainThread();
-  login_profile_ = chromeos::ProfileHelper::GetSigninProfile();
+  login_profile_ = ash::ProfileHelper::GetSigninProfile();
   ASSERT_TRUE(login_profile_);
   // Set the login screen profile.
   auto* accessibility_manager = ash::AccessibilityManager::Get();
   ASSERT_TRUE(accessibility_manager);
   accessibility_manager->SetProfileForTest(
-      chromeos::ProfileHelper::GetSigninProfile());
+      ash::ProfileHelper::GetSigninProfile());
 
   auto* magnification_manager = ash::MagnificationManager::Get();
   ASSERT_TRUE(magnification_manager);
   magnification_manager->SetProfileForTest(
-      chromeos::ProfileHelper::GetSigninProfile());
+      ash::ProfileHelper::GetSigninProfile());
 }
 
 void DeviceLoginScreenPolicyBrowsertest::
diff --git a/chrome/browser/ash/policy/login/force_maximize_on_first_run_browsertest.cc b/chrome/browser/ash/policy/login/force_maximize_on_first_run_browsertest.cc
index 4c95206..8501634d 100644
--- a/chrome/browser/ash/policy/login/force_maximize_on_first_run_browsertest.cc
+++ b/chrome/browser/ash/policy/login/force_maximize_on_first_run_browsertest.cc
@@ -51,8 +51,7 @@
   const Browser* OpenNewBrowserWindow() {
     const user_manager::User* const user =
         user_manager::UserManager::Get()->GetActiveUser();
-    Profile* const profile =
-        chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+    Profile* const profile = ash::ProfileHelper::Get()->GetProfileByUser(user);
     return CreateBrowser(profile);
   }
 };
diff --git a/chrome/browser/ash/policy/login/login_policy_test_base.cc b/chrome/browser/ash/policy/login/login_policy_test_base.cc
index 8b8655b..4938a93 100644
--- a/chrome/browser/ash/policy/login/login_policy_test_base.cc
+++ b/chrome/browser/ash/policy/login/login_policy_test_base.cc
@@ -88,7 +88,7 @@
 
   EXPECT_NE(user, nullptr);
 
-  return chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+  return ash::ProfileHelper::Get()->GetProfileByUser(user);
 }
 
 void LoginPolicyTestBase::GetMandatoryPoliciesValue(
diff --git a/chrome/browser/ash/policy/login/login_screen_accessibility_policy_browsertest.cc b/chrome/browser/ash/policy/login/login_screen_accessibility_policy_browsertest.cc
index 8ad0105..6ea5a9f 100644
--- a/chrome/browser/ash/policy/login/login_screen_accessibility_policy_browsertest.cc
+++ b/chrome/browser/ash/policy/login/login_screen_accessibility_policy_browsertest.cc
@@ -116,18 +116,18 @@
 
 void LoginScreenAccessibilityPolicyBrowsertest::SetUpOnMainThread() {
   DevicePolicyCrosBrowserTest::SetUpOnMainThread();
-  login_profile_ = chromeos::ProfileHelper::GetSigninProfile();
+  login_profile_ = ash::ProfileHelper::GetSigninProfile();
   ASSERT_TRUE(login_profile_);
   // Set the login screen profile.
   AccessibilityManager* accessibility_manager = AccessibilityManager::Get();
   ASSERT_TRUE(accessibility_manager);
   accessibility_manager->SetProfileForTest(
-      chromeos::ProfileHelper::GetSigninProfile());
+      ash::ProfileHelper::GetSigninProfile());
 
   MagnificationManager* magnification_manager = MagnificationManager::Get();
   ASSERT_TRUE(magnification_manager);
   magnification_manager->SetProfileForTest(
-      chromeos::ProfileHelper::GetSigninProfile());
+      ash::ProfileHelper::GetSigninProfile());
 
   // Disable PolicyRecommendationRestorer. See https://crbug.com/1015763#c13 for
   // details.
diff --git a/chrome/browser/ash/policy/login/login_screen_default_policy_browsertest.cc b/chrome/browser/ash/policy/login/login_screen_default_policy_browsertest.cc
index cc8859f..7d63965 100644
--- a/chrome/browser/ash/policy/login/login_screen_default_policy_browsertest.cc
+++ b/chrome/browser/ash/policy/login/login_screen_default_policy_browsertest.cc
@@ -147,7 +147,7 @@
 
 void LoginScreenDefaultPolicyBrowsertestBase::SetUpOnMainThread() {
   DevicePolicyCrosBrowserTest::SetUpOnMainThread();
-  login_profile_ = chromeos::ProfileHelper::GetSigninProfile();
+  login_profile_ = ash::ProfileHelper::GetSigninProfile();
   ASSERT_TRUE(login_profile_);
 }
 
@@ -178,12 +178,12 @@
   AccessibilityManager* accessibility_manager = AccessibilityManager::Get();
   ASSERT_TRUE(accessibility_manager);
   accessibility_manager->SetProfileForTest(
-      chromeos::ProfileHelper::GetSigninProfile());
+      ash::ProfileHelper::GetSigninProfile());
 
   MagnificationManager* magnification_manager = MagnificationManager::Get();
   ASSERT_TRUE(magnification_manager);
   magnification_manager->SetProfileForTest(
-      chromeos::ProfileHelper::GetSigninProfile());
+      ash::ProfileHelper::GetSigninProfile());
 }
 
 void LoginScreenDefaultPolicyLoginScreenBrowsertest::TearDownOnMainThread() {
diff --git a/chrome/browser/ash/policy/login/signin_profile_extensions_policy_test_base.cc b/chrome/browser/ash/policy/login/signin_profile_extensions_policy_test_base.cc
index ae5f09f..6278473 100644
--- a/chrome/browser/ash/policy/login/signin_profile_extensions_policy_test_base.cc
+++ b/chrome/browser/ash/policy/login/signin_profile_extensions_policy_test_base.cc
@@ -53,12 +53,12 @@
 }
 
 Profile* SigninProfileExtensionsPolicyTestBase::GetInitialProfile() {
-  // Intentionally not using the |chromeos::ProfileHelper::GetSigninProfile|
+  // Intentionally not using the |ash::ProfileHelper::GetSigninProfile|
   // method here, as it performs the lazy construction of the profile, while for
   // the testing purposes it's better to assert that it has been created before.
   Profile* const profile =
       g_browser_process->profile_manager()->GetProfileByPath(
-          chromeos::ProfileHelper::GetSigninProfileDir());
+          ash::ProfileHelper::GetSigninProfileDir());
   DCHECK(profile);
 
   return profile;
diff --git a/chrome/browser/ash/policy/networking/network_policy_application_browsertest.cc b/chrome/browser/ash/policy/networking/network_policy_application_browsertest.cc
index 5d187c5..4c319b1d 100644
--- a/chrome/browser/ash/policy/networking/network_policy_application_browsertest.cc
+++ b/chrome/browser/ash/policy/networking/network_policy_application_browsertest.cc
@@ -323,9 +323,8 @@
   // updates (regression test for https://crbug.com/936677).
   shill_service_client_test_->SetHoldBackServicePropertyUpdates(true);
 
-  std::string user_hash =
-      chromeos::ProfileHelper::GetUserIdHashByUserIdForTesting(
-          test_account_id_.GetUserEmail());
+  std::string user_hash = ash::ProfileHelper::GetUserIdHashByUserIdForTesting(
+      test_account_id_.GetUserEmail());
   LoginUser(test_account_id_);
   shill_profile_client_test_->AddProfile(kUserProfilePath, user_hash);
 
diff --git a/chrome/browser/ash/policy/networking/policy_cert_service_factory.cc b/chrome/browser/ash/policy/networking/policy_cert_service_factory.cc
index 186666e..e3311325 100644
--- a/chrome/browser/ash/policy/networking/policy_cert_service_factory.cc
+++ b/chrome/browser/ash/policy/networking/policy_cert_service_factory.cc
@@ -30,7 +30,7 @@
 // certificates set.
 chromeos::PolicyCertificateProvider* GetPolicyCertificateProvider(
     Profile* profile) {
-  if (chromeos::ProfileHelper::Get()->IsSigninProfile(profile)) {
+  if (ash::ProfileHelper::Get()->IsSigninProfile(profile)) {
     return g_browser_process->platform_part()
         ->browser_policy_connector_ash()
         ->GetDeviceNetworkConfigurationUpdater();
@@ -104,7 +104,7 @@
   if (!policy_certificate_provider)
     return nullptr;
 
-  if (chromeos::ProfileHelper::Get()->IsSigninProfile(profile)) {
+  if (ash::ProfileHelper::Get()->IsSigninProfile(profile)) {
     return new PolicyCertService(profile, policy_certificate_provider,
                                  /*may_use_profile_wide_trust_anchors=*/false);
   }
@@ -112,9 +112,8 @@
   // Don't allow policy-provided certificates for "special" Profiles except the
   // one listed above.
   user_manager::UserManager* user_manager = user_manager::UserManager::Get();
-  const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(
-          profile->GetOriginalProfile());
+  const user_manager::User* user = ash::ProfileHelper::Get()->GetUserByProfile(
+      profile->GetOriginalProfile());
   if (!user)
     return nullptr;
 
diff --git a/chrome/browser/ash/policy/networking/policy_certs_browsertest.cc b/chrome/browser/ash/policy/networking/policy_certs_browsertest.cc
index 70c48258..f043135 100644
--- a/chrome/browser/ash/policy/networking/policy_certs_browsertest.cc
+++ b/chrome/browser/ash/policy/networking/policy_certs_browsertest.cc
@@ -789,8 +789,7 @@
   Profile* active_user_profile() {
     const user_manager::User* const user =
         user_manager::UserManager::Get()->GetActiveUser();
-    Profile* const profile =
-        chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+    Profile* const profile = ash::ProfileHelper::Get()->GetProfileByUser(user);
     return profile;
   }
 };
@@ -919,7 +918,7 @@
     SigninProfileExtensionsPolicyTestBase::SetUpOnMainThread();
 
     signin_profile_ = GetInitialProfile();
-    ASSERT_TRUE(chromeos::ProfileHelper::IsSigninProfile(signin_profile_));
+    ASSERT_TRUE(ash::ProfileHelper::IsSigninProfile(signin_profile_));
 
     extensions::ExtensionHostTestHelper extension_1_observer(
         signin_profile_, kSigninScreenExtension1);
diff --git a/chrome/browser/ash/policy/networking/user_network_configuration_updater_factory.cc b/chrome/browser/ash/policy/networking/user_network_configuration_updater_factory.cc
index 939d7b3..d82a074 100644
--- a/chrome/browser/ash/policy/networking/user_network_configuration_updater_factory.cc
+++ b/chrome/browser/ash/policy/networking/user_network_configuration_updater_factory.cc
@@ -62,12 +62,12 @@
     content::BrowserContext* context) const {
   // On the login/lock screen only device network policies apply.
   Profile* profile = Profile::FromBrowserContext(context);
-  if (!chromeos::ProfileHelper::IsRegularProfile(profile)) {
+  if (!ash::ProfileHelper::IsRegularProfile(profile)) {
     return nullptr;
   }
 
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   DCHECK(user);
   // Currently, only the network policy of the primary user is supported. See
   // also http://crbug.com/310685 .
diff --git a/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager.cc b/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager.cc
index e8f6bb1..c52ecfe 100644
--- a/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager.cc
+++ b/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager.cc
@@ -71,7 +71,7 @@
 
 bool MetricReportingManager::Delegate::IsAffiliated(Profile* profile) {
   const user_manager::User* const user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   return user && user->IsAffiliated();
 }
 
diff --git a/chrome/browser/ash/policy/reporting/user_added_removed/user_added_removed_reporter.cc b/chrome/browser/ash/policy/reporting/user_added_removed/user_added_removed_reporter.cc
index 0b03a90..4eae3c5d 100644
--- a/chrome/browser/ash/policy/reporting/user_added_removed/user_added_removed_reporter.cc
+++ b/chrome/browser/ash/policy/reporting/user_added_removed/user_added_removed_reporter.cc
@@ -43,7 +43,7 @@
     return;
   }
   user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   if (!user || user->IsKioskType() ||
       user->GetType() == user_manager::USER_TYPE_PUBLIC_ACCOUNT ||
       user->GetType() == user_manager::USER_TYPE_GUEST) {
diff --git a/chrome/browser/ash/policy/status_collector/app_info_generator.cc b/chrome/browser/ash/policy/status_collector/app_info_generator.cc
index 91dbc7a..d441cd6 100644
--- a/chrome/browser/ash/policy/status_collector/app_info_generator.cc
+++ b/chrome/browser/ash/policy/status_collector/app_info_generator.cc
@@ -22,8 +22,8 @@
 
 bool IsPrimaryAndAffiliated(Profile* profile) {
   user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
-  bool is_primary = chromeos::ProfileHelper::Get()->IsPrimaryProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
+  bool is_primary = ash::ProfileHelper::Get()->IsPrimaryProfile(profile);
   bool is_affiliated = user && user->IsAffiliated();
   if (!is_primary || !is_affiliated) {
     VLOG(1) << "The profile for the primary user is not associated with an "
diff --git a/chrome/browser/ash/policy/status_collector/child_status_collector_browsertest.cc b/chrome/browser/ash/policy/status_collector/child_status_collector_browsertest.cc
index 8f96c03..41fb49a 100644
--- a/chrome/browser/ash/policy/status_collector/child_status_collector_browsertest.cc
+++ b/chrome/browser/ash/policy/status_collector/child_status_collector_browsertest.cc
@@ -367,7 +367,7 @@
     TestingProfile::Builder profile_builder;
     profile_builder.SetProfileName(account_id.GetUserEmail());
     testing_profile_ = profile_builder.Build();
-    chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
+    ash::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
         user, testing_profile_.get());
 
     EXPECT_CALL(*user_manager_, IsLoggedInAsKioskApp())
diff --git a/chrome/browser/ash/policy/status_collector/device_status_collector.cc b/chrome/browser/ash/policy/status_collector/device_status_collector.cc
index ed4bb32..257de73 100644
--- a/chrome/browser/ash/policy/status_collector/device_status_collector.cc
+++ b/chrome/browser/ash/policy/status_collector/device_status_collector.cc
@@ -2802,8 +2802,7 @@
     scoped_refptr<DeviceStatusCollectorState> state,
     em::SessionStatusReportRequest* status,
     const user_manager::User* user) {
-  Profile* const profile =
-      chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+  Profile* const profile = ash::ProfileHelper::Get()->GetProfileByUser(user);
   if (!profile)
     return false;
 
@@ -2930,7 +2929,7 @@
 
 std::string DeviceStatusCollector::GetAppVersion(
     const std::string& kiosk_app_id) {
-  Profile* const profile = chromeos::ProfileHelper::Get()->GetProfileByUser(
+  Profile* const profile = ash::ProfileHelper::Get()->GetProfileByUser(
       user_manager::UserManager::Get()->GetActiveUser());
   // TODO(b/191334671): Replace with DCHECK once we no longer hit this timing
   // issue.
diff --git a/chrome/browser/ash/policy/status_collector/device_status_collector_browsertest.cc b/chrome/browser/ash/policy/status_collector/device_status_collector_browsertest.cc
index 478fa51..7109d1b 100644
--- a/chrome/browser/ash/policy/status_collector/device_status_collector_browsertest.cc
+++ b/chrome/browser/ash/policy/status_collector/device_status_collector_browsertest.cc
@@ -1151,7 +1151,7 @@
     TestingProfile::Builder profile_builder;
     profile_builder.SetProfileName(account_id.GetUserEmail());
     testing_profile_ = profile_builder.Build();
-    chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
+    ash::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
         user, testing_profile_.get());
 
     EXPECT_CALL(*user_manager_, IsLoggedInAsKioskApp())
@@ -1186,7 +1186,7 @@
     }
 
     testing_profile_ = std::make_unique<TestingProfile>();
-    chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
+    ash::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
         user, testing_profile_.get());
 
     SetDeviceLocalAccounts(&owner_settings_service_, accounts);
diff --git a/chrome/browser/ash/policy/status_collector/legacy_device_status_collector.cc b/chrome/browser/ash/policy/status_collector/legacy_device_status_collector.cc
index d2771f6..f426e31f 100644
--- a/chrome/browser/ash/policy/status_collector/legacy_device_status_collector.cc
+++ b/chrome/browser/ash/policy/status_collector/legacy_device_status_collector.cc
@@ -2659,8 +2659,7 @@
     scoped_refptr<DeviceStatusCollectorState> state,
     em::SessionStatusReportRequest* status,
     const user_manager::User* user) {
-  Profile* const profile =
-      chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+  Profile* const profile = ash::ProfileHelper::Get()->GetProfileByUser(user);
   if (!profile)
     return false;
 
@@ -2787,7 +2786,7 @@
 
 std::string LegacyDeviceStatusCollector::GetAppVersion(
     const std::string& kiosk_app_id) {
-  Profile* const profile = chromeos::ProfileHelper::Get()->GetProfileByUser(
+  Profile* const profile = ash::ProfileHelper::Get()->GetProfileByUser(
       user_manager::UserManager::Get()->GetActiveUser());
   // TODO(b/191334671): Replace with DCHECK once we no longer hit this timing
   // issue.
diff --git a/chrome/browser/ash/policy/status_collector/legacy_device_status_collector_browsertest.cc b/chrome/browser/ash/policy/status_collector/legacy_device_status_collector_browsertest.cc
index 7fc0476..213a5a1 100644
--- a/chrome/browser/ash/policy/status_collector/legacy_device_status_collector_browsertest.cc
+++ b/chrome/browser/ash/policy/status_collector/legacy_device_status_collector_browsertest.cc
@@ -1044,7 +1044,7 @@
     TestingProfile::Builder profile_builder;
     profile_builder.SetProfileName(account_id.GetUserEmail());
     testing_profile_ = profile_builder.Build();
-    chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
+    ash::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
         user, testing_profile_.get());
 
     EXPECT_CALL(*user_manager_, IsLoggedInAsKioskApp())
@@ -1079,7 +1079,7 @@
     }
 
     testing_profile_ = std::make_unique<TestingProfile>();
-    chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
+    ash::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
         user, testing_profile_.get());
 
     SetDeviceLocalAccounts(&owner_settings_service_, accounts);
diff --git a/chrome/browser/ash/policy/status_collector/managed_session_service.cc b/chrome/browser/ash/policy/status_collector/managed_session_service.cc
index fcedbaa..6a8f201b 100644
--- a/chrome/browser/ash/policy/status_collector/managed_session_service.cc
+++ b/chrome/browser/ash/policy/status_collector/managed_session_service.cc
@@ -72,10 +72,10 @@
 
 void ManagedSessionService::OnUserProfileLoaded(const AccountId& account_id) {
   Profile* profile =
-      chromeos::ProfileHelper::Get()->GetProfileByAccountId(account_id);
+      ash::ProfileHelper::Get()->GetProfileByAccountId(account_id);
   profile_observations_.AddObservation(profile);
   if (ash::SessionTerminationManager::Get() &&
-      chromeos::ProfileHelper::Get()->IsPrimaryProfile(profile)) {
+      ash::ProfileHelper::Get()->IsPrimaryProfile(profile)) {
     ash::SessionTerminationManager::Get()->AddObserver(this);
   }
   for (auto& observer : observers_) {
diff --git a/chrome/browser/ash/quick_pair/quick_pair_browser_delegate_impl.cc b/chrome/browser/ash/quick_pair/quick_pair_browser_delegate_impl.cc
index ac58c9d0..45ecc1a8 100644
--- a/chrome/browser/ash/quick_pair/quick_pair_browser_delegate_impl.cc
+++ b/chrome/browser/ash/quick_pair/quick_pair_browser_delegate_impl.cc
@@ -69,7 +69,7 @@
       user_manager::UserManager::Get()->GetActiveUser();
   DCHECK(active_user);
 
-  return chromeos::ProfileHelper::Get()->GetProfileByUser(active_user);
+  return ProfileHelper::Get()->GetProfileByUser(active_user);
 }
 
 }  // namespace quick_pair
diff --git a/chrome/browser/ash/system_extensions/api/window_management/window_management_impl.cc b/chrome/browser/ash/system_extensions/api/window_management/window_management_impl.cc
index fa498258b..ff4ca8b6 100644
--- a/chrome/browser/ash/system_extensions/api/window_management/window_management_impl.cc
+++ b/chrome/browser/ash/system_extensions/api/window_management/window_management_impl.cc
@@ -64,7 +64,9 @@
         }
       });
   // TODO(crbug.com/1253318): Ensure this works with multiple screens.
-  target->SetBounds(gfx::Rect(x, y, width, height));
+  if (target) {
+    target->SetBounds(gfx::Rect(x, y, width, height));
+  }
 }
 
 }  // namespace ash
diff --git a/chrome/browser/ash/system_extensions/system_extensions_provider_factory.cc b/chrome/browser/ash/system_extensions/system_extensions_provider_factory.cc
index 2c339309..7c7714d1 100644
--- a/chrome/browser/ash/system_extensions/system_extensions_provider_factory.cc
+++ b/chrome/browser/ash/system_extensions/system_extensions_provider_factory.cc
@@ -55,10 +55,10 @@
   if (profile->IsSystemProfile())
     return nullptr;
 
-  if (!chromeos::ProfileHelper::IsRegularProfile(profile))
+  if (!ash::ProfileHelper::IsRegularProfile(profile))
     return nullptr;
 
-  if (!chromeos::ProfileHelper::IsPrimaryProfile(profile))
+  if (!ash::ProfileHelper::IsPrimaryProfile(profile))
     return nullptr;
 
   auto* user_manager = user_manager::UserManager::Get();
diff --git a/chrome/browser/ash/system_logs/debug_daemon_log_source.cc b/chrome/browser/ash/system_logs/debug_daemon_log_source.cc
index ad5f632a..66003cfa 100644
--- a/chrome/browser/ash/system_logs/debug_daemon_log_source.cc
+++ b/chrome/browser/ash/system_logs/debug_daemon_log_source.cc
@@ -184,8 +184,7 @@
       continue;
 
     profile_dirs.emplace_back(
-        chromeos::ProfileHelper::GetProfilePathByUserIdHash(
-            user->username_hash()));
+        ash::ProfileHelper::GetProfilePathByUserIdHash(user->username_hash()));
   }
 
   auto response = std::make_unique<SystemLogsResponse>();
diff --git a/chrome/browser/ash/tether/tether_service.cc b/chrome/browser/ash/tether/tether_service.cc
index b5af1be..91ab429 100644
--- a/chrome/browser/ash/tether/tether_service.cc
+++ b/chrome/browser/ash/tether/tether_service.cc
@@ -42,7 +42,7 @@
   // TetherService object should be created for secondary users. If multiple
   // instances were created for each user, inconsistencies could lead to browser
   // crashes. See https://crbug.com/809357.
-  if (!chromeos::ProfileHelper::Get()->IsPrimaryProfile(profile))
+  if (!ProfileHelper::Get()->IsPrimaryProfile(profile))
     return nullptr;
 
   return TetherServiceFactory::GetForBrowserContext(profile);
diff --git a/chrome/browser/ash/web_applications/personalization_app/chrome_personalization_app_wallpaper_provider.cc b/chrome/browser/ash/web_applications/personalization_app/chrome_personalization_app_wallpaper_provider.cc
index da667009..91e543d3 100644
--- a/chrome/browser/ash/web_applications/personalization_app/chrome_personalization_app_wallpaper_provider.cc
+++ b/chrome/browser/ash/web_applications/personalization_app/chrome_personalization_app_wallpaper_provider.cc
@@ -86,7 +86,7 @@
 }
 
 const user_manager::User* GetUser(const Profile* profile) {
-  auto* profile_helper = chromeos::ProfileHelper::Get();
+  auto* profile_helper = ash::ProfileHelper::Get();
   DCHECK(profile_helper);
   const user_manager::User* user = profile_helper->GetUserByProfile(profile);
   DCHECK(user);
diff --git a/chrome/browser/attribution_reporting/android/java/src/org/chromium/chrome/browser/attribution_reporting/AttributionReportingProvider.java b/chrome/browser/attribution_reporting/android/java/src/org/chromium/chrome/browser/attribution_reporting/AttributionReportingProvider.java
index 1dc2d691..43b02f7 100644
--- a/chrome/browser/attribution_reporting/android/java/src/org/chromium/chrome/browser/attribution_reporting/AttributionReportingProvider.java
+++ b/chrome/browser/attribution_reporting/android/java/src/org/chromium/chrome/browser/attribution_reporting/AttributionReportingProvider.java
@@ -4,15 +4,16 @@
 
 package org.chromium.chrome.browser.attribution_reporting;
 
+import org.chromium.base.annotations.IdentifierNameString;
 import org.chromium.chrome.browser.base.SplitCompatContentProvider;
-import org.chromium.chrome.browser.base.SplitCompatUtils;
 
 /** See {@link AttributionReportingProviderImpl}. */
 public class AttributionReportingProvider extends SplitCompatContentProvider {
+    @IdentifierNameString
     private static final String IMPL_CLASS = "org.chromium.chrome.browser.attribution_reporting"
             + ".AttributionReportingProviderImpl";
 
     public AttributionReportingProvider() {
-        super(SplitCompatUtils.getIdentifierName(IMPL_CLASS));
+        super(IMPL_CLASS);
     }
 }
diff --git a/chrome/browser/browsing_data/browsing_data_media_license_helper.cc b/chrome/browser/browsing_data/browsing_data_media_license_helper.cc
index 8f49fe10..a411e0a 100644
--- a/chrome/browser/browsing_data/browsing_data_media_license_helper.cc
+++ b/chrome/browser/browsing_data/browsing_data_media_license_helper.cc
@@ -13,6 +13,7 @@
 #include "components/browsing_data/content/browsing_data_helper.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/storage_usage_info.h"
 #include "storage/browser/file_system/file_system_context.h"
 #include "storage/browser/file_system/file_system_quota_util.h"
 #include "storage/browser/file_system/plugin_private_file_system_backend.h"
@@ -26,7 +27,7 @@
 
 // An implementation of the BrowsingDataMediaLicenseHelper interface that
 // determine data on media licenses in a given |filesystem_context| and
-// returns a list of MediaLicenseInfo items to a client.
+// returns a list of StorageUsageInfo items to a client.
 class BrowsingDataMediaLicenseHelperImpl final
     : public BrowsingDataMediaLicenseHelper {
  public:
@@ -40,19 +41,18 @@
       const BrowsingDataMediaLicenseHelperImpl&) = delete;
 
   void StartFetching(FetchCallback callback) final;
-  void DeleteMediaLicenseOrigin(const GURL& origin) final;
+  void DeleteMediaLicenseOrigin(const url::Origin& origin) final;
 
  private:
   ~BrowsingDataMediaLicenseHelperImpl() final;
 
-  // Enumerates all filesystem files, storing the resulting list into
-  // file_system_file_ for later use. This must be called on the file
-  // task runner.
+  // Enumerates all origins with media licenses, returning the resulting list in
+  // the callback. This must be called on the file task runner.
   void FetchMediaLicenseInfoOnFileTaskRunner(FetchCallback callback);
 
   // Deletes all file systems associated with |origin|. This must be called on
   // the file task runner.
-  void DeleteMediaLicenseOriginOnFileTaskRunner(const GURL& origin);
+  void DeleteMediaLicenseOriginOnFileTaskRunner(const url::Origin& origin);
 
   // Returns the file task runner for the |filesystem_context_|.
   base::SequencedTaskRunner* file_task_runner() {
@@ -82,7 +82,7 @@
 }
 
 void BrowsingDataMediaLicenseHelperImpl::DeleteMediaLicenseOrigin(
-    const GURL& origin) {
+    const url::Origin& origin) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   file_task_runner()->PostTask(
       FROM_HERE, base::BindOnce(&BrowsingDataMediaLicenseHelperImpl::
@@ -104,7 +104,7 @@
   // Determine the set of StorageKeys used.
   std::vector<blink::StorageKey> storage_keys =
       backend->GetStorageKeysForTypeOnFileTaskRunner(kType);
-  std::list<MediaLicenseInfo> result;
+  std::list<content::StorageUsageInfo> result;
   for (const auto& storage_key : storage_keys) {
     if (!browsing_data::HasWebScheme(storage_key.origin().GetURL()))
       continue;  // Non-websafe state is not considered browsing data.
@@ -114,8 +114,7 @@
     backend->GetOriginDetailsOnFileTaskRunner(filesystem_context_.get(),
                                               storage_key.origin(), &size,
                                               &last_modified_time);
-    result.emplace_back(storage_key.origin().GetURL(), size,
-                                      last_modified_time);
+    result.emplace_back(storage_key.origin(), size, last_modified_time);
   }
 
   content::GetUIThreadTaskRunner({})->PostTask(
@@ -123,7 +122,7 @@
 }
 
 void BrowsingDataMediaLicenseHelperImpl::
-    DeleteMediaLicenseOriginOnFileTaskRunner(const GURL& origin) {
+    DeleteMediaLicenseOriginOnFileTaskRunner(const url::Origin& origin) {
   DCHECK(file_task_runner()->RunsTasksInCurrentSequence());
 
   const storage::FileSystemType kType = storage::kFileSystemTypePluginPrivate;
@@ -134,22 +133,11 @@
   // file system will be partitioned and use the appropriate StorageKey.
   quota_util->DeleteStorageKeyDataOnFileTaskRunner(
       filesystem_context_.get(), filesystem_context_->quota_manager_proxy(),
-      blink::StorageKey(url::Origin::Create(origin)), kType);
+      blink::StorageKey(origin), kType);
 }
 
 }  // namespace
 
-BrowsingDataMediaLicenseHelper::MediaLicenseInfo::MediaLicenseInfo(
-    const GURL& origin,
-    int64_t size,
-    base::Time last_modified_time)
-    : origin(origin), size(size), last_modified_time(last_modified_time) {}
-
-BrowsingDataMediaLicenseHelper::MediaLicenseInfo::MediaLicenseInfo(
-    const MediaLicenseInfo& other) = default;
-
-BrowsingDataMediaLicenseHelper::MediaLicenseInfo::~MediaLicenseInfo() {}
-
 // static
 BrowsingDataMediaLicenseHelper* BrowsingDataMediaLicenseHelper::Create(
     storage::FileSystemContext* filesystem_context) {
diff --git a/chrome/browser/browsing_data/browsing_data_media_license_helper.h b/chrome/browser/browsing_data/browsing_data_media_license_helper.h
index 72c67bbd..c24d703d 100644
--- a/chrome/browser/browsing_data/browsing_data_media_license_helper.h
+++ b/chrome/browser/browsing_data/browsing_data_media_license_helper.h
@@ -11,11 +11,18 @@
 #include "base/callback.h"
 #include "base/memory/ref_counted.h"
 #include "base/time/time.h"
-#include "url/gurl.h"
+
+namespace content {
+struct StorageUsageInfo;
+}  // namespace content
 
 namespace storage {
 class FileSystemContext;
-}
+}  // namespace storage
+
+namespace url {
+class Origin;
+}  // namespace url
 
 // Defines an interface for classes that deal with aggregating and deleting
 // media licenses.
@@ -24,30 +31,13 @@
 // data when a client calls StartFetching from the UI thread, and will
 // notify the client via a supplied callback when the data is available.
 //
-// The client's callback is passed a list of MediaLicenseInfo objects
+// The client's callback is passed a list of StorageUsageInfo objects
 // containing usage information for each origin's media licenses.
 class BrowsingDataMediaLicenseHelper
     : public base::RefCountedThreadSafe<BrowsingDataMediaLicenseHelper> {
  public:
-  // Detailed information about a media license, including it's origin GURL
-  // and the amount of data (in bytes).
-  struct MediaLicenseInfo {
-    MediaLicenseInfo(const GURL& origin,
-                     int64_t size,
-                     base::Time last_modified_time);
-    MediaLicenseInfo(const MediaLicenseInfo& other);
-    ~MediaLicenseInfo();
-
-    // The origin for which the information is relevant.
-    GURL origin;
-    // Size (in bytes).
-    int64_t size;
-    // Last modified time.
-    base::Time last_modified_time;
-  };
-
   using FetchCallback =
-      base::OnceCallback<void(const std::list<MediaLicenseInfo>&)>;
+      base::OnceCallback<void(const std::list<content::StorageUsageInfo>&)>;
 
   // Creates a BrowsingDataMediaLicenseHelper instance for the media
   // licenses stored in |profile|'s user data directory. The
@@ -61,7 +51,7 @@
 
   // Starts the process of fetching media license data, which will call
   // |callback| upon completion, passing it a constant list of
-  // MediaLicenseInfo objects. StartFetching must be called only in the UI
+  // StorageUsageInfo objects. StartFetching must be called only in the UI
   // thread; the provided Callback will likewise be executed asynchronously
   // on the UI thread. Obtaining the data will occur asynchronously on the
   // FILE thread.
@@ -70,7 +60,7 @@
   // Deletes any media licenses associated with |origin| from the disk.
   // Deletion will occur asynchronously on the FILE thread, but this function
   // must be called only on the UI thread.
-  virtual void DeleteMediaLicenseOrigin(const GURL& origin) = 0;
+  virtual void DeleteMediaLicenseOrigin(const url::Origin& origin) = 0;
 
  protected:
   friend class base::RefCountedThreadSafe<BrowsingDataMediaLicenseHelper>;
diff --git a/chrome/browser/browsing_data/browsing_data_media_license_helper_unittest.cc b/chrome/browser/browsing_data/browsing_data_media_license_helper_unittest.cc
index ccc15b52..b3a37bb 100644
--- a/chrome/browser/browsing_data/browsing_data_media_license_helper_unittest.cc
+++ b/chrome/browser/browsing_data/browsing_data_media_license_helper_unittest.cc
@@ -15,9 +15,11 @@
 #include "base/memory/raw_ptr.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/test_future.h"
 #include "chrome/browser/browsing_data/browsing_data_media_license_helper.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/storage_partition.h"
+#include "content/public/browser/storage_usage_info.h"
 #include "content/public/test/browser_task_environment.h"
 #include "storage/browser/file_system/async_file_util.h"
 #include "storage/browser/file_system/file_system_context.h"
@@ -28,58 +30,17 @@
 #include "storage/common/file_system/file_system_types.h"
 #include "storage/common/file_system/file_system_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/origin.h"
 
 using content::BrowserContext;
 using content::BrowserThread;
+using content::StorageUsageInfo;
 
 namespace {
 
 const char kWidevineCdmPluginId[] = "application_x-ppapi-widevine-cdm";
 const char kClearKeyCdmPluginId[] = "application_x-ppapi-clearkey-cdm";
 
-class AwaitCompletionHelper {
- public:
-  AwaitCompletionHelper() : start_(false), already_quit_(false) {}
-
-  AwaitCompletionHelper(const AwaitCompletionHelper&) = delete;
-  AwaitCompletionHelper& operator=(const AwaitCompletionHelper&) = delete;
-
-  virtual ~AwaitCompletionHelper() {}
-
-  void BlockUntilNotified() {
-    if (!already_quit_) {
-      DCHECK(!start_);
-      start_ = true;
-      base::RunLoop().Run();
-    } else {
-      DCHECK(!start_);
-      already_quit_ = false;
-    }
-  }
-
-  base::OnceClosure NotifyClosure() {
-    return base::BindOnce(&AwaitCompletionHelper::Notify,
-                          base::Unretained(this));
-  }
-
- private:
-  void Notify() {
-    if (start_) {
-      DCHECK(!already_quit_);
-      base::RunLoop::QuitCurrentWhenIdleDeprecated();
-      start_ = false;
-    } else {
-      DCHECK(!already_quit_);
-      already_quit_ = true;
-    }
-  }
-
-  // Helps prevent from running message_loop, if the callback invoked
-  // immediately.
-  bool start_;
-  bool already_quit_;
-};
-
 // The FileSystem APIs are all asynchronous; this testing class wraps up the
 // boilerplate code necessary to deal with waiting for responses. In a nutshell,
 // any async call whose response we want to test ought to be followed by a call
@@ -106,36 +67,25 @@
     base::RunLoop().RunUntilIdle();
   }
 
-  // Calls StartFetching() on the test's BrowsingDataMediaLicenseHelper
-  // object, then blocks until the callback is executed.
+  // Calls StartFetching() on the test's BrowsingDataMediaLicenseHelper object,
+  // then stores found file systems locally so that they are available via
+  // GetFileSystems().
   void FetchMediaLicenses() {
-    AwaitCompletionHelper await_completion;
-    helper_->StartFetching(base::BindOnce(
-        &BrowsingDataMediaLicenseHelperTest::OnFetchMediaLicenses,
-        base::Unretained(this), await_completion.NotifyClosure()));
-    await_completion.BlockUntilNotified();
-  }
+    base::test::TestFuture<std::list<StorageUsageInfo>> future;
+    helper_->StartFetching(
+        future.GetCallback<const std::list<StorageUsageInfo>&>());
 
-  // Callback that should be executed in response to StartFetching(), and stores
-  // found file systems locally so that they are available via GetFileSystems().
-  void OnFetchMediaLicenses(
-      base::OnceClosure done_cb,
-      const std::list<BrowsingDataMediaLicenseHelper::MediaLicenseInfo>&
-          media_license_info_list) {
-    media_license_info_list_ = std::make_unique<
-        std::list<BrowsingDataMediaLicenseHelper::MediaLicenseInfo>>(
-
-        media_license_info_list);
-    std::move(done_cb).Run();
+    media_license_info_list_ =
+        std::make_unique<std::list<StorageUsageInfo>>(future.Take());
   }
 
   // Add some files to the PluginPrivateFileSystem. They are created as follows:
   //   |origin1| - ClearKey - 1 file - timestamp 10 days ago
   //   |origin2| - Widevine - 2 files - timestamps now and 60 days ago
   //   |origin3| - Widevine - 2 files - timestamps 20 and 30 days ago
-  virtual void PopulateTestMediaLicenseData(const GURL& origin1,
-                                            const GURL& origin2,
-                                            const GURL& origin3) {
+  virtual void PopulateTestMediaLicenseData(const url::Origin& origin1,
+                                            const url::Origin& origin2,
+                                            const url::Origin& origin3) {
     const base::Time ten_days_ago = now_ - base::Days(10);
     const base::Time twenty_days_ago = now_ - base::Days(20);
     const base::Time thirty_days_ago = now_ - base::Days(30);
@@ -166,12 +116,11 @@
 
   const base::Time Now() { return now_; }
 
-  void DeleteMediaLicenseOrigin(const GURL& origin) {
+  void DeleteMediaLicenseOrigin(const url::Origin& origin) {
     helper_->DeleteMediaLicenseOrigin(origin);
   }
 
-  std::list<BrowsingDataMediaLicenseHelper::MediaLicenseInfo>*
-  ReturnedMediaLicenseInfo() const {
+  std::list<StorageUsageInfo>* ReturnedMediaLicenseInfo() const {
     return media_license_info_list_.get();
   }
 
@@ -180,39 +129,32 @@
   // provided. Returns the file system ID for the created
   // PluginPrivateFileSystem.
   std::string CreateFileSystem(const std::string& plugin_name,
-                               const GURL& origin) {
-    AwaitCompletionHelper await_completion;
+                               const url::Origin& origin) {
     std::string fsid =
         storage::IsolatedContext::GetInstance()
             ->RegisterFileSystemForVirtualPath(
                 storage::kFileSystemTypePluginPrivate,
                 storage::kPluginPrivateRootName, base::FilePath());
     EXPECT_TRUE(storage::ValidateIsolatedFileSystemId(fsid));
-    filesystem_context_->OpenPluginPrivateFileSystem(
-        url::Origin::Create(origin), storage::kFileSystemTypePluginPrivate,
-        fsid, plugin_name, storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
-        base::BindOnce(&BrowsingDataMediaLicenseHelperTest::OnFileSystemOpened,
-                       base::Unretained(this),
-                       await_completion.NotifyClosure()));
-    await_completion.BlockUntilNotified();
-    return fsid;
-  }
 
-  void OnFileSystemOpened(base::OnceClosure done_cb, base::File::Error result) {
+    base::test::TestFuture<base::File::Error> future;
+    filesystem_context_->OpenPluginPrivateFileSystem(
+        origin, storage::kFileSystemTypePluginPrivate, fsid, plugin_name,
+        storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT, future.GetCallback());
+    const base::File::Error result = future.Get();
     EXPECT_EQ(base::File::FILE_OK, result) << base::File::ErrorToString(result);
-    std::move(done_cb).Run();
+    return fsid;
   }
 
   // Creates a file named |file_name| in the PluginPrivateFileSystem identified
   // by |origin| and |fsid|. The file is empty (so size = 0). Returns the URL
   // for the created file. The file must not already exist or the test will
   // fail.
-  storage::FileSystemURL CreateFile(const GURL& origin,
+  storage::FileSystemURL CreateFile(const url::Origin& origin,
                                     const std::string& fsid,
                                     const std::string& file_name) {
-    AwaitCompletionHelper await_completion;
     std::string root = storage::GetIsolatedFileSystemRootURIString(
-        origin, fsid, storage::kPluginPrivateRootName);
+        origin.GetURL(), fsid, storage::kPluginPrivateRootName);
     storage::FileSystemURL file_url =
         filesystem_context_->CrackURLInFirstPartyContext(
             GURL(root + file_name));
@@ -223,46 +165,33 @@
             filesystem_context_));
     operation_context->set_allowed_bytes_growth(
         storage::QuotaManager::kNoLimit);
-    file_util->EnsureFileExists(
-        std::move(operation_context), file_url,
-        base::BindOnce(&BrowsingDataMediaLicenseHelperTest::OnFileCreated,
-                       base::Unretained(this),
-                       await_completion.NotifyClosure()));
-    await_completion.BlockUntilNotified();
-    return file_url;
-  }
 
-  void OnFileCreated(base::OnceClosure done_cb,
-                     base::File::Error result,
-                     bool created) {
+    base::test::TestFuture<base::File::Error, bool> future;
+    file_util->EnsureFileExists(std::move(operation_context), file_url,
+                                future.GetCallback());
+    const base::File::Error result = future.Get<0>();
+    const bool created = future.Get<1>();
     EXPECT_EQ(base::File::FILE_OK, result) << base::File::ErrorToString(result);
     EXPECT_TRUE(created);
-    std::move(done_cb).Run();
+    return file_url;
   }
 
   // Sets the last_access_time and last_modified_time to |time_stamp| on the
   // file specified by |file_url|. The file must already exist.
   void SetFileTimestamp(const storage::FileSystemURL& file_url,
                         const base::Time& time_stamp) {
-    AwaitCompletionHelper await_completion;
     storage::AsyncFileUtil* file_util = filesystem_context_->GetAsyncFileUtil(
         storage::kFileSystemTypePluginPrivate);
     std::unique_ptr<storage::FileSystemOperationContext> operation_context(
         std::make_unique<storage::FileSystemOperationContext>(
             filesystem_context_));
-    file_util->Touch(
-        std::move(operation_context), file_url, time_stamp, time_stamp,
-        base::BindOnce(&BrowsingDataMediaLicenseHelperTest::OnFileTouched,
-                       base::Unretained(this),
-                       await_completion.NotifyClosure()));
-    await_completion.BlockUntilNotified();
-  }
 
-  void OnFileTouched(base::OnceClosure done_cb, base::File::Error result) {
+    base::test::TestFuture<base::File::Error> future;
+    file_util->Touch(std::move(operation_context), file_url, time_stamp,
+                     time_stamp, future.GetCallback());
+    const base::File::Error result = future.Get();
     EXPECT_EQ(base::File::FILE_OK, result) << base::File::ErrorToString(result);
-    std::move(done_cb).Run();
   }
-
   content::BrowserTaskEnvironment task_environment_;
   std::unique_ptr<TestingProfile> profile_;
   scoped_refptr<BrowsingDataMediaLicenseHelper> helper_;
@@ -274,8 +203,7 @@
   raw_ptr<storage::FileSystemContext> filesystem_context_;
 
   // Storage to pass information back from callbacks.
-  std::unique_ptr<std::list<BrowsingDataMediaLicenseHelper::MediaLicenseInfo>>
-      media_license_info_list_;
+  std::unique_ptr<std::list<StorageUsageInfo>> media_license_info_list_;
 };
 
 // Verifies that the BrowsingDataMediaLicenseHelper correctly handles an empty
@@ -288,9 +216,9 @@
 // Verifies that the BrowsingDataMediaLicenseHelper correctly finds the test
 // data, and that each media license returned contains the expected data.
 TEST_F(BrowsingDataMediaLicenseHelperTest, FetchData) {
-  const GURL kOrigin1("http://host1:1");
-  const GURL kOrigin2("http://host2:1");
-  const GURL kOrigin3("http://host3:1");
+  const url::Origin kOrigin1 = url::Origin::Create(GURL("http://host1:1"));
+  const url::Origin kOrigin2 = url::Origin::Create(GURL("http://host2:1"));
+  const url::Origin kOrigin3 = url::Origin::Create(GURL("http://host3:1"));
   PopulateTestMediaLicenseData(kOrigin1, kOrigin2, kOrigin3);
 
   FetchMediaLicenses();
@@ -302,23 +230,24 @@
     if (info.origin == kOrigin1) {
       EXPECT_FALSE(test_hosts_found[0]);
       test_hosts_found[0] = true;
-      EXPECT_EQ(0u, info.size);
+      EXPECT_EQ(0u, info.total_size_bytes);
       // Single file for |origin1| should be 10 days ago.
-      EXPECT_EQ(10, (Now() - info.last_modified_time).InDays());
+      EXPECT_EQ(10, (Now() - info.last_modified).InDays());
     } else if (info.origin == kOrigin2) {
       EXPECT_FALSE(test_hosts_found[1]);
       test_hosts_found[1] = true;
-      EXPECT_EQ(0u, info.size);
+      EXPECT_EQ(0u, info.total_size_bytes);
       // Files for |origin2| are now and 60 days ago, so it should report now.
-      EXPECT_EQ(0, (Now() - info.last_modified_time).InDays());
+      EXPECT_EQ(0, (Now() - info.last_modified).InDays());
     } else if (info.origin == kOrigin3) {
       EXPECT_FALSE(test_hosts_found[2]);
       test_hosts_found[2] = true;
-      EXPECT_EQ(0u, info.size);
+      EXPECT_EQ(0u, info.total_size_bytes);
       // Files for |origin3| are 20 and 30 days ago, so it should report 20.
-      EXPECT_EQ(20, (Now() - info.last_modified_time).InDays());
+      EXPECT_EQ(20, (Now() - info.last_modified).InDays());
     } else {
-      ADD_FAILURE() << info.origin.spec() << " isn't an origin we added.";
+      ADD_FAILURE() << info.origin.GetURL().spec()
+                    << " isn't an origin we added.";
     }
   }
   for (const auto found : test_hosts_found) {
@@ -329,9 +258,9 @@
 // Verifies that the BrowsingDataMediaLicenseHelper correctly deletes media
 // licenses via DeleteMediaLicenseOrigin().
 TEST_F(BrowsingDataMediaLicenseHelperTest, DeleteData) {
-  const GURL kOrigin1("http://host1:1");
-  const GURL kOrigin2("http://host2:1");
-  const GURL kOrigin3("http://host3:1");
+  const url::Origin kOrigin1 = url::Origin::Create(GURL("http://host1:1"));
+  const url::Origin kOrigin2 = url::Origin::Create(GURL("http://host2:1"));
+  const url::Origin kOrigin3 = url::Origin::Create(GURL("http://host3:1"));
   PopulateTestMediaLicenseData(kOrigin1, kOrigin2, kOrigin3);
 
   DeleteMediaLicenseOrigin(kOrigin1);
@@ -340,11 +269,10 @@
   FetchMediaLicenses();
   EXPECT_EQ(1u, ReturnedMediaLicenseInfo()->size());
 
-  BrowsingDataMediaLicenseHelper::MediaLicenseInfo info =
-      *(ReturnedMediaLicenseInfo()->begin());
+  StorageUsageInfo info = *(ReturnedMediaLicenseInfo()->begin());
   EXPECT_EQ(kOrigin3, info.origin);
-  EXPECT_EQ(0u, info.size);
-  EXPECT_EQ(20, (Now() - info.last_modified_time).InDays());
+  EXPECT_EQ(0u, info.total_size_bytes);
+  EXPECT_EQ(20, (Now() - info.last_modified).InDays());
 }
 
 }  // namespace
diff --git a/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc b/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc
index 9f71481..362011a 100644
--- a/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc
+++ b/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc
@@ -39,6 +39,7 @@
 #include "components/sync/driver/test_sync_service.h"
 #include "content/public/browser/browsing_data_filter_builder.h"
 #include "content/public/browser/storage_partition.h"
+#include "content/public/browser/storage_usage_info.h"
 #include "content/public/common/content_paths.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/network_service_util.h"
@@ -182,12 +183,11 @@
         BrowsingDataMediaLicenseHelper::Create(
             partition->GetFileSystemContext());
     media_license_helper->StartFetching(base::BindLambdaForTesting(
-        [&](const std::list<BrowsingDataMediaLicenseHelper::MediaLicenseInfo>&
-                licenses) {
+        [&](const std::list<content::StorageUsageInfo>& licenses) {
           count = licenses.size();
           LOG(INFO) << "Found " << count << " licenses.";
           for (const auto& license : licenses)
-            LOG(INFO) << license.last_modified_time;
+            LOG(INFO) << license.last_modified;
           run_loop.Quit();
         }));
     run_loop.Run();
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
index 669e58f..c7a881b4 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -1039,7 +1039,7 @@
     // clearing only a specified set of sites.
     if (filter_builder->GetMode() != BrowsingDataFilterBuilder::Mode::kDelete) {
       const user_manager::User* user =
-          chromeos::ProfileHelper::Get()->GetUserByProfile(profile_);
+          ash::ProfileHelper::Get()->GetUserByProfile(profile_);
       if (!user) {
         LOG(WARNING) << "Failed to find user for current profile.";
       } else {
diff --git a/chrome/browser/browsing_data/cookies_tree_model.cc b/chrome/browser/browsing_data/cookies_tree_model.cc
index bbe19bb..fbcc38e 100644
--- a/chrome/browser/browsing_data/cookies_tree_model.cc
+++ b/chrome/browser/browsing_data/cookies_tree_model.cc
@@ -295,10 +295,10 @@
 }
 
 CookieTreeNode::DetailedInfo& CookieTreeNode::DetailedInfo::InitMediaLicense(
-    const BrowsingDataMediaLicenseHelper::MediaLicenseInfo* media_license) {
+    const content::StorageUsageInfo* storage_usage_info) {
   Init(TYPE_MEDIA_LICENSE);
-  media_license_info = media_license;
-  origin = url::Origin::Create(media_license_info->origin);
+  media_license_usage_info = storage_usage_info;
+  origin = media_license_usage_info->origin;
   return *this;
 }
 
@@ -797,13 +797,14 @@
  public:
   friend class CookieTreeMediaLicensesNode;
 
-  // |media_license_info| is expected to remain valid as long as the
+  // |media_license_usage_info| is expected to remain valid as long as the
   // CookieTreeMediaLicenseNode is valid.
   explicit CookieTreeMediaLicenseNode(
-      const std::list<BrowsingDataMediaLicenseHelper::MediaLicenseInfo>::
-          iterator media_license_info)
-      : CookieTreeNode(base::UTF8ToUTF16(media_license_info->origin.spec())),
-        media_license_info_(media_license_info) {}
+      const std::list<content::StorageUsageInfo>::iterator
+          media_license_usage_info)
+      : CookieTreeNode(base::UTF8ToUTF16(
+            media_license_usage_info->origin.GetURL().spec())),
+        media_license_usage_info_(media_license_usage_info) {}
 
   CookieTreeMediaLicenseNode(const CookieTreeMediaLicenseNode&) = delete;
   CookieTreeMediaLicenseNode& operator=(const CookieTreeMediaLicenseNode&) =
@@ -816,22 +817,23 @@
 
     if (container) {
       container->media_license_helper_->DeleteMediaLicenseOrigin(
-          media_license_info_->origin);
-      container->media_license_info_list_.erase(media_license_info_);
+          media_license_usage_info_->origin);
+      container->media_license_info_list_.erase(media_license_usage_info_);
     }
   }
 
   DetailedInfo GetDetailedInfo() const override {
-    return DetailedInfo().InitMediaLicense(&*media_license_info_);
+    return DetailedInfo().InitMediaLicense(&*media_license_usage_info_);
   }
 
-  int64_t InclusiveSize() const override { return media_license_info_->size; }
+  int64_t InclusiveSize() const override {
+    return media_license_usage_info_->total_size_bytes;
+  }
 
  private:
-  // |media_license_info_| is expected to remain valid as long as the
+  // |media_license_usage_info_| is expected to remain valid as long as the
   // CookieTreeMediaLicenseNode is valid.
-  std::list<BrowsingDataMediaLicenseHelper::MediaLicenseInfo>::iterator
-      media_license_info_;
+  std::list<content::StorageUsageInfo>::iterator media_license_usage_info_;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1803,10 +1805,9 @@
     return;
 
   notifier->StartBatchUpdate();
-  for (auto media_license_info = container->media_license_info_list_.begin();
-       media_license_info != container->media_license_info_list_.end();
-       ++media_license_info) {
-    GURL origin(media_license_info->origin);
+  for (auto usage_info = container->media_license_info_list_.begin();
+       usage_info != container->media_license_info_list_.end(); ++usage_info) {
+    GURL origin(usage_info->origin.GetURL());
 
     if (filter.empty() || (CookieTreeHostNode::TitleForUrl(origin).find(
                                filter) != std::u16string::npos)) {
@@ -1814,7 +1815,7 @@
       CookieTreeMediaLicensesNode* media_licenses_node =
           host_node->GetOrCreateMediaLicensesNode();
       media_licenses_node->AddMediaLicenseNode(
-          std::make_unique<CookieTreeMediaLicenseNode>(media_license_info));
+          std::make_unique<CookieTreeMediaLicenseNode>(usage_info));
     }
   }
 }
diff --git a/chrome/browser/browsing_data/cookies_tree_model.h b/chrome/browser/browsing_data/cookies_tree_model.h
index 87ad4b6..cd01fdc 100644
--- a/chrome/browser/browsing_data/cookies_tree_model.h
+++ b/chrome/browser/browsing_data/cookies_tree_model.h
@@ -120,7 +120,7 @@
     DetailedInfo& InitCacheStorage(
         const content::StorageUsageInfo* storage_usage_info);
     DetailedInfo& InitMediaLicense(
-        const BrowsingDataMediaLicenseHelper::MediaLicenseInfo* media_license);
+        const content::StorageUsageInfo* storage_usage_info);
 
     NodeType node_type;
     url::Origin origin;
@@ -133,8 +133,7 @@
     raw_ptr<const BrowsingDataQuotaHelper::QuotaInfo> quota_info = nullptr;
     raw_ptr<const browsing_data::SharedWorkerHelper::SharedWorkerInfo>
         shared_worker_info = nullptr;
-    raw_ptr<const BrowsingDataMediaLicenseHelper::MediaLicenseInfo>
-        media_license_info = nullptr;
+    raw_ptr<const content::StorageUsageInfo> media_license_usage_info = nullptr;
   };
 
   CookieTreeNode() {}
diff --git a/chrome/browser/browsing_data/cookies_tree_model_unittest.cc b/chrome/browser/browsing_data/cookies_tree_model_unittest.cc
index 8b719d9..b7f1275 100644
--- a/chrome/browser/browsing_data/cookies_tree_model_unittest.cc
+++ b/chrome/browser/browsing_data/cookies_tree_model_unittest.cc
@@ -290,7 +290,10 @@
       case CookieTreeNode::DetailedInfo::TYPE_SHARED_WORKER:
         return node->GetDetailedInfo().shared_worker_info->worker.spec() + ",";
       case CookieTreeNode::DetailedInfo::TYPE_MEDIA_LICENSE:
-        return node->GetDetailedInfo().media_license_info->origin.spec() + ",";
+        return node->GetDetailedInfo()
+                   .media_license_usage_info->origin.GetURL()
+                   .spec() +
+               ",";
       default:
         return std::string();
     }
diff --git a/chrome/browser/browsing_data/counters/site_data_counting_helper.cc b/chrome/browser/browsing_data/counters/site_data_counting_helper.cc
index a1a26d7e..a6ebe70 100644
--- a/chrome/browser/browsing_data/counters/site_data_counting_helper.cc
+++ b/chrome/browser/browsing_data/counters/site_data_counting_helper.cc
@@ -183,12 +183,11 @@
 }
 
 void SiteDataCountingHelper::SitesWithMediaLicensesCallback(
-    const std::list<BrowsingDataMediaLicenseHelper::MediaLicenseInfo>&
-        media_license_info_list) {
+    const std::list<content::StorageUsageInfo>& media_license_usage_info_list) {
   std::vector<GURL> origins;
-  for (const auto& info : media_license_info_list) {
-    if (info.last_modified_time >= begin_ && info.last_modified_time < end_)
-      origins.push_back(info.origin);
+  for (const auto& info : media_license_usage_info_list) {
+    if (info.last_modified >= begin_ && info.last_modified < end_)
+      origins.push_back(info.origin.GetURL());
   }
   Done(origins);
 }
diff --git a/chrome/browser/browsing_data/counters/site_data_counting_helper.h b/chrome/browser/browsing_data/counters/site_data_counting_helper.h
index 72bb5ef..4770622 100644
--- a/chrome/browser/browsing_data/counters/site_data_counting_helper.h
+++ b/chrome/browser/browsing_data/counters/site_data_counting_helper.h
@@ -53,8 +53,8 @@
   void GetQuotaBucketsCallback(const std::set<storage::BucketLocator>& buckets,
                                blink::mojom::StorageType type);
   void SitesWithMediaLicensesCallback(
-      const std::list<BrowsingDataMediaLicenseHelper::MediaLicenseInfo>&
-          media_license_info_list);
+      const std::list<content::StorageUsageInfo>&
+          media_license_usage_info_list);
 
   void Done(const std::vector<GURL>& origins);
 
diff --git a/chrome/browser/browsing_data/incognito_browsing_data_browsertest.cc b/chrome/browser/browsing_data/incognito_browsing_data_browsertest.cc
index 34d6956e..bbba2ca 100644
--- a/chrome/browser/browsing_data/incognito_browsing_data_browsertest.cc
+++ b/chrome/browser/browsing_data/incognito_browsing_data_browsertest.cc
@@ -28,6 +28,7 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/storage_partition.h"
+#include "content/public/browser/storage_usage_info.h"
 #include "content/public/common/content_paths.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test.h"
@@ -165,12 +166,11 @@
         BrowsingDataMediaLicenseHelper::Create(
             partition->GetFileSystemContext());
     media_license_helper->StartFetching(base::BindLambdaForTesting(
-        [&](const std::list<BrowsingDataMediaLicenseHelper::MediaLicenseInfo>&
-                licenses) {
+        [&](const std::list<content::StorageUsageInfo>& licenses) {
           count = licenses.size();
           LOG(INFO) << "Found " << count << " licenses.";
           for (const auto& license : licenses)
-            LOG(INFO) << license.last_modified_time;
+            LOG(INFO) << license.last_modified;
           run_loop.Quit();
         }));
     run_loop.Run();
diff --git a/chrome/browser/browsing_data/local_data_container.cc b/chrome/browser/browsing_data/local_data_container.cc
index ee18cba..ff05ee29 100644
--- a/chrome/browser/browsing_data/local_data_container.cc
+++ b/chrome/browser/browsing_data/local_data_container.cc
@@ -198,7 +198,7 @@
 }
 
 void LocalDataContainer::OnMediaLicenseInfoLoaded(
-    const MediaLicenseInfoList& media_license_info) {
+    const MediaLicenseUsageInfoList& media_license_info) {
   media_license_info_list_ = media_license_info;
   DCHECK(model_);
   model_->PopulateMediaLicenseInfo(this);
diff --git a/chrome/browser/browsing_data/local_data_container.h b/chrome/browser/browsing_data/local_data_container.h
index 430dfa7..3d33a15f 100644
--- a/chrome/browser/browsing_data/local_data_container.h
+++ b/chrome/browser/browsing_data/local_data_container.h
@@ -55,8 +55,7 @@
   using SharedWorkerInfoList =
       std::list<browsing_data::SharedWorkerHelper::SharedWorkerInfo>;
   using CacheStorageUsageInfoList = std::list<content::StorageUsageInfo>;
-  using MediaLicenseInfoList =
-      std::list<BrowsingDataMediaLicenseHelper::MediaLicenseInfo>;
+  using MediaLicenseUsageInfoList = std::list<content::StorageUsageInfo>;
 
   LocalDataContainer(
       scoped_refptr<browsing_data::CookieHelper> cookie_helper,
@@ -111,7 +110,8 @@
   void OnSharedWorkerInfoLoaded(const SharedWorkerInfoList& shared_worker_info);
   void OnCacheStorageModelInfoLoaded(
       const CacheStorageUsageInfoList& cache_storage_info);
-  void OnMediaLicenseInfoLoaded(const MediaLicenseInfoList& media_license_info);
+  void OnMediaLicenseInfoLoaded(
+      const MediaLicenseUsageInfoList& media_license_usage_info);
 
   // Pointers to the helper objects, needed to retreive all the types of locally
   // stored data.
@@ -139,7 +139,7 @@
   ServiceWorkerUsageInfoList service_worker_info_list_;
   SharedWorkerInfoList shared_worker_info_list_;
   CacheStorageUsageInfoList cache_storage_info_list_;
-  MediaLicenseInfoList media_license_info_list_;
+  MediaLicenseUsageInfoList media_license_info_list_;
 
   // A delegate, which must outlive this object. The update callbacks use the
   // delegate to deliver the updated data to the CookieTreeModel.
diff --git a/chrome/browser/browsing_data/mock_browsing_data_media_license_helper.cc b/chrome/browser/browsing_data/mock_browsing_data_media_license_helper.cc
index cc0e7a3c..1f202e88 100644
--- a/chrome/browser/browsing_data/mock_browsing_data_media_license_helper.cc
+++ b/chrome/browser/browsing_data/mock_browsing_data_media_license_helper.cc
@@ -6,7 +6,10 @@
 
 #include <algorithm>
 
+#include "content/public/browser/storage_usage_info.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+#include "url/origin.h"
 
 MockBrowsingDataMediaLicenseHelper::MockBrowsingDataMediaLicenseHelper(
     Profile* profile) {}
@@ -20,9 +23,9 @@
 }
 
 void MockBrowsingDataMediaLicenseHelper::DeleteMediaLicenseOrigin(
-    const GURL& origin) {
+    const url::Origin& origin) {
   auto entry = std::find_if(media_licenses_.begin(), media_licenses_.end(),
-                            [origin](const MediaLicenseInfo& entry) {
+                            [origin](const content::StorageUsageInfo& entry) {
                               return entry.origin == origin;
                             });
   ASSERT_TRUE(entry != media_licenses_.end());
@@ -30,13 +33,13 @@
 }
 
 void MockBrowsingDataMediaLicenseHelper::AddMediaLicenseSamples() {
-  const GURL kOrigin1("https://media1/");
-  const GURL kOrigin2("https://media2/");
+  const url::Origin kOrigin1 = url::Origin::Create(GURL("https://media1/"));
+  const url::Origin kOrigin2 = url::Origin::Create(GURL("https://media2/"));
   const base::Time ten_days_ago = base::Time::Now() - base::Days(10);
   const base::Time twenty_days_ago = base::Time::Now() - base::Days(20);
 
-  media_licenses_.push_back(MediaLicenseInfo(kOrigin1, 1000, ten_days_ago));
-  media_licenses_.push_back(MediaLicenseInfo(kOrigin2, 50, twenty_days_ago));
+  media_licenses_.emplace_back(kOrigin1, 1000, ten_days_ago);
+  media_licenses_.emplace_back(kOrigin2, 50, twenty_days_ago);
 }
 
 void MockBrowsingDataMediaLicenseHelper::Notify() {
diff --git a/chrome/browser/browsing_data/mock_browsing_data_media_license_helper.h b/chrome/browser/browsing_data/mock_browsing_data_media_license_helper.h
index 7d0f71e373..3c3dfc47 100644
--- a/chrome/browser/browsing_data/mock_browsing_data_media_license_helper.h
+++ b/chrome/browser/browsing_data/mock_browsing_data_media_license_helper.h
@@ -11,7 +11,14 @@
 #include "base/callback.h"
 #include "chrome/browser/browsing_data/browsing_data_media_license_helper.h"
 #include "chrome/browser/profiles/profile.h"
-#include "url/gurl.h"
+
+namespace content {
+struct StorageUsageInfo;
+}  // namespace content
+
+namespace url {
+class Origin;
+}  // namespace url
 
 class MockBrowsingDataMediaLicenseHelper
     : public BrowsingDataMediaLicenseHelper {
@@ -25,7 +32,7 @@
 
   // BrowsingDataMediaLicenseHelper implementation:
   void StartFetching(FetchCallback callback) override;
-  void DeleteMediaLicenseOrigin(const GURL& origin) override;
+  void DeleteMediaLicenseOrigin(const url::Origin& origin) override;
 
   // Add some MediaLicenseInfo samples.
   void AddMediaLicenseSamples();
@@ -41,7 +48,7 @@
 
  private:
   FetchCallback callback_;
-  std::list<MediaLicenseInfo> media_licenses_;
+  std::list<content::StorageUsageInfo> media_licenses_;
 };
 
 #endif  // CHROME_BROWSER_BROWSING_DATA_MOCK_BROWSING_DATA_MEDIA_LICENSE_HELPER_H_
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 58ef5f5..6852ada 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -3015,9 +3015,9 @@
 // no certificate got auto-selected.
 bool CanPromptWithNonmatchingCertificates(const Profile* profile) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  if (chromeos::ProfileHelper::IsSigninProfile(profile) ||
-      chromeos::ProfileHelper::IsLockScreenProfile(profile) ||
-      chromeos::ProfileHelper::IsLockScreenAppProfile(profile)) {
+  if (ash::ProfileHelper::IsSigninProfile(profile) ||
+      ash::ProfileHelper::IsLockScreenProfile(profile) ||
+      ash::ProfileHelper::IsLockScreenAppProfile(profile)) {
     // On non-regular profiles (e.g. sign-in profile or lock-screen profile),
     // never show certificate selection to the user. A client certificate is an
     // identifier that can be stable for a long time, so only the administrator
@@ -3071,9 +3071,9 @@
   // context of the sign-in frame.
   // Note that this is explicitly not happening for the lock screen app profile
   // which does not support a gaia / SAML IdP sign-in frame.
-  if (chromeos::ProfileHelper::IsSigninProfile(profile) ||
-      chromeos::ProfileHelper::IsLockScreenProfile(profile)) {
-    const char* profile_name = chromeos::ProfileHelper::IsSigninProfile(profile)
+  if (ash::ProfileHelper::IsSigninProfile(profile) ||
+      ash::ProfileHelper::IsLockScreenProfile(profile)) {
+    const char* profile_name = ash::ProfileHelper::IsSigninProfile(profile)
                                    ? "sign-in"
                                    : "lock screen";
     content::StoragePartition* storage_partition =
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index df6adea..7f1d29e 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -854,6 +854,8 @@
     "../ash/arc/input_overlay/actions/action_label.h",
     "../ash/arc/input_overlay/actions/action_move_key.cc",
     "../ash/arc/input_overlay/actions/action_move_key.h",
+    "../ash/arc/input_overlay/actions/action_move_mouse.cc",
+    "../ash/arc/input_overlay/actions/action_move_mouse.h",
     "../ash/arc/input_overlay/actions/action_tap_key.cc",
     "../ash/arc/input_overlay/actions/action_tap_key.h",
     "../ash/arc/input_overlay/actions/dependent_position.cc",
@@ -3959,7 +3961,6 @@
     "../ash/arc/input_overlay/actions/position_unittest.cc",
     "../ash/arc/input_overlay/arc_input_overlay_manager_unittest.cc",
     "../ash/arc/input_overlay/display_overlay_controller_unittest.cc",
-    "../ash/arc/input_overlay/input_overlay_resources_util_unittest.cc",
     "../ash/arc/input_overlay/test/arc_test_window.cc",
     "../ash/arc/input_overlay/test/arc_test_window.h",
     "../ash/arc/input_overlay/test/event_capturer.cc",
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
index 93bb958..763c7c7 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
@@ -118,7 +118,7 @@
       continue;
     original_profiles.insert(profile);
     const user_manager::User* const user =
-        chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+        ash::ProfileHelper::Get()->GetUserByProfile(profile);
     if (!user || !user->is_logged_in())
       continue;
 
@@ -210,9 +210,8 @@
 
 ExtensionFunction::ResponseAction
 FileManagerPrivateLogoutUserForReauthenticationFunction::Run() {
-  const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(
-          Profile::FromBrowserContext(browser_context()));
+  const user_manager::User* user = ash::ProfileHelper::Get()->GetUserByProfile(
+      Profile::FromBrowserContext(browser_context()));
   if (user) {
     user_manager::UserManager::Get()->SaveUserOAuthStatus(
         user->GetAccountId(), user_manager::User::OAUTH2_TOKEN_STATUS_INVALID);
diff --git a/chrome/browser/chromeos/extensions/gfx_utils.cc b/chrome/browser/chromeos/extensions/gfx_utils.cc
index f70b9556..e141b86 100644
--- a/chrome/browser/chromeos/extensions/gfx_utils.cc
+++ b/chrome/browser/chromeos/extensions/gfx_utils.cc
@@ -200,7 +200,7 @@
 
   Profile* profile = Profile::FromBrowserContext(context);
   // Only apply Chrome badge for the primary profile.
-  if (!chromeos::ProfileHelper::IsPrimaryProfile(profile) ||
+  if (!ash::ProfileHelper::IsPrimaryProfile(profile) ||
       !multi_user_util::IsProfileFromActiveUser(profile)) {
     return false;
   }
@@ -221,7 +221,7 @@
 
   Profile* profile = Profile::FromBrowserContext(context);
   // Only apply Chrome badge for the primary profile.
-  if (!chromeos::ProfileHelper::IsPrimaryProfile(profile) ||
+  if (!ash::ProfileHelper::IsPrimaryProfile(profile) ||
       !multi_user_util::IsProfileFromActiveUser(profile)) {
     return false;
   }
diff --git a/chrome/browser/chromeos/extensions/info_private_api.cc b/chrome/browser/chromeos/extensions/info_private_api.cc
index 5c2dfa3..a03b051 100644
--- a/chrome/browser/chromeos/extensions/info_private_api.cc
+++ b/chrome/browser/chromeos/extensions/info_private_api.cc
@@ -449,7 +449,7 @@
           ->SetString(prefs::kUserTimezone, param_value);
     } else {
       const user_manager::User* user =
-          chromeos::ProfileHelper::Get()->GetUserByProfile(
+          ash::ProfileHelper::Get()->GetUserByProfile(
               Profile::FromBrowserContext(browser_context()));
       if (user)
         ash::system::SetSystemTimezone(user, param_value);
diff --git a/chrome/browser/chromeos/extensions/login_screen/login/cleanup/extension_cleanup_handler_browsertest.cc b/chrome/browser/chromeos/extensions/login_screen/login/cleanup/extension_cleanup_handler_browsertest.cc
index 668774a9..6f7f857 100644
--- a/chrome/browser/chromeos/extensions/login_screen/login/cleanup/extension_cleanup_handler_browsertest.cc
+++ b/chrome/browser/chromeos/extensions/login_screen/login/cleanup/extension_cleanup_handler_browsertest.cc
@@ -123,7 +123,7 @@
   Profile* GetActiveUserProfile() {
     const user_manager::User* active_user =
         user_manager::UserManager::Get()->GetActiveUser();
-    return chromeos::ProfileHelper::Get()->GetProfileByUser(active_user);
+    return ash::ProfileHelper::Get()->GetProfileByUser(active_user);
   }
 
   void InstallUserExtension(const std::string& extension_id) {
diff --git a/chrome/browser/chromeos/extensions/login_screen/login/login_api.cc b/chrome/browser/chromeos/extensions/login_screen/login/login_api.cc
index 26214cf..b5e017d 100644
--- a/chrome/browser/chromeos/extensions/login_screen/login/login_api.cc
+++ b/chrome/browser/chromeos/extensions/login_screen/login/login_api.cc
@@ -33,7 +33,7 @@
 namespace {
 
 std::string GetLaunchExtensionIdPrefValue(const user_manager::User* user) {
-  Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+  Profile* profile = ash::ProfileHelper::Get()->GetProfileByUser(user);
   DCHECK(profile);
   PrefService* prefs = profile->GetPrefs();
   return prefs->GetString(prefs::kLoginExtensionApiLaunchExtensionId);
diff --git a/chrome/browser/chromeos/extensions/login_screen/login/login_api_unittest.cc b/chrome/browser/chromeos/extensions/login_screen/login/login_api_unittest.cc
index e7b81f2..2d60a1c 100644
--- a/chrome/browser/chromeos/extensions/login_screen/login/login_api_unittest.cc
+++ b/chrome/browser/chromeos/extensions/login_screen/login/login_api_unittest.cc
@@ -189,8 +189,7 @@
     user_manager::User* user =
         fake_chrome_user_manager_->AddPublicAccountUser(account_id);
     TestingProfile* profile = profile_manager()->CreateTestingProfile(email);
-    chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(user,
-                                                                      profile);
+    ash::ProfileHelper::Get()->SetUserToProfileMappingForTesting(user, profile);
 
     return std::make_unique<ScopedTestingProfile>(profile, profile_manager());
   }
diff --git a/chrome/browser/chromeos/extensions/login_screen/login/login_apitest.cc b/chrome/browser/chromeos/extensions/login_screen/login/login_apitest.cc
index 948a42b..ad2539d6 100644
--- a/chrome/browser/chromeos/extensions/login_screen/login/login_apitest.cc
+++ b/chrome/browser/chromeos/extensions/login_screen/login/login_apitest.cc
@@ -152,8 +152,7 @@
   GetTestExtensionRegistryObserver(const std::string& extension_id) {
     const user_manager::User* active_user =
         user_manager::UserManager::Get()->GetActiveUser();
-    Profile* profile =
-        chromeos::ProfileHelper::Get()->GetProfileByUser(active_user);
+    Profile* profile = ash::ProfileHelper::Get()->GetProfileByUser(active_user);
     return std::make_unique<extensions::TestExtensionRegistryObserver>(
         extensions::ExtensionRegistry::Get(profile), extension_id);
   }
@@ -378,8 +377,7 @@
 
   const user_manager::User* active_user =
       user_manager::UserManager::Get()->GetActiveUser();
-  Profile* profile =
-      chromeos::ProfileHelper::Get()->GetProfileByUser(active_user);
+  Profile* profile = ash::ProfileHelper::Get()->GetProfileByUser(active_user);
   PrefService* prefs = profile->GetPrefs();
   prefs->SetString(prefs::kLoginExtensionApiLaunchExtensionId,
                    kWrongExtensionId);
diff --git a/chrome/browser/chromeos/extensions/login_screen/login_state/login_state_api_unittest.cc b/chrome/browser/chromeos/extensions/login_screen/login_state/login_state_api_unittest.cc
index 2479068..f5103e0 100644
--- a/chrome/browser/chromeos/extensions/login_screen/login_state/login_state_api_unittest.cc
+++ b/chrome/browser/chromeos/extensions/login_screen/login_state/login_state_api_unittest.cc
@@ -61,7 +61,7 @@
 // Test that |loginState.getProfileType()| returns |SIGNIN_PROFILE| for
 // extensions running in the signin profile.
 TEST_F(LoginStateApiUnittest, GetProfileType_SigninProfile) {
-  // |chromeos::ProfileHelper::GetSigninProfile()| cannot be used as the
+  // |ash::ProfileHelper::GetSigninProfile()| cannot be used as the
   // |TestingProfileManager| set up by |BrowserWithTestWindowTest| has an empty
   // user data directory.
   TestingProfile::Builder builder;
diff --git a/chrome/browser/chromeos/extensions/users_private/users_private_api.cc b/chrome/browser/chromeos/extensions/users_private/users_private_api.cc
index 71eba8a..df1abc4e 100644
--- a/chrome/browser/chromeos/extensions/users_private/users_private_api.cc
+++ b/chrome/browser/chromeos/extensions/users_private/users_private_api.cc
@@ -44,7 +44,7 @@
 
 bool IsChild(Profile* profile) {
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   if (!user)
     return false;
 
@@ -277,9 +277,8 @@
     default;
 
 ExtensionFunction::ResponseAction UsersPrivateGetCurrentUserFunction::Run() {
-  const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(
-          Profile::FromBrowserContext(browser_context()));
+  const user_manager::User* user = ash::ProfileHelper::Get()->GetUserByProfile(
+      Profile::FromBrowserContext(browser_context()));
   return user ? RespondNow(OneArgument(base::Value::FromUniquePtrValue(
                     CreateApiUser(user->GetAccountId().GetUserEmail(), *user)
                         .ToValue())))
diff --git a/chrome/browser/chromeos/extensions/wallpaper_api.cc b/chrome/browser/chromeos/extensions/wallpaper_api.cc
index 4ce0a41..ceaecab7 100644
--- a/chrome/browser/chromeos/extensions/wallpaper_api.cc
+++ b/chrome/browser/chromeos/extensions/wallpaper_api.cc
@@ -137,7 +137,7 @@
   Profile* profile = Profile::FromBrowserContext(context);
   DCHECK(profile);
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   DCHECK(user);
   return user;
 }
diff --git a/chrome/browser/chromeos/extensions/wallpaper_private_api.cc b/chrome/browser/chromeos/extensions/wallpaper_private_api.cc
index 98401f0f..f27a8b3 100644
--- a/chrome/browser/chromeos/extensions/wallpaper_private_api.cc
+++ b/chrome/browser/chromeos/extensions/wallpaper_private_api.cc
@@ -127,7 +127,7 @@
   Profile* profile = Profile::FromBrowserContext(context);
   DCHECK(profile);
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   DCHECK(user);
   return user;
 }
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_rules_manager_factory.cc b/chrome/browser/chromeos/policy/dlp/dlp_rules_manager_factory.cc
index 9a2b058..3f550d4 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_rules_manager_factory.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_rules_manager_factory.cc
@@ -34,7 +34,7 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   // UserManager might be not available in tests.
   is_main_profile = user_manager::UserManager::IsInitialized() &&
-                    chromeos::ProfileHelper::IsPrimaryProfile(profile);
+                    ash::ProfileHelper::IsPrimaryProfile(profile);
 #elif BUILDFLAG(IS_CHROMEOS_LACROS)
   // DLP policy is not per-profile yet and hence currently we do not
   // support secondary profiles. DLP policy is instantiated once with
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_rules_manager_impl.cc b/chrome/browser/chromeos/policy/dlp/dlp_rules_manager_impl.cc
index 752880f..c927dfc 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_rules_manager_impl.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_rules_manager_impl.cc
@@ -250,8 +250,7 @@
          restriction == Restriction::kFiles);
 
   // Allow copy/paste within the same document.
-  if (url::Origin::Create(source).IsSameOriginWith(
-          url::Origin::Create(destination)))
+  if (url::IsSameOriginWith(source, destination))
     return Level::kAllow;
 
   const RulesConditionsMap src_rules_map = MatchUrlAndGetRulesMapping(
diff --git a/chrome/browser/download/download_prefs_unittest.cc b/chrome/browser/download/download_prefs_unittest.cc
index f45ae7f..e088dd3 100644
--- a/chrome/browser/download/download_prefs_unittest.cc
+++ b/chrome/browser/download/download_prefs_unittest.cc
@@ -510,9 +510,9 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
     ash::FakeChromeUserManager user_manager;
     const auto* user = user_manager.AddUser(account_id);
-    chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
-        user, &profile2);
-    chromeos::ProfileHelper::Get()->SetProfileToUserMappingForTesting(
+    ash::ProfileHelper::Get()->SetUserToProfileMappingForTesting(user,
+                                                                 &profile2);
+    ash::ProfileHelper::Get()->SetProfileToUserMappingForTesting(
         const_cast<user_manager::User*>(user));
     profile2.GetPrefs()->SetString(drive::prefs::kDriveFsProfileSalt,
                                    drivefs_profile_salt);
diff --git a/chrome/browser/download/notification/download_notification_browsertest.cc b/chrome/browser/download/notification/download_notification_browsertest.cc
index cd73426..fda2441 100644
--- a/chrome/browser/download/notification/download_notification_browsertest.cc
+++ b/chrome/browser/download/notification/download_notification_browsertest.cc
@@ -1220,7 +1220,7 @@
   }
 
   Profile* GetProfileByIndex(int index) {
-    return chromeos::ProfileHelper::GetProfileByUserIdHashForTest(
+    return ash::ProfileHelper::GetProfileByUserIdHashForTest(
         kTestAccounts[index].hash);
   }
 
@@ -1235,7 +1235,7 @@
         AccountId::FromUserEmailGaiaId(info.email, info.gaia_id),
         base::UTF8ToUTF16(info.display_name));
     Profile* profile =
-        chromeos::ProfileHelper::GetProfileByUserIdHashForTest(info.hash);
+        ash::ProfileHelper::GetProfileByUserIdHashForTest(info.hash);
 
     signin::IdentityManager* identity_manager =
         IdentityManagerFactory::GetForProfile(profile);
diff --git a/chrome/browser/drive/drive_notification_manager_factory_browsertest.cc b/chrome/browser/drive/drive_notification_manager_factory_browsertest.cc
index 50068fb..b8c73ab6 100644
--- a/chrome/browser/drive/drive_notification_manager_factory_browsertest.cc
+++ b/chrome/browser/drive/drive_notification_manager_factory_browsertest.cc
@@ -33,7 +33,7 @@
 IN_PROC_BROWSER_TEST_F(DriveNotificationManagerFactoryLoginScreenBrowserTest,
                        NoDriveNotificationManager) {
   Profile* signin_profile =
-      chromeos::ProfileHelper::GetSigninProfile()->GetOriginalProfile();
+      ash::ProfileHelper::GetSigninProfile()->GetOriginalProfile();
   EXPECT_FALSE(DriveNotificationManagerFactory::FindForBrowserContext(
       signin_profile));
 }
@@ -58,11 +58,11 @@
   user_manager::UserManager* user_manager = user_manager::UserManager::Get();
   EXPECT_TRUE(user_manager->IsLoggedInAsGuest());
   Profile* guest_profile =
-      chromeos::ProfileHelper::Get()
+      ash::ProfileHelper::Get()
           ->GetProfileByUserUnsafe(user_manager->GetActiveUser())
           ->GetOriginalProfile();
   Profile* signin_profile =
-      chromeos::ProfileHelper::GetSigninProfile()->GetOriginalProfile();
+      ash::ProfileHelper::GetSigninProfile()->GetOriginalProfile();
   EXPECT_FALSE(DriveNotificationManagerFactory::FindForBrowserContext(
       guest_profile));
   EXPECT_FALSE(DriveNotificationManagerFactory::FindForBrowserContext(
diff --git a/chrome/browser/enterprise/browser_management/browser_management_status_provider.cc b/chrome/browser/enterprise/browser_management/browser_management_status_provider.cc
index 7259e6a..a3ebeb0 100644
--- a/chrome/browser/enterprise/browser_management/browser_management_status_provider.cc
+++ b/chrome/browser/enterprise/browser_management/browser_management_status_provider.cc
@@ -92,7 +92,7 @@
   auto* primary_user = user_manager::UserManager::Get()->GetPrimaryUser();
   if (primary_user &&
       IsProfileManaged(
-          chromeos::ProfileHelper::Get()->GetProfileByUser(primary_user))) {
+          ash::ProfileHelper::Get()->GetProfileByUser(primary_user))) {
     return EnterpriseManagementAuthority::CLOUD;
   }
 #endif
diff --git a/chrome/browser/enterprise/connectors/connectors_service.cc b/chrome/browser/enterprise/connectors/connectors_service.cc
index 337c6218..140ecbf 100644
--- a/chrome/browser/enterprise/connectors/connectors_service.cc
+++ b/chrome/browser/enterprise/connectors/connectors_service.cc
@@ -561,7 +561,7 @@
   Profile* profile = Profile::FromBrowserContext(context_);
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   const bool include_device_info = user && user->IsAffiliated();
 #elif BUILDFLAG(IS_CHROMEOS_LACROS)
   const bool include_device_info =
diff --git a/chrome/browser/enterprise/reporting/browser_report_generator_desktop.cc b/chrome/browser/enterprise/reporting/browser_report_generator_desktop.cc
index 0d1c467e..0143280 100644
--- a/chrome/browser/enterprise/reporting/browser_report_generator_desktop.cc
+++ b/chrome/browser/enterprise/reporting/browser_report_generator_desktop.cc
@@ -58,7 +58,7 @@
                                .GetAllProfilesAttributes()) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
     // Skip sign-in and lock screen app profile on Chrome OS.
-    if (!chromeos::ProfileHelper::IsRegularProfilePath(
+    if (!ash::ProfileHelper::IsRegularProfilePath(
             entry->GetPath().BaseName())) {
       continue;
     }
diff --git a/chrome/browser/enterprise/util/managed_browser_utils.cc b/chrome/browser/enterprise/util/managed_browser_utils.cc
index bbacae7..5364746 100644
--- a/chrome/browser/enterprise/util/managed_browser_utils.cc
+++ b/chrome/browser/enterprise/util/managed_browser_utils.cc
@@ -137,7 +137,7 @@
   auto* primary_user = user_manager::UserManager::Get()->GetPrimaryUser();
   if (primary_user) {
     auto* primary_profile =
-        chromeos::ProfileHelper::Get()->GetProfileByUser(primary_user);
+        ash::ProfileHelper::Get()->GetProfileByUser(primary_user);
     if (primary_profile) {
       auto* primary_profile_connector =
           primary_profile->GetProfilePolicyConnector();
diff --git a/chrome/browser/extensions/active_tab_unittest.cc b/chrome/browser/extensions/active_tab_unittest.cc
index 0416672..8e6200f 100644
--- a/chrome/browser/extensions/active_tab_unittest.cc
+++ b/chrome/browser/extensions/active_tab_unittest.cc
@@ -554,8 +554,7 @@
     const AccountId account_id =
         AccountId::FromUserEmailGaiaId(user_email, user_id);
     const std::string user_id_hash =
-        chromeos::ProfileHelper::Get()->GetUserIdHashByUserIdForTesting(
-            user_id);
+        ash::ProfileHelper::Get()->GetUserIdHashByUserIdForTesting(user_id);
 
     local_state_ = std::make_unique<ScopedTestingLocalState>(
         TestingBrowserProcess::GetGlobal());
diff --git a/chrome/browser/extensions/api/braille_display_private/braille_display_private_apitest.cc b/chrome/browser/extensions/api/braille_display_private/braille_display_private_apitest.cc
index 6060eed..f4fa3c4 100644
--- a/chrome/browser/extensions/api/braille_display_private/braille_display_private_apitest.cc
+++ b/chrome/browser/extensions/api/braille_display_private/braille_display_private_apitest.cc
@@ -331,7 +331,7 @@
   ash::ScreenLockerTester tester;
 
   // Make sure the signin profile and active profile are different.
-  Profile* signin_profile = chromeos::ProfileHelper::GetSigninProfile();
+  Profile* signin_profile = ash::ProfileHelper::GetSigninProfile();
   Profile* user_profile = ProfileManager::GetActiveUserProfile();
   ASSERT_FALSE(signin_profile->IsSameOrParent(user_profile))
       << signin_profile->GetDebugName() << " vs "
diff --git a/chrome/browser/extensions/api/declarative_content/declarative_content_apitest.cc b/chrome/browser/extensions/api/declarative_content/declarative_content_apitest.cc
index 43a27485..4a8009fc 100644
--- a/chrome/browser/extensions/api/declarative_content/declarative_content_apitest.cc
+++ b/chrome/browser/extensions/api/declarative_content/declarative_content_apitest.cc
@@ -175,7 +175,8 @@
 
   EXPECT_FALSE(incognito_action->GetIsVisible(incognito_tab_id));
 
-  NavigateInRenderer(incognito_tab, GURL("http://test_split/"));
+  // TODO(https://crbug.com/1204390): Understand why these are EXPECT_FALSE.
+  EXPECT_FALSE(NavigateInRenderer(incognito_tab, GURL("http://test_split/")));
   if (mode == SPLIT) {
     EXPECT_EQ(is_enabled_in_incognito,
               incognito_action->GetIsVisible(incognito_tab_id));
@@ -183,7 +184,7 @@
     EXPECT_FALSE(incognito_action->GetIsVisible(incognito_tab_id));
   }
 
-  NavigateInRenderer(incognito_tab, GURL("http://test_normal/"));
+  EXPECT_FALSE(NavigateInRenderer(incognito_tab, GURL("http://test_normal/")));
   if (mode != SPLIT) {
     EXPECT_EQ(is_enabled_in_incognito,
               incognito_action->GetIsVisible(incognito_tab_id));
@@ -201,10 +202,10 @@
 
   EXPECT_FALSE(action->GetIsVisible(tab_id));
 
-  NavigateInRenderer(tab, GURL("http://test_normal/"));
+  EXPECT_FALSE(NavigateInRenderer(tab, GURL("http://test_normal/")));
   EXPECT_TRUE(action->GetIsVisible(tab_id));
 
-  NavigateInRenderer(tab, GURL("http://test_split/"));
+  EXPECT_FALSE(NavigateInRenderer(tab, GURL("http://test_split/")));
   EXPECT_FALSE(action->GetIsVisible(tab_id));
 }
 
@@ -223,7 +224,8 @@
           ->GetExtensionAction(*extension);
   ASSERT_TRUE(action);
 
-  NavigateInRenderer(tab, GURL("http://test1/"));
+  // TODO(https://crbug.com/1204390): Understand why these are EXPECT_FALSE.
+  EXPECT_FALSE(NavigateInRenderer(tab, GURL("http://test1/")));
   EXPECT_FALSE(action->GetIsVisible(tab_id));
 
   static const char kSetIsBookmarkedRule[] =
@@ -252,10 +254,10 @@
   bookmark_model->AddURL(bookmark_model->other_node(), 0, u"title",
                          GURL("http://test2/"));
 
-  NavigateInRenderer(tab, GURL("http://test2/"));
+  EXPECT_FALSE(NavigateInRenderer(tab, GURL("http://test2/")));
   EXPECT_EQ(match_is_bookmarked, action->GetIsVisible(tab_id));
 
-  NavigateInRenderer(tab, GURL("http://test3/"));
+  EXPECT_FALSE(NavigateInRenderer(tab, GURL("http://test3/")));
   EXPECT_EQ(!match_is_bookmarked, action->GetIsVisible(tab_id));
 }
 
@@ -301,14 +303,15 @@
   // actual update to the page action.
   ChromeExtensionTestNotificationObserver test_observer(browser());
 
-  NavigateInRenderer(tab, GURL("http://test1/"));
+  // TODO(https://crbug.com/1204390): Understand why these are EXPECT_FALSE.
+  EXPECT_FALSE(NavigateInRenderer(tab, GURL("http://test1/")));
   // The declarative API should show the page action instantly, rather
   // than waiting for the extension to run.
   test_observer.WaitForPageActionVisibilityChangeTo(1);
   EXPECT_TRUE(action->GetIsVisible(tab_id));
 
   // Make sure leaving a matching page unshows the page action.
-  NavigateInRenderer(tab, GURL("http://not_checked/"));
+  EXPECT_FALSE(NavigateInRenderer(tab, GURL("http://not_checked/")));
   test_observer.WaitForPageActionVisibilityChangeTo(0);
   EXPECT_FALSE(action->GetIsVisible(tab_id));
 
@@ -379,7 +382,8 @@
   const int tab_id = ExtensionTabUtil::GetTabId(tab);
 
   // This navigation matches both rules.
-  NavigateInRenderer(tab, GURL("http://test1/"));
+  // TODO(https://crbug.com/1204390): Understand why this is EXPECT_FALSE.
+  EXPECT_FALSE(NavigateInRenderer(tab, GURL("http://test1/")));
 
   EXPECT_TRUE(action->GetIsVisible(tab_id));
 }
@@ -399,7 +403,8 @@
       browser()->tab_strip_model()->GetWebContentsAt(0);
   const int tab_id = ExtensionTabUtil::GetTabId(tab);
 
-  NavigateInRenderer(tab, GURL("http://test1/"));
+  // TODO(https://crbug.com/1204390): Understand why these are EXPECT_FALSE.
+  EXPECT_FALSE(NavigateInRenderer(tab, GURL("http://test1/")));
 
   const std::string kAddTestRules =
       "addRules([{\n"
@@ -424,7 +429,7 @@
 
   EXPECT_FALSE(action->GetIsVisible(tab_id));
 
-  NavigateInRenderer(tab, GURL("http://test2/"));
+  EXPECT_FALSE(NavigateInRenderer(tab, GURL("http://test2/")));
 
   EXPECT_TRUE(action->GetIsVisible(tab_id));
 
@@ -517,7 +522,8 @@
   // browser actions, both of these should pass.
   EXPECT_THAT(result, testing::HasSubstr(kSuccessStr));
 
-  NavigateInRenderer(tab, GURL("http://test/"));
+  // TODO(https://crbug.com/1204390): Understand why this is EXPECT_FALSE.
+  EXPECT_FALSE(NavigateInRenderer(tab, GURL("http://test/")));
 
   const int tab_id = sessions::SessionTabHelper::IdForTab(tab).id();
   EXPECT_TRUE(action->GetIsVisible(tab_id));
@@ -585,11 +591,12 @@
       browser()->tab_strip_model()->GetWebContentsAt(0);
   const int tab_id = ExtensionTabUtil::GetTabId(tab);
 
-  NavigateInRenderer(tab, GURL("http://blank/"));
+  // TODO(https://crbug.com/1204390): Understand why these are EXPECT_FALSE.
+  EXPECT_FALSE(NavigateInRenderer(tab, GURL("http://blank/")));
   EXPECT_FALSE(action->GetIsVisible(tab_id));
-  NavigateInRenderer(tab, GURL("http://test1/"));
+  EXPECT_FALSE(NavigateInRenderer(tab, GURL("http://test1/")));
   EXPECT_TRUE(action->GetIsVisible(tab_id));
-  NavigateInRenderer(tab, GURL("http://test2/"));
+  EXPECT_FALSE(NavigateInRenderer(tab, GURL("http://test2/")));
   EXPECT_FALSE(action->GetIsVisible(tab_id));
 }
 
@@ -634,7 +641,8 @@
       incognito_browser->tab_strip_model()->GetWebContentsAt(0);
   const int incognito_tab_id = ExtensionTabUtil::GetTabId(incognito_tab);
 
-  NavigateInRenderer(incognito_tab, GURL("http://test_normal/"));
+  // TODO(https://crbug.com/1204390): Understand why this is EXPECT_FALSE.
+  EXPECT_FALSE(NavigateInRenderer(incognito_tab, GURL("http://test_normal/")));
 
   ext_dir_.WriteManifest(kDeclarativeContentManifest);
   ext_dir_.WriteFile(FILE_PATH_LITERAL("background.js"),
@@ -710,11 +718,12 @@
   ASSERT_TRUE(action);
   EXPECT_FALSE(action->GetIsVisible(tab_id));
 
-  NavigateInRenderer(tab, GURL("http://test_normal/"));
+  // TODO(https://crbug.com/1204390): Understand why these are EXPECT_FALSE.
+  EXPECT_FALSE(NavigateInRenderer(tab, GURL("http://test_normal/")));
   test_observer.WaitForPageActionVisibilityChangeTo(1);
   EXPECT_TRUE(action->GetIsVisible(tab_id));
 
-  NavigateInRenderer(tab, GURL("http://test_split/"));
+  EXPECT_FALSE(NavigateInRenderer(tab, GURL("http://test_split/")));
   test_observer.WaitForPageActionVisibilityChangeTo(0);
   EXPECT_FALSE(action->GetIsVisible(tab_id));
 
@@ -735,11 +744,11 @@
           ->GetExtensionAction(*extension);
   ASSERT_TRUE(incognito_action);
 
-  NavigateInRenderer(incognito_tab, GURL("http://test_split/"));
+  EXPECT_FALSE(NavigateInRenderer(incognito_tab, GURL("http://test_split/")));
   incognito_test_observer.WaitForPageActionVisibilityChangeTo(1);
   EXPECT_TRUE(incognito_action->GetIsVisible(incognito_tab_id));
 
-  NavigateInRenderer(incognito_tab, GURL("http://test_normal/"));
+  EXPECT_FALSE(NavigateInRenderer(incognito_tab, GURL("http://test_normal/")));
   incognito_test_observer.WaitForPageActionVisibilityChangeTo(0);
   EXPECT_FALSE(incognito_action->GetIsVisible(incognito_tab_id));
 }
@@ -775,7 +784,8 @@
       browser()->tab_strip_model()->GetWebContentsAt(0);
   const int tab_id = ExtensionTabUtil::GetTabId(tab);
 
-  NavigateInRenderer(tab, GURL("http://test/"));
+  // TODO(https://crbug.com/1204390): Understand why these are EXPECT_FALSE.
+  EXPECT_FALSE(NavigateInRenderer(tab, GURL("http://test/")));
 
   EXPECT_TRUE(action->GetIsVisible(tab_id));
   EXPECT_TRUE(WaitForPageActionVisibilityChangeTo(1));
@@ -790,7 +800,7 @@
             ExecuteScriptInBackgroundPage(extension_id, kTestRule));
   // TODO(jyasskin): Apply new rules to existing tabs, without waiting for a
   // navigation.
-  NavigateInRenderer(tab, GURL("http://test/"));
+  EXPECT_FALSE(NavigateInRenderer(tab, GURL("http://test/")));
   EXPECT_TRUE(WaitForPageActionVisibilityChangeTo(1));
   EXPECT_EQ(1u, extension_action_test_util::GetVisiblePageActionCount(tab));
   EXPECT_EQ(1u, extension_action_test_util::GetTotalPageActionCount(tab));
@@ -798,7 +808,7 @@
   UnloadExtension(extension_id);
   // Wait for declarative rules to be removed.
   profile()->GetDefaultStoragePartition()->FlushNetworkInterfaceForTesting();
-  NavigateInRenderer(tab, GURL("http://test/"));
+  EXPECT_FALSE(NavigateInRenderer(tab, GURL("http://test/")));
   EXPECT_TRUE(WaitForPageActionVisibilityChangeTo(0));
   EXPECT_EQ(0u, extension_action_test_util::GetVisiblePageActionCount(tab));
   EXPECT_EQ(0u, extension_action_test_util::GetTotalPageActionCount(tab));
@@ -990,7 +1000,8 @@
   // tab.
   browser()->tab_strip_model()->DetachAndDeleteWebContentsAt(
       browser()->tab_strip_model()->GetIndexOfWebContents(tab2));
-  NavigateInRenderer(tab1, GURL("http://test1/"));
+  // TODO(https://crbug.com/1204390): Understand why this is EXPECT_FALSE.
+  EXPECT_FALSE(NavigateInRenderer(tab1, GURL("http://test1/")));
   EXPECT_TRUE(action->GetIsVisible(ExtensionTabUtil::GetTabId(tab1)));
 }
 
diff --git a/chrome/browser/extensions/api/declarative_content/set_icon_apitest.cc b/chrome/browser/extensions/api/declarative_content/set_icon_apitest.cc
index b4c72ca..c7c6279 100644
--- a/chrome/browser/extensions/api/declarative_content/set_icon_apitest.cc
+++ b/chrome/browser/extensions/api/declarative_content/set_icon_apitest.cc
@@ -120,11 +120,11 @@
 
   // There should be no declarative icon until we navigate to a matched page.
   EXPECT_TRUE(action->GetDeclarativeIcon(tab_id).IsEmpty());
-  NavigateInRenderer(tab, GURL("http://test1/"));
+  EXPECT_FALSE(NavigateInRenderer(tab, GURL("http://test1/")));
   EXPECT_FALSE(action->GetDeclarativeIcon(tab_id).IsEmpty());
 
   // Navigating to an unmatched page should reset the icon.
-  NavigateInRenderer(tab, GURL("http://test2/"));
+  EXPECT_FALSE(NavigateInRenderer(tab, GURL("http://test2/")));
   EXPECT_TRUE(action->GetDeclarativeIcon(tab_id).IsEmpty());
 }
 }  // namespace
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.cc b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
index f9e3dbb..faa330f 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api.cc
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
@@ -83,6 +83,7 @@
 #include "extensions/browser/management_policy.h"
 #include "extensions/browser/notification_types.h"
 #include "extensions/browser/path_util.h"
+#include "extensions/browser/permissions_manager.h"
 #include "extensions/browser/process_manager_factory.h"
 #include "extensions/browser/ui_util.h"
 #include "extensions/browser/warning_service.h"
@@ -2111,6 +2112,29 @@
   Respond(NoArguments());
 }
 
+DeveloperPrivateGetUserSiteSettingsFunction::
+    DeveloperPrivateGetUserSiteSettingsFunction() = default;
+DeveloperPrivateGetUserSiteSettingsFunction::
+    ~DeveloperPrivateGetUserSiteSettingsFunction() = default;
+
+ExtensionFunction::ResponseAction
+DeveloperPrivateGetUserSiteSettingsFunction::Run() {
+  const PermissionsManager::UserPermissionsSettings& settings =
+      PermissionsManager::Get(browser_context())->GetUserPermissionsSettings();
+
+  developer::UserSiteSettings user_site_settings;
+  user_site_settings.permitted_sites.reserve(settings.permitted_sites.size());
+  for (const auto& origin : settings.permitted_sites)
+    user_site_settings.permitted_sites.push_back(origin.Serialize());
+
+  user_site_settings.restricted_sites.reserve(settings.restricted_sites.size());
+  for (const auto& origin : settings.restricted_sites)
+    user_site_settings.restricted_sites.push_back(origin.Serialize());
+
+  return RespondNow(OneArgument(
+      base::Value::FromUniquePtrValue(user_site_settings.ToValue())));
+}
+
 }  // namespace api
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.h b/chrome/browser/extensions/api/developer_private/developer_private_api.h
index b0bb7298..b0bcc38d 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api.h
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api.h
@@ -864,6 +864,24 @@
   void OnRuntimePermissionsRevoked();
 };
 
+class DeveloperPrivateGetUserSiteSettingsFunction
+    : public DeveloperPrivateAPIFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("developerPrivate.getUserSiteSettings",
+                             DEVELOPERPRIVATE_GETUSERSITESETTINGS)
+  DeveloperPrivateGetUserSiteSettingsFunction();
+
+  DeveloperPrivateGetUserSiteSettingsFunction(
+      const DeveloperPrivateGetUserSiteSettingsFunction&) = delete;
+  DeveloperPrivateGetUserSiteSettingsFunction& operator=(
+      const DeveloperPrivateGetUserSiteSettingsFunction&) = delete;
+
+ private:
+  ~DeveloperPrivateGetUserSiteSettingsFunction() override;
+
+  ResponseAction Run() override;
+};
+
 }  // namespace api
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
index fea8582..c3e7db6f 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
@@ -45,6 +45,7 @@
 #include "extensions/browser/install/extension_install_ui.h"
 #include "extensions/browser/mock_external_provider.h"
 #include "extensions/browser/notification_types.h"
+#include "extensions/browser/permissions_manager.h"
 #include "extensions/browser/test_event_router_observer.h"
 #include "extensions/browser/test_extension_registry_observer.h"
 #include "extensions/common/extension.h"
@@ -1800,6 +1801,35 @@
   EXPECT_EQ("Simple Empty Extension", extension->name());
 }
 
+// Test developerPrivate.getUserSiteSettings.
+TEST_F(DeveloperPrivateApiUnitTest, DeveloperPrivateGetUserSiteSettings) {
+  PermissionsManager* manager = PermissionsManager::Get(browser_context());
+  const url::Origin permitted_url =
+      url::Origin::Create(GURL("http://a.example.com"));
+  const url::Origin restricted_url =
+      url::Origin::Create(GURL("http://b.example.com"));
+
+  manager->AddUserPermittedSite(permitted_url);
+  manager->AddUserRestrictedSite(restricted_url);
+
+  scoped_refptr<ExtensionFunction> function(
+      new api::DeveloperPrivateGetUserSiteSettingsFunction());
+
+  base::ListValue args;
+  EXPECT_TRUE(RunFunction(function, args)) << function->GetError();
+  ASSERT_TRUE(function->GetResultList());
+  ASSERT_EQ(1u, function->GetResultList()->GetList().size());
+  const base::Value& response_value = function->GetResultList()->GetList()[0];
+  std::unique_ptr<api::developer_private::UserSiteSettings> settings =
+      api::developer_private::UserSiteSettings::FromValue(response_value);
+
+  ASSERT_TRUE(settings);
+  EXPECT_THAT(settings->permitted_sites,
+              testing::UnorderedElementsAre("http://a.example.com"));
+  EXPECT_THAT(settings->restricted_sites,
+              testing::UnorderedElementsAre("http://b.example.com"));
+}
+
 class DeveloperPrivateApiAllowlistUnitTest
     : public DeveloperPrivateApiUnitTest {
  public:
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc b/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc
index 5d51224..fb34995 100644
--- a/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc
+++ b/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc
@@ -151,7 +151,7 @@
 
 // Returns the profile into which login-screen extensions are force-installed.
 Profile* GetOriginalSigninProfile() {
-  return chromeos::ProfileHelper::GetSigninProfile()->GetOriginalProfile();
+  return ash::ProfileHelper::GetSigninProfile()->GetOriginalProfile();
 }
 
 void ImportPrivateKeyPKCS8ToSlot(const unsigned char* pkcs8_der,
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc
index 214ccf9..3f5bd3c 100644
--- a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc
+++ b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc
@@ -30,7 +30,7 @@
 bool EPKPChallengeKey::IsExtensionAllowed(
     Profile* profile,
     scoped_refptr<const Extension> extension) {
-  if (!chromeos::ProfileHelper::Get()->GetUserByProfile(profile)) {
+  if (!ash::ProfileHelper::Get()->GetUserByProfile(profile)) {
     // Only allow remote attestation for apps that were force-installed on the
     // login/signin screen.
     // TODO(drcrash): Use a separate device-wide policy for the API.
diff --git a/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc b/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc
index 25dbdba..d3a9068 100644
--- a/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc
+++ b/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc
@@ -153,9 +153,9 @@
   drive::DriveIntegrationService* CreateDriveIntegrationService(
       Profile* profile) {
     // Ignore signin and lock screen apps profile.
-    if (profile->GetPath() == chromeos::ProfileHelper::GetSigninProfileDir() ||
+    if (profile->GetPath() == ash::ProfileHelper::GetSigninProfileDir() ||
         profile->GetPath() ==
-            chromeos::ProfileHelper::GetLockScreenAppProfilePath()) {
+            ash::ProfileHelper::GetLockScreenAppProfilePath()) {
       return nullptr;
     }
 
@@ -304,9 +304,9 @@
   drive::DriveIntegrationService* CreateDriveIntegrationService(
       Profile* profile) {
     // Ignore signin and lock screen apps profile.
-    if (profile->GetPath() == chromeos::ProfileHelper::GetSigninProfileDir() ||
+    if (profile->GetPath() == ash::ProfileHelper::GetSigninProfileDir() ||
         profile->GetPath() ==
-            chromeos::ProfileHelper::GetLockScreenAppProfilePath()) {
+            ash::ProfileHelper::GetLockScreenAppProfilePath()) {
       return nullptr;
     }
 
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
index 87422285..de10972 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
@@ -906,7 +906,7 @@
     is_login = active_state->GetUIStyle() ==
                ash::input_method::InputMethodManager::UIStyle::kLogin;
   } else {
-    is_login = chromeos::ProfileHelper::IsSigninProfile(profile);
+    is_login = ash::ProfileHelper::IsSigninProfile(profile);
   }
 
   if (is_login && profile->HasPrimaryOTRProfile()) {
diff --git a/chrome/browser/extensions/api/passwords_private/passwords_private_utils_chromeos.cc b/chrome/browser/extensions/api/passwords_private/passwords_private_utils_chromeos.cc
index 8b55f70c..fdf23d98 100644
--- a/chrome/browser/extensions/api/passwords_private/passwords_private_utils_chromeos.cc
+++ b/chrome/browser/extensions/api/passwords_private/passwords_private_utils_chromeos.cc
@@ -42,9 +42,7 @@
                           base::TimeDelta auth_token_lifetime) {
   const bool user_cannot_manually_enter_password =
       !ash::password_visibility::AccountHasUserFacingPassword(
-          chromeos::ProfileHelper::Get()
-              ->GetUserByProfile(profile)
-              ->GetAccountId());
+          ash::ProfileHelper::Get()->GetUserByProfile(profile)->GetAccountId());
   if (user_cannot_manually_enter_password)
     return true;
 
diff --git a/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_api.cc b/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_api.cc
index 3956dfc..7d60eb6 100644
--- a/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_api.cc
+++ b/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_api.cc
@@ -78,7 +78,7 @@
 // Returns the active set of quick unlock modes.
 void ComputeActiveModes(Profile* profile, ActiveModeCallback result) {
   user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   ash::quick_unlock::PinBackend::GetInstance()->IsSet(
       user->GetAccountId(),
       base::BindOnce(
@@ -192,7 +192,7 @@
   Profile* profile = Profile::FromBrowserContext(browser_context);
   // When OOBE continues in-session as Furst Run UI, it is still executed
   // under Sign-In profile.
-  if (chromeos::ProfileHelper::IsSigninProfile(profile))
+  if (ash::ProfileHelper::IsSigninProfile(profile))
     return ProfileManager::GetPrimaryUserProfile();
 
   return profile;
@@ -320,7 +320,7 @@
 
   Profile* profile = GetActiveProfile(browser_context());
   user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
 
   ash::quick_unlock::PinBackend::GetInstance()->SetPinAutoSubmitEnabled(
       user->GetAccountId(), params->pin, params->enabled,
@@ -354,7 +354,7 @@
 
   Profile* profile = GetActiveProfile(browser_context());
   user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
 
   ash::quick_unlock::PinBackend::GetInstance()->CanAuthenticate(
       user->GetAccountId(),
@@ -584,7 +584,7 @@
   if (update_pin) {
     Profile* profile = GetActiveProfile(browser_context());
     user_manager::User* user =
-        chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+        ash::ProfileHelper::Get()->GetUserByProfile(profile);
     if (pin_credential.empty()) {
       ash::quick_unlock::PinBackend::GetInstance()->Remove(
           user->GetAccountId(), params_->token,
@@ -627,7 +627,7 @@
     FireEvent(updated_modes);
 
   const user_manager::User* const user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(
+      ash::ProfileHelper::Get()->GetUserByProfile(
           GetActiveProfile(browser_context()));
   const ash::UserContext user_context(*user);
 
diff --git a/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_ash_utils.cc b/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_ash_utils.cc
index 15dde6b6..23cbbdd7 100644
--- a/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_ash_utils.cc
+++ b/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_ash_utils.cc
@@ -48,7 +48,7 @@
   callback_ = std::move(callback);
 
   const user_manager::User* const user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile_);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile_);
   ash::UserContext user_context(*user);
   user_context.SetKey(ash::Key(password));
 
diff --git a/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc b/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc
index bba5a80..d427c2984 100644
--- a/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc
+++ b/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc
@@ -938,7 +938,7 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   const user_manager::User* user = GetChromeOSUser();
   if (user) {
-    Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+    Profile* profile = ash::ProfileHelper::Get()->GetProfileByUser(user);
     // If primary user profile is not finalized, use the current profile.
     if (!profile)
       profile = Profile::FromBrowserContext(context_);
diff --git a/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_unittest.cc b/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_unittest.cc
index be77a86..5f000827 100644
--- a/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_unittest.cc
+++ b/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_unittest.cc
@@ -1242,8 +1242,8 @@
         AccountId::FromUserEmail(profile_->GetProfileUserName()));
     const user_manager::User* user = user_manager->AddUserWithAffiliation(
         account_id, /*is_affiliated=*/is_manageable_);
-    chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(user,
-                                                                      profile_);
+    ash::ProfileHelper::Get()->SetUserToProfileMappingForTesting(user,
+                                                                 profile_);
     user_manager->UserLoggedIn(account_id, user->username_hash(),
                                /*browser_restart=*/false,
                                /*is_child=*/false);
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc
index 35597bbd..0f18983 100644
--- a/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -1126,7 +1126,7 @@
     if (!string_value)
       return settings_private::SetPrefResult::PREF_TYPE_MISMATCH;
     const user_manager::User* user =
-        chromeos::ProfileHelper::Get()->GetUserByProfile(profile_);
+        ash::ProfileHelper::Get()->GetUserByProfile(profile_);
     if (user && ash::system::SetSystemTimezone(user, *string_value))
       return settings_private::SetPrefResult::SUCCESS;
     return settings_private::SetPrefResult::PREF_NOT_MODIFIABLE;
@@ -1200,7 +1200,7 @@
     return false;
 
   if (IsPrivilegedCrosSetting(pref_name)) {
-    if (!chromeos::ProfileHelper::IsOwnerProfile(profile_))
+    if (!ash::ProfileHelper::IsOwnerProfile(profile_))
       return true;
   }
   return false;
@@ -1212,7 +1212,7 @@
   if (pref_name == prefs::kUserTimezone || pref_name == ash::kSystemTimezone) {
     user_manager::UserManager* user_manager = user_manager::UserManager::Get();
     const user_manager::User* user =
-        chromeos::ProfileHelper::Get()->GetUserByProfile(profile_);
+        ash::ProfileHelper::Get()->GetUserByProfile(profile_);
     if (user && user->GetAccountId() !=
                     user_manager->GetPrimaryUser()->GetAccountId()) {
       return true;
diff --git a/chrome/browser/extensions/api/storage/managed_value_store_cache.cc b/chrome/browser/extensions/api/storage/managed_value_store_cache.cc
index 7971c45..26cb2da8 100644
--- a/chrome/browser/extensions/api/storage/managed_value_store_cache.cc
+++ b/chrome/browser/extensions/api/storage/managed_value_store_cache.cc
@@ -326,7 +326,7 @@
 // static
 policy::PolicyDomain ManagedValueStoreCache::GetPolicyDomain(Profile* profile) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  return chromeos::ProfileHelper::IsSigninProfile(profile)
+  return ash::ProfileHelper::IsSigninProfile(profile)
              ? policy::POLICY_DOMAIN_SIGNIN_EXTENSIONS
              : policy::POLICY_DOMAIN_EXTENSIONS;
 #else
diff --git a/chrome/browser/extensions/api/vpn_provider/vpn_provider_apitest.cc b/chrome/browser/extensions/api/vpn_provider/vpn_provider_apitest.cc
index 6e75bbd..22b875b 100644
--- a/chrome/browser/extensions/api/vpn_provider/vpn_provider_apitest.cc
+++ b/chrome/browser/extensions/api/vpn_provider/vpn_provider_apitest.cc
@@ -132,7 +132,7 @@
   void AddNetworkProfileForUser() {
     ShillProfileClient::Get()->GetTestInterface()->AddProfile(
         kNetworkProfilePath,
-        chromeos::ProfileHelper::GetUserIdHashFromProfile(profile()));
+        ash::ProfileHelper::GetUserIdHashFromProfile(profile()));
     content::RunAllPendingInMessageLoop();
   }
 
diff --git a/chrome/browser/extensions/api/web_request/web_request_apitest.cc b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
index 03cb2ea..3e88775 100644
--- a/chrome/browser/extensions/api/web_request/web_request_apitest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
@@ -1877,7 +1877,7 @@
   // Create a profile that will be destroyed later.
   base::ScopedAllowBlockingForTesting allow_blocking;
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  chromeos::ProfileHelper::SetAlwaysReturnPrimaryUserForTesting(true);
+  ash::ProfileHelper::SetAlwaysReturnPrimaryUserForTesting(true);
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   ProfileManager* profile_manager = g_browser_process->profile_manager();
   Profile* temp_profile =
diff --git a/chrome/browser/extensions/app_process_apitest.cc b/chrome/browser/extensions/app_process_apitest.cc
index 5dbd57f..f2089ac 100644
--- a/chrome/browser/extensions/app_process_apitest.cc
+++ b/chrome/browser/extensions/app_process_apitest.cc
@@ -236,10 +236,10 @@
   // extent. They should switch processes.
   const GURL& app_url(base_url.Resolve("path1/empty.html"));
   const GURL& non_app_url(base_url.Resolve("path3/empty.html"));
-  NavigateInRenderer(browser()->tab_strip_model()->GetWebContentsAt(2),
-                     non_app_url);
-  NavigateInRenderer(browser()->tab_strip_model()->GetWebContentsAt(3),
-                     app_url);
+  EXPECT_TRUE(NavigateInRenderer(
+      browser()->tab_strip_model()->GetWebContentsAt(2), non_app_url));
+  EXPECT_TRUE(NavigateInRenderer(
+      browser()->tab_strip_model()->GetWebContentsAt(3), app_url));
   EXPECT_NE(tab->GetMainFrame()->GetProcess(), browser()
                                                    ->tab_strip_model()
                                                    ->GetWebContentsAt(2)
@@ -253,8 +253,8 @@
 
   // If one of the popup tabs navigates back to the app, window.opener should
   // be valid.
-  NavigateInRenderer(browser()->tab_strip_model()->GetWebContentsAt(6),
-                     app_url);
+  EXPECT_TRUE(NavigateInRenderer(
+      browser()->tab_strip_model()->GetWebContentsAt(6), app_url));
   EXPECT_EQ(tab->GetMainFrame()->GetProcess(), browser()
                                                    ->tab_strip_model()
                                                    ->GetWebContentsAt(6)
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.cc b/chrome/browser/extensions/chrome_extensions_browser_client.cc
index 37b944f..1a1e230 100644
--- a/chrome/browser/extensions/chrome_extensions_browser_client.cc
+++ b/chrome/browser/extensions/chrome_extensions_browser_client.cc
@@ -179,7 +179,7 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 std::string ChromeExtensionsBrowserClient::GetUserIdHashFromContext(
     content::BrowserContext* context) {
-  return chromeos::ProfileHelper::GetUserIdHashFromProfile(
+  return ash::ProfileHelper::GetUserIdHashFromProfile(
       static_cast<Profile*>(context));
 }
 #endif
@@ -515,7 +515,7 @@
 bool ChromeExtensionsBrowserClient::IsLockScreenContext(
     content::BrowserContext* context) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  return chromeos::ProfileHelper::IsLockScreenAppProfile(
+  return ash::ProfileHelper::IsLockScreenAppProfile(
       Profile::FromBrowserContext(context));
 #else
   return false;
diff --git a/chrome/browser/extensions/chrome_process_manager_delegate.cc b/chrome/browser/extensions/chrome_process_manager_delegate.cc
index 3a7fda7..a4b33da2 100644
--- a/chrome/browser/extensions/chrome_process_manager_delegate.cc
+++ b/chrome/browser/extensions/chrome_process_manager_delegate.cc
@@ -74,9 +74,8 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   Profile* profile = Profile::FromBrowserContext(context);
 
-  const bool is_signin_profile =
-      chromeos::ProfileHelper::IsSigninProfile(profile) &&
-      !profile->IsOffTheRecord();
+  const bool is_signin_profile = ash::ProfileHelper::IsSigninProfile(profile) &&
+                                 !profile->IsOffTheRecord();
 
   if (is_signin_profile) {
     // Check for flag.
@@ -96,7 +95,7 @@
            IsComponentExtensionAllowlistedForSignInProfile(extension.id());
   }
 
-  if (chromeos::ProfileHelper::IsLockScreenAppProfile(profile) &&
+  if (ash::ProfileHelper::IsLockScreenAppProfile(profile) &&
       !profile->IsOffTheRecord()) {
     return extension.permissions_data()->HasAPIPermission(
         mojom::APIPermissionID::kLockScreen);
diff --git a/chrome/browser/extensions/extension_assets_manager_chromeos.cc b/chrome/browser/extensions/extension_assets_manager_chromeos.cc
index 48df683..c6a26bea 100644
--- a/chrome/browser/extensions/extension_assets_manager_chromeos.cc
+++ b/chrome/browser/extensions/extension_assets_manager_chromeos.cc
@@ -538,7 +538,7 @@
         // For logged in user also check that this path is actually used as
         // installed extension or as delayed install.
         Profile* profile =
-            chromeos::ProfileHelper::Get()->GetProfileByUserUnsafe(user);
+            ash::ProfileHelper::Get()->GetProfileByUserUnsafe(user);
         ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(profile);
         if (!extension_prefs || extension_prefs->pref_service()->ReadOnly())
           return false;
diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc
index de93b31..f0352ad 100644
--- a/chrome/browser/extensions/extension_browsertest.cc
+++ b/chrome/browser/extensions/extension_browsertest.cc
@@ -798,14 +798,15 @@
     *newtab_result = newtab;
 }
 
-void ExtensionBrowserTest::NavigateInRenderer(content::WebContents* contents,
+bool ExtensionBrowserTest::NavigateInRenderer(content::WebContents* contents,
                                               const GURL& url) {
   // Note: We use ExecuteScript instead of ExecJS here, because ExecuteScript
   // works on pages with a Content Security Policy.
   EXPECT_TRUE(content::ExecuteScript(
       contents, "window.location = '" + url.spec() + "';"));
-  content::WaitForLoadStop(contents);
+  bool result = content::WaitForLoadStop(contents);
   EXPECT_EQ(url, contents->GetController().GetLastCommittedEntry()->GetURL());
+  return result;
 }
 
 ExtensionHost* ExtensionBrowserTest::FindHostWithPath(ProcessManager* manager,
diff --git a/chrome/browser/extensions/extension_browsertest.h b/chrome/browser/extensions/extension_browsertest.h
index faa7f23..c93829e 100644
--- a/chrome/browser/extensions/extension_browsertest.h
+++ b/chrome/browser/extensions/extension_browsertest.h
@@ -315,8 +315,9 @@
                   content::WebContents** newtab_result);
 
   // Simulates a page navigating itself to an URL and waits for the
-  // navigation.
-  void NavigateInRenderer(content::WebContents* contents, const GURL& url);
+  // navigation. Returns true if the navigation succeeds.
+  WARN_UNUSED_RESULT bool NavigateInRenderer(content::WebContents* contents,
+                                             const GURL& url);
 
   // Looks for an ExtensionHost whose URL has the given path component
   // (including leading slash).  Also verifies that the expected number of hosts
diff --git a/chrome/browser/extensions/extension_garbage_collector_chromeos.cc b/chrome/browser/extensions/extension_garbage_collector_chromeos.cc
index 40b8a88..bf5299d 100644
--- a/chrome/browser/extensions/extension_garbage_collector_chromeos.cc
+++ b/chrome/browser/extensions/extension_garbage_collector_chromeos.cc
@@ -65,7 +65,7 @@
     if (!active_users[i]->is_profile_created())
       return false;
     Profile* profile =
-        chromeos::ProfileHelper::Get()->GetProfileByUserUnsafe(active_users[i]);
+        ash::ProfileHelper::Get()->GetProfileByUserUnsafe(active_users[i]);
     ExtensionGarbageCollectorChromeOS* gc =
         ExtensionGarbageCollectorChromeOS::Get(profile);
     if (gc && gc->crx_installs_in_progress_ > 0)
diff --git a/chrome/browser/extensions/extension_garbage_collector_chromeos_unittest.cc b/chrome/browser/extensions/extension_garbage_collector_chromeos_unittest.cc
index 4e89aaa..2f3375f 100644
--- a/chrome/browser/extensions/extension_garbage_collector_chromeos_unittest.cc
+++ b/chrome/browser/extensions/extension_garbage_collector_chromeos_unittest.cc
@@ -67,7 +67,7 @@
 
     GetFakeUserManager()->AddUser(user_manager::StubAccountId());
     GetFakeUserManager()->LoginUser(user_manager::StubAccountId());
-    chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
+    ash::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
         GetFakeUserManager()->GetActiveUser(), profile_.get());
   }
 
diff --git a/chrome/browser/extensions/extension_loading_browsertest.cc b/chrome/browser/extensions/extension_loading_browsertest.cc
index 6d23ab53..7ead0f6 100644
--- a/chrome/browser/extensions/extension_loading_browsertest.cc
+++ b/chrome/browser/extensions/extension_loading_browsertest.cc
@@ -85,8 +85,9 @@
       embedded_test_server()->GetURL("/README.chromium");
   EXPECT_THAT(test_link_from_NTP.spec(), testing::EndsWith("/README.chromium"))
       << "Check that the test server started.";
-  NavigateInRenderer(browser()->tab_strip_model()->GetActiveWebContents(),
-                     test_link_from_NTP);
+  EXPECT_TRUE(
+      NavigateInRenderer(browser()->tab_strip_model()->GetActiveWebContents(),
+                         test_link_from_NTP));
 
   // Increase the extension's version.
   extension_dir.WriteManifest(base::StringPrintf(kManifestTemplate, 2));
@@ -140,8 +141,9 @@
       embedded_test_server()->GetURL("/README.chromium");
   EXPECT_THAT(test_link_from_ntp.spec(), testing::EndsWith("/README.chromium"))
       << "Check that the test server started.";
-  NavigateInRenderer(browser()->tab_strip_model()->GetActiveWebContents(),
-                     test_link_from_ntp);
+  EXPECT_TRUE(
+      NavigateInRenderer(browser()->tab_strip_model()->GetActiveWebContents(),
+                         test_link_from_ntp));
 
   // Increase the extension's version and add the NTP url override which will
   // add the kNewTabPageOverride permission.
diff --git a/chrome/browser/extensions/extension_management.cc b/chrome/browser/extensions/extension_management.cc
index 82c2d7c..cab63771 100644
--- a/chrome/browser/extensions/extension_management.cc
+++ b/chrome/browser/extensions/extension_management.cc
@@ -63,7 +63,7 @@
   TRACE_EVENT0("browser,startup",
                "ExtensionManagement::ExtensionManagement::ctor");
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  is_signin_profile_ = chromeos::ProfileHelper::IsSigninProfile(profile);
+  is_signin_profile_ = ash::ProfileHelper::IsSigninProfile(profile);
 #endif
   pref_change_registrar_.Init(pref_service_);
   base::RepeatingClosure pref_change_callback = base::BindRepeating(
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index c104747e..424dbc8 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -473,15 +473,14 @@
   bool load_saved_extensions = true;
   bool load_command_line_extensions = extensions_enabled_;
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  if (!chromeos::ProfileHelper::IsRegularProfile(profile_)) {
+  if (!ash::ProfileHelper::IsRegularProfile(profile_)) {
     load_saved_extensions = false;
     load_command_line_extensions = false;
   }
 
   const bool load_autotest_ext =
       command_line_->HasSwitch(switches::kLoadSigninProfileTestExtension);
-  const bool is_signin_profile =
-      chromeos::ProfileHelper::IsSigninProfile(profile_);
+  const bool is_signin_profile = ash::ProfileHelper::IsSigninProfile(profile_);
   if (load_autotest_ext && is_signin_profile) {
     LoadSigninProfileTestExtension(command_line_->GetSwitchValueASCII(
         switches::kLoadSigninProfileTestExtension));
diff --git a/chrome/browser/extensions/extension_startup_browsertest.cc b/chrome/browser/extensions/extension_startup_browsertest.cc
index a27d7e0..b2dd3826 100644
--- a/chrome/browser/extensions/extension_startup_browsertest.cc
+++ b/chrome/browser/extensions/extension_startup_browsertest.cc
@@ -358,7 +358,7 @@
   // The --load-extension command line flag should not be applied to the sign-in
   // profile.
   EXPECT_EQ(0, GetNonComponentEnabledExtensionCount(
-                   chromeos::ProfileHelper::GetSigninProfile()));
+                   ash::ProfileHelper::GetSigninProfile()));
 }
 
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/extensions/extension_system_impl.cc b/chrome/browser/extensions/extension_system_impl.cc
index 6509fb4..2280a75 100644
--- a/chrome/browser/extensions/extension_system_impl.cc
+++ b/chrome/browser/extensions/extension_system_impl.cc
@@ -146,7 +146,7 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   // Lazy creation of SigninScreenPolicyProvider.
   if (!signin_screen_policy_provider_) {
-    if (chromeos::ProfileHelper::IsSigninProfile(profile_)) {
+    if (ash::ProfileHelper::IsSigninProfile(profile_)) {
       signin_screen_policy_provider_ =
           std::make_unique<chromeos::SigninScreenPolicyProvider>();
     }
@@ -206,7 +206,7 @@
                             !profile_->IsSystemProfile();
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   if (!extensions_enabled ||
-      chromeos::ProfileHelper::IsLockScreenAppProfile(profile_)) {
+      ash::ProfileHelper::IsLockScreenAppProfile(profile_)) {
     autoupdate_enabled = false;
   }
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
@@ -261,9 +261,8 @@
   // Skip loading session extensions if we are not in a user session or if the
   // profile is the sign-in or lock screen app profile, which don't correspond
   // to a user session.
-  skip_session_extensions =
-      !chromeos::LoginState::Get()->IsUserLoggedIn() ||
-      !chromeos::ProfileHelper::IsRegularProfile(profile_);
+  skip_session_extensions = !chromeos::LoginState::Get()->IsUserLoggedIn() ||
+                            !ash::ProfileHelper::IsRegularProfile(profile_);
   if (chrome::IsRunningInForcedAppMode()) {
     extension_service_->component_loader()->
         AddDefaultComponentExtensionsForKioskMode(skip_session_extensions);
diff --git a/chrome/browser/extensions/extension_util.cc b/chrome/browser/extensions/extension_util.cc
index 1dbb665..204c350 100644
--- a/chrome/browser/extensions/extension_util.cc
+++ b/chrome/browser/extensions/extension_util.cc
@@ -87,7 +87,7 @@
   const bool is_policy_extension =
       extension && Manifest::IsPolicyLocation(extension->location());
   Profile* profile = Profile::FromBrowserContext(context);
-  if (profile && chromeos::ProfileHelper::IsSigninProfile(profile) &&
+  if (profile && ash::ProfileHelper::IsSigninProfile(profile) &&
       is_policy_extension) {
     return true;
   }
diff --git a/chrome/browser/extensions/external_provider_impl.cc b/chrome/browser/extensions/external_provider_impl.cc
index 23e3198..b6ab515 100644
--- a/chrome/browser/extensions/external_provider_impl.cc
+++ b/chrome/browser/extensions/external_provider_impl.cc
@@ -633,7 +633,7 @@
   ManifestLocation crx_location = ManifestLocation::kInvalidLocation;
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  if (chromeos::ProfileHelper::IsSigninProfile(profile)) {
+  if (ash::ProfileHelper::IsSigninProfile(profile)) {
     // Download extensions/apps installed by policy in the login profile.
     // Extensions (not apps) installed through this path will have type
     // |TYPE_LOGIN_SCREEN_EXTENSION| with limited API capabilities.
@@ -654,7 +654,7 @@
       g_browser_process->platform_part()->browser_policy_connector_ash();
   bool is_chrome_os_public_session = false;
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   policy::DeviceLocalAccount::Type account_type;
   if (user && connector->IsDeviceEnterpriseManaged() &&
       policy::IsDeviceLocalAccountUser(user->GetAccountId().GetUserEmail(),
diff --git a/chrome/browser/extensions/forced_extensions/force_installed_metrics_unittest.cc b/chrome/browser/extensions/forced_extensions/force_installed_metrics_unittest.cc
index 8f30629..cc1fb2af 100644
--- a/chrome/browser/extensions/forced_extensions/force_installed_metrics_unittest.cc
+++ b/chrome/browser/extensions/forced_extensions/force_installed_metrics_unittest.cc
@@ -903,7 +903,7 @@
   fake_user_manager->UserLoggedIn(account_id, user->username_hash(),
                                   false /* browser_restart */,
                                   false /* is_child */);
-  chromeos::ProfileHelper::Get()->SetProfileToUserMappingForTesting(user);
+  ash::ProfileHelper::Get()->SetProfileToUserMappingForTesting(user);
   SetupForceList(ExtensionOrigin::kWebStore);
   install_stage_tracker()->ReportFailure(
       kExtensionId1, InstallStageTracker::FailureReason::INVALID_ID);
@@ -929,7 +929,7 @@
   fake_user_manager->UserLoggedIn(account_id, user->username_hash(),
                                   false /* browser_restart */,
                                   false /* is_child */);
-  chromeos::ProfileHelper::Get()->SetProfileToUserMappingForTesting(user);
+  ash::ProfileHelper::Get()->SetProfileToUserMappingForTesting(user);
   SetupForceList(ExtensionOrigin::kWebStore);
   install_stage_tracker()->ReportFailure(
       kExtensionId1, InstallStageTracker::FailureReason::INVALID_ID);
@@ -958,7 +958,7 @@
   fake_user_manager->UserLoggedIn(account_id, user->username_hash(),
                                   false /* browser_restart */,
                                   false /* is_child */);
-  chromeos::ProfileHelper::Get()->SetProfileToUserMappingForTesting(user);
+  ash::ProfileHelper::Get()->SetProfileToUserMappingForTesting(user);
 
   SetupForceList(ExtensionOrigin::kWebStore);
   CreateExtensionService(/*extensions_enabled=*/true);
diff --git a/chrome/browser/extensions/forced_extensions/install_stage_tracker.cc b/chrome/browser/extensions/forced_extensions/install_stage_tracker.cc
index 99e7307..5a7857a 100644
--- a/chrome/browser/extensions/forced_extensions/install_stage_tracker.cc
+++ b/chrome/browser/extensions/forced_extensions/install_stage_tracker.cc
@@ -134,7 +134,7 @@
 InstallStageTracker::UserInfo InstallStageTracker::GetUserInfo(
     Profile* profile) {
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   if (!user)
     return UserInfo();
 
diff --git a/chrome/browser/extensions/isolated_app_browsertest.cc b/chrome/browser/extensions/isolated_app_browsertest.cc
index b28277b..2718b17 100644
--- a/chrome/browser/extensions/isolated_app_browsertest.cc
+++ b/chrome/browser/extensions/isolated_app_browsertest.cc
@@ -508,8 +508,8 @@
 
   // Navigating the second tab out of the app should cause a process swap.
   const GURL& non_app_url(base_url.Resolve("non_app/main.html"));
-  NavigateInRenderer(browser()->tab_strip_model()->GetWebContentsAt(1),
-                     non_app_url);
+  EXPECT_TRUE(NavigateInRenderer(
+      browser()->tab_strip_model()->GetWebContentsAt(1), non_app_url));
   EXPECT_NE(process_id_1, browser()
                               ->tab_strip_model()
                               ->GetWebContentsAt(1)
diff --git a/chrome/browser/extensions/process_manager_browsertest.cc b/chrome/browser/extensions/process_manager_browsertest.cc
index ab5d607..8d8af17 100644
--- a/chrome/browser/extensions/process_manager_browsertest.cc
+++ b/chrome/browser/extensions/process_manager_browsertest.cc
@@ -338,7 +338,7 @@
   Profile* otr = original->GetPrimaryOTRProfile(/*create_if_needed=*/true);
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   EXPECT_EQ(profile(), otr);
-  EXPECT_TRUE(chromeos::ProfileHelper::IsSigninProfile(original));
+  EXPECT_TRUE(ash::ProfileHelper::IsSigninProfile(original));
 #endif
 
   ProcessManager* pm = ProcessManager::Get(original);
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedProcessScopeDependencyProvider.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedProcessScopeDependencyProvider.java
index 7d986b05..247345a 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedProcessScopeDependencyProvider.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedProcessScopeDependencyProvider.java
@@ -17,7 +17,6 @@
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.task.PostTask;
 import org.chromium.base.task.TaskTraits;
-import org.chromium.chrome.browser.base.SplitCompatUtils;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.privacy.settings.PrivacyPreferencesManager;
 import org.chromium.chrome.browser.xsurface.ImageFetchClient;
@@ -110,7 +109,7 @@
     }
 
     public static Context createFeedContext(Context context) {
-        return SplitCompatUtils.createContextForInflation(context, FEED_SPLIT_NAME);
+        return BundleUtils.createContextForInflation(context, FEED_SPLIT_NAME);
     }
 
     @Override
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 19b1339..3766d4c 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -265,11 +265,6 @@
     "expiry_milestone": 110
   },
   {
-    "name": "ash-advanced-screen-capture-settings",
-    "owners": [ "afakhry", "gzadina", "fanafan" ],
-    "expiry_milestone": 100
-  },
-  {
     "name": "ash-bento-bar",
     "owners": [ "minch", "janetmac" ],
     "expiry_milestone": 100
@@ -510,12 +505,12 @@
   {
     "name": "autofill-use-improved-label-disambiguation",
     "owners": [ "autofill-squad-muc@google.com" ],
-    "expiry_milestone": 98
+    "expiry_milestone": 102
   },
   {
     "name": "autofill-use-mobile-label-disambiguation",
     "owners": [ "autofill-squad-muc@google.com" ],
-    "expiry_milestone": 98
+    "expiry_milestone": 102
   },
   {
     "name": "autofill-use-renderer-ids",
@@ -2133,6 +2128,11 @@
     "expiry_milestone": 90
   },
   {
+    "name": "enable-holding-space-in-progress-animation-v2",
+    "owners": [ "//ash/public/cpp/holding_space/OWNERS" ],
+    "expiry_milestone": 101
+  },
+  {
     "name": "enable-holding-space-in-progress-downloads-integration",
     "owners": [ "//ash/public/cpp/holding_space/OWNERS" ],
     "expiry_milestone": 99
@@ -2679,7 +2679,7 @@
   {
     "name": "enable-suggestions-with-substring-match",
     "owners": [ "autofill-squad-muc@google.com" ],
-    "expiry_milestone": 98
+    "expiry_milestone": 102
   },
   {
     "name": "enable-surface-control",
@@ -5098,8 +5098,8 @@
   },
   {
     "name": "shimless-rma-flow",
-    "owners": [ "zentaro", "cros-peripherals@google.com" ],
-    "expiry_milestone": 98
+    "owners": [ "zentaro", "gavinwill", "cros-peripherals@google.com" ],
+    "expiry_milestone": 103
   },
   {
     "name": "shopping-list",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index e38fc2a9..4bc6000 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -4724,6 +4724,11 @@
     "Enables the integration between the help app and the local search"
     " service. Includes using the search service for in app search.";
 
+const char kHoldingSpaceInProgressAnimationV2Name[] =
+    "Enable showing v2 in-progress animations in Tote.";
+const char kHoldingSpaceInProgressAnimationV2Description[] =
+    "Show v2 in-progress animations in Tote.";
+
 const char kHoldingSpaceInProgressDownloadsIntegrationName[] =
     "Enable showing in-progress downloads in Tote.";
 const char kHoldingSpaceInProgressDownloadsIntegrationDescription[] =
@@ -4852,11 +4857,6 @@
     "Limits items on the shelf to the ones associated with windows on the "
     "active desk";
 
-const char kImprovedScreenCaptureSettingsName[] =
-    "Advanced screen capture settings";
-const char kImprovedScreenCaptureSettingsDescription[] =
-    "Enable the advanced settings view for screen capture mode";
-
 const char kListAllDisplayModesName[] = "List all display modes";
 const char kListAllDisplayModesDescription[] =
     "Enables listing all external displays' modes in the display settings.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index da655f0..3d15338a 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -2710,6 +2710,9 @@
 extern const char kHelpAppSearchServiceIntegrationName[];
 extern const char kHelpAppSearchServiceIntegrationDescription[];
 
+extern const char kHoldingSpaceInProgressAnimationV2Name[];
+extern const char kHoldingSpaceInProgressAnimationV2Description[];
+
 extern const char kHoldingSpaceInProgressDownloadsIntegrationName[];
 extern const char kHoldingSpaceInProgressDownloadsIntegrationDescription[];
 
@@ -2781,9 +2784,6 @@
 extern const char kLimitShelfItemsToActiveDeskName[];
 extern const char kLimitShelfItemsToActiveDeskDescription[];
 
-extern const char kImprovedScreenCaptureSettingsName[];
-extern const char kImprovedScreenCaptureSettingsDescription[];
-
 extern const char kListAllDisplayModesName[];
 extern const char kListAllDisplayModesDescription[];
 
diff --git a/chrome/browser/invalidation/profile_invalidation_provider_factory.cc b/chrome/browser/invalidation/profile_invalidation_provider_factory.cc
index 50f862b..ae85571 100644
--- a/chrome/browser/invalidation/profile_invalidation_provider_factory.cc
+++ b/chrome/browser/invalidation/profile_invalidation_provider_factory.cc
@@ -77,7 +77,7 @@
   // when this method is called during the creation of the sign-in profile
   // itself. Using ProfileHelper::GetSigninProfileDir() is safe because it does
   // not try to access the sign-in profile.
-  if (profile->GetPath() == chromeos::ProfileHelper::GetSigninProfileDir() ||
+  if (profile->GetPath() == ash::ProfileHelper::GetSigninProfileDir() ||
       (user_manager::UserManager::IsInitialized() &&
        user_manager::UserManager::Get()->IsLoggedInAsGuest())) {
     // The Chrome OS login and Chrome OS guest profiles do not have GAIA
diff --git a/chrome/browser/invalidation/profile_invalidation_provider_factory_browsertest.cc b/chrome/browser/invalidation/profile_invalidation_provider_factory_browsertest.cc
index 6857328..396f4d1 100644
--- a/chrome/browser/invalidation/profile_invalidation_provider_factory_browsertest.cc
+++ b/chrome/browser/invalidation/profile_invalidation_provider_factory_browsertest.cc
@@ -78,7 +78,7 @@
 IN_PROC_BROWSER_TEST_F(ProfileInvalidationProviderFactoryLoginScreenBrowserTest,
                        NoInvalidationService) {
   Profile* login_profile =
-      chromeos::ProfileHelper::GetSigninProfile()->GetOriginalProfile();
+      ash::ProfileHelper::GetSigninProfile()->GetOriginalProfile();
   EXPECT_FALSE(CanConstructProfileInvalidationProvider(login_profile));
 }
 
@@ -120,11 +120,11 @@
   user_manager::UserManager* user_manager = user_manager::UserManager::Get();
   EXPECT_TRUE(user_manager->IsLoggedInAsGuest());
   Profile* guest_profile =
-      chromeos::ProfileHelper::Get()
+      ash::ProfileHelper::Get()
           ->GetProfileByUserUnsafe(user_manager->GetActiveUser())
           ->GetOriginalProfile();
   Profile* login_profile =
-      chromeos::ProfileHelper::GetSigninProfile()->GetOriginalProfile();
+      ash::ProfileHelper::GetSigninProfile()->GetOriginalProfile();
   EXPECT_FALSE(CanConstructProfileInvalidationProvider(guest_profile));
   EXPECT_FALSE(CanConstructProfileInvalidationProvider(login_profile));
 }
diff --git a/chrome/browser/media/media_engagement_contents_observer.cc b/chrome/browser/media/media_engagement_contents_observer.cc
index a6d629c..bbceee5 100644
--- a/chrome/browser/media/media_engagement_contents_observer.cc
+++ b/chrome/browser/media/media_engagement_contents_observer.cc
@@ -169,8 +169,7 @@
   RegisterAudiblePlayersWithSession();
   ClearPlayerStates();
 
-  url::Origin new_origin = url::Origin::Create(navigation_handle->GetURL());
-  if (session_ && session_->IsSameOriginWith(new_origin))
+  if (session_ && session_->IsSameOriginWith(navigation_handle->GetURL()))
     return;
 
   // Only get the opener if the navigation originated from a link.
@@ -653,7 +652,8 @@
       service_->GetContentsObserverFor(opener);
 
   if (opener_observer && opener_observer->session_ &&
-      opener_observer->session_->IsSameOriginWith(origin)) {
+      opener_observer->session_->IsSameOriginWith(
+          navigation_handle->GetURL())) {
     return opener_observer->session_;
   }
 
diff --git a/chrome/browser/media/media_engagement_session.cc b/chrome/browser/media/media_engagement_session.cc
index 32fa377..35a655b6 100644
--- a/chrome/browser/media/media_engagement_session.cc
+++ b/chrome/browser/media/media_engagement_session.cc
@@ -23,8 +23,8 @@
     pending_data_to_commit_.visit = false;
 }
 
-bool MediaEngagementSession::IsSameOriginWith(const url::Origin& origin) const {
-  return origin_.IsSameOriginWith(origin);
+bool MediaEngagementSession::IsSameOriginWith(const GURL& url) const {
+  return origin_.IsSameOriginWith(url);
 }
 
 void MediaEngagementSession::RecordSignificantMediaElementPlayback() {
diff --git a/chrome/browser/media/media_engagement_session.h b/chrome/browser/media/media_engagement_session.h
index a5a709f..d0408e9 100644
--- a/chrome/browser/media/media_engagement_session.h
+++ b/chrome/browser/media/media_engagement_session.h
@@ -36,8 +36,8 @@
   MediaEngagementSession(const MediaEngagementSession&) = delete;
   MediaEngagementSession& operator=(const MediaEngagementSession&) = delete;
 
-  // Returns whether the session's origin is same origin with |origin|.
-  bool IsSameOriginWith(const url::Origin& origin) const;
+  // Returns whether the session's origin is same origin with |url|.
+  bool IsSameOriginWith(const GURL& url) const;
 
   // Record that the session received a significant playback from a media
   // element.
diff --git a/chrome/browser/media/media_engagement_session_unittest.cc b/chrome/browser/media/media_engagement_session_unittest.cc
index a9848d2..38d9ff44 100644
--- a/chrome/browser/media/media_engagement_session_unittest.cc
+++ b/chrome/browser/media/media_engagement_session_unittest.cc
@@ -157,17 +157,14 @@
       service(), origin(), MediaEngagementSession::RestoreType::kNotRestored,
       ukm_source_id());
 
-  std::vector<url::Origin> origins = {
-      origin(),
-      url::Origin::Create(GURL("http://example.com")),
-      url::Origin::Create(GURL("https://example.org")),
-      url::Origin(),
-      url::Origin::Create(GURL("http://google.com")),
-      url::Origin::Create(GURL("http://foo.example.com")),
+  std::vector<GURL> urls = {
+      origin().GetURL(),           GURL("http://example.com"),
+      GURL("https://example.org"), GURL(),
+      GURL("http://google.com"),   GURL("http://foo.example.com"),
   };
 
-  for (const auto& orig : origins) {
-    EXPECT_EQ(origin().IsSameOriginWith(orig), session->IsSameOriginWith(orig));
+  for (const auto& url : urls) {
+    EXPECT_EQ(origin().IsSameOriginWith(url), session->IsSameOriginWith(url));
   }
 }
 
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager_common.cc b/chrome/browser/media/webrtc/webrtc_event_log_manager_common.cc
index 372714b..c559ae1 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_manager_common.cc
+++ b/chrome/browser/media/webrtc/webrtc_event_log_manager_common.cc
@@ -1022,7 +1022,7 @@
 // For Chrome OS, exclude special profiles and users.
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   // We do not log an error here since this can happen in several cases,
   // e.g. for signin profiles or lock screen app profiles.
   if (!user) {
@@ -1032,7 +1032,7 @@
   if (user_type != user_manager::USER_TYPE_REGULAR) {
     return false;
   }
-  if (chromeos::ProfileHelper::IsEphemeralUserProfile(profile)) {
+  if (ash::ProfileHelper::IsEphemeralUserProfile(profile)) {
     return false;
   }
 #endif
diff --git a/chrome/browser/metrics/cached_metrics_profile.cc b/chrome/browser/metrics/cached_metrics_profile.cc
index 6f56ea6..4dfb856 100644
--- a/chrome/browser/metrics/cached_metrics_profile.cc
+++ b/chrome/browser/metrics/cached_metrics_profile.cc
@@ -50,8 +50,7 @@
       user_manager::UserManager::Get()->GetPrimaryUser();
   if (!primary_user || !primary_user->is_profile_created())
     return nullptr;
-  cached_profile_ =
-      chromeos::ProfileHelper::Get()->GetProfileByUser(primary_user);
+  cached_profile_ = ash::ProfileHelper::Get()->GetProfileByUser(primary_user);
 #else
   // Find a suitable profile to use, and cache it so that we continue to report
   // statistics on the same profile.
diff --git a/chrome/browser/metrics/chrome_metrics_service_client.cc b/chrome/browser/metrics/chrome_metrics_service_client.cc
index 69653a6..db0ae5fef 100644
--- a/chrome/browser/metrics/chrome_metrics_service_client.cc
+++ b/chrome/browser/metrics/chrome_metrics_service_client.cc
@@ -991,7 +991,7 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   // Ignore the signin, lock screen app and lock screen profile for sync
   // disables / history deletion.
-  if (!chromeos::ProfileHelper::IsRegularProfile(profile)) {
+  if (!ash::ProfileHelper::IsRegularProfile(profile)) {
     // No listeners, but still a success case.
     return true;
   }
diff --git a/chrome/browser/metrics/chromeos_metrics_provider_unittest.cc b/chrome/browser/metrics/chromeos_metrics_provider_unittest.cc
index 1e97d07a..1cd934b 100644
--- a/chrome/browser/metrics/chromeos_metrics_provider_unittest.cc
+++ b/chrome/browser/metrics/chromeos_metrics_provider_unittest.cc
@@ -208,7 +208,7 @@
   user_manager->AddKioskAppUser(account_id1);
   user_manager->LoginUser(account_id1);
   const user_manager::User* primary_user = user_manager->GetPrimaryUser();
-  chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
+  ash::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
       primary_user, testing_profile_);
 
   TestChromeOSMetricsProvider provider;
diff --git a/chrome/browser/metrics/family_link_user_metrics_provider.cc b/chrome/browser/metrics/family_link_user_metrics_provider.cc
index 8763597b..38baec4 100644
--- a/chrome/browser/metrics/family_link_user_metrics_provider.cc
+++ b/chrome/browser/metrics/family_link_user_metrics_provider.cc
@@ -63,10 +63,9 @@
   }
 
   DCHECK(primary_user->is_profile_created());
-  Profile* profile =
-      chromeos::ProfileHelper::Get()->GetProfileByUser(primary_user);
+  Profile* profile = ash::ProfileHelper::Get()->GetProfileByUser(primary_user);
   DCHECK(profile);
-  DCHECK(chromeos::ProfileHelper::IsRegularProfile(profile));
+  DCHECK(ash::ProfileHelper::IsRegularProfile(profile));
 
   signin::IdentityManager* identity_manager =
       IdentityManagerFactory::GetForProfile(profile);
diff --git a/chrome/browser/metrics/family_user_metrics_provider.cc b/chrome/browser/metrics/family_user_metrics_provider.cc
index e5e14868..0c760a35 100644
--- a/chrome/browser/metrics/family_user_metrics_provider.cc
+++ b/chrome/browser/metrics/family_user_metrics_provider.cc
@@ -52,10 +52,9 @@
       user_manager::UserManager::Get()->GetPrimaryUser();
   DCHECK(primary_user);
   DCHECK(primary_user->is_profile_created());
-  Profile* profile =
-      chromeos::ProfileHelper::Get()->GetProfileByUser(primary_user);
+  Profile* profile = ash::ProfileHelper::Get()->GetProfileByUser(primary_user);
   DCHECK(profile);
-  DCHECK(chromeos::ProfileHelper::IsRegularProfile(profile));
+  DCHECK(ash::ProfileHelper::IsRegularProfile(profile));
   return profile;
 }
 
diff --git a/chrome/browser/metrics/perf/metric_provider.cc b/chrome/browser/metrics/perf/metric_provider.cc
index bc6b264..f70dbdc 100644
--- a/chrome/browser/metrics/perf/metric_provider.cc
+++ b/chrome/browser/metrics/perf/metric_provider.cc
@@ -229,7 +229,7 @@
     // The Default profile, lock screen app profile and lock screen profile are
     // all not regular user profiles on Chrome OS. They always disable sync and
     // we would skip them.
-    if (!chromeos::ProfileHelper::IsRegularProfile(profile))
+    if (!ash::ProfileHelper::IsRegularProfile(profile))
       continue;
     auto app_sync_state = AppSyncStateForUserProfile(profile);
     if (app_sync_state != RecordAttemptStatus::kAppSyncEnabled)
diff --git a/chrome/browser/metrics/usertype_by_devicetype_metrics_provider.cc b/chrome/browser/metrics/usertype_by_devicetype_metrics_provider.cc
index 69775f7..140f01b8 100644
--- a/chrome/browser/metrics/usertype_by_devicetype_metrics_provider.cc
+++ b/chrome/browser/metrics/usertype_by_devicetype_metrics_provider.cc
@@ -80,8 +80,7 @@
       user_manager::UserManager::Get()->GetPrimaryUser();
   DCHECK(primary_user);
   DCHECK(primary_user->is_profile_created());
-  Profile* profile =
-      chromeos::ProfileHelper::Get()->GetProfileByUser(primary_user);
+  Profile* profile = ash::ProfileHelper::Get()->GetProfileByUser(primary_user);
   DCHECK(profile);
 
   user_segment_ = GetUserSegment(profile);
diff --git a/chrome/browser/nearby_sharing/nearby_share_profile_info_provider_impl.cc b/chrome/browser/nearby_sharing/nearby_share_profile_info_provider_impl.cc
index f1c43df6..b8fbca0a 100644
--- a/chrome/browser/nearby_sharing/nearby_share_profile_info_provider_impl.cc
+++ b/chrome/browser/nearby_sharing/nearby_share_profile_info_provider_impl.cc
@@ -18,7 +18,7 @@
 absl::optional<std::u16string>
 NearbyShareProfileInfoProviderImpl::GetGivenName() const {
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile_);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile_);
   if (!user)
     return absl::nullopt;
 
diff --git a/chrome/browser/net/nss_context_chromeos_browsertest.cc b/chrome/browser/net/nss_context_chromeos_browsertest.cc
index dac17e6..dca2801 100644
--- a/chrome/browser/net/nss_context_chromeos_browsertest.cc
+++ b/chrome/browser/net/nss_context_chromeos_browsertest.cc
@@ -247,7 +247,7 @@
   user_manager::UserManager* user_manager = user_manager::UserManager::Get();
 
   LoginUser(affiliated_account_id_1_);
-  Profile* profile1 = chromeos::ProfileHelper::Get()->GetProfileByUserUnsafe(
+  Profile* profile1 = ash::ProfileHelper::Get()->GetProfileByUserUnsafe(
       user_manager->FindUser(affiliated_account_id_1_));
   ASSERT_TRUE(profile1);
 
@@ -264,7 +264,7 @@
   const AccountId account_id1(
       login_mixin_.users()[kUnaffiliatedUserIdx1].account_id);
   LoginUser(account_id1);
-  Profile* profile1 = chromeos::ProfileHelper::Get()->GetProfileByUserUnsafe(
+  Profile* profile1 = ash::ProfileHelper::Get()->GetProfileByUserUnsafe(
       user_manager->FindUser(account_id1));
   ASSERT_TRUE(profile1);
 
@@ -280,7 +280,7 @@
 
   // Log in first user and get their DB.
   LoginUser(affiliated_account_id_1_);
-  Profile* profile1 = chromeos::ProfileHelper::Get()->GetProfileByUserUnsafe(
+  Profile* profile1 = ash::ProfileHelper::Get()->GetProfileByUserUnsafe(
       user_manager->FindUser(affiliated_account_id_1_));
   ASSERT_TRUE(profile1);
 
@@ -295,7 +295,7 @@
   AddUser(affiliated_account_id_2_);
   observer.WaitUntilUserAddingFinishedOrCancelled();
 
-  Profile* profile2 = chromeos::ProfileHelper::Get()->GetProfileByUserUnsafe(
+  Profile* profile2 = ash::ProfileHelper::Get()->GetProfileByUserUnsafe(
       user_manager->FindUser(affiliated_account_id_2_));
   ASSERT_TRUE(profile2);
 
@@ -318,7 +318,7 @@
   const AccountId account_id1(
       login_mixin_.users()[kUnaffiliatedUserIdx1].account_id);
   LoginUser(account_id1);
-  Profile* profile1 = chromeos::ProfileHelper::Get()->GetProfileByUserUnsafe(
+  Profile* profile1 = ash::ProfileHelper::Get()->GetProfileByUserUnsafe(
       user_manager->FindUser(account_id1));
   ASSERT_TRUE(profile1);
 
@@ -335,7 +335,7 @@
   AddUser(account_id2);
   observer.WaitUntilUserAddingFinishedOrCancelled();
 
-  Profile* profile2 = chromeos::ProfileHelper::Get()->GetProfileByUserUnsafe(
+  Profile* profile2 = ash::ProfileHelper::Get()->GetProfileByUserUnsafe(
       user_manager->FindUser(account_id2));
   ASSERT_TRUE(profile2);
 
@@ -356,7 +356,7 @@
 
   // Log in first user and get their DB.
   LoginUser(affiliated_account_id_1_);
-  Profile* profile1 = chromeos::ProfileHelper::Get()->GetProfileByUserUnsafe(
+  Profile* profile1 = ash::ProfileHelper::Get()->GetProfileByUserUnsafe(
       user_manager->FindUser(affiliated_account_id_1_));
   ASSERT_TRUE(profile1);
 
@@ -373,7 +373,7 @@
   AddUser(account_id2);
   observer.WaitUntilUserAddingFinishedOrCancelled();
 
-  Profile* profile2 = chromeos::ProfileHelper::Get()->GetProfileByUserUnsafe(
+  Profile* profile2 = ash::ProfileHelper::Get()->GetProfileByUserUnsafe(
       user_manager->FindUser(account_id2));
   ASSERT_TRUE(profile2);
 
diff --git a/chrome/browser/net/nss_service_chromeos.cc b/chrome/browser/net/nss_service_chromeos.cc
index 4eb8b87..bc01796 100644
--- a/chrome/browser/net/nss_service_chromeos.cc
+++ b/chrome/browser/net/nss_service_chromeos.cc
@@ -244,7 +244,7 @@
 
   Profile* profile = Profile::FromBrowserContext(context);
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   // No need to initialize NSS for users with empty username hash:
   // Getters for a user's NSS slots always return a null slot if the user's
   // username hash is empty, even when the NSS is not initialized for the
diff --git a/chrome/browser/net/profile_network_context_service.cc b/chrome/browser/net/profile_network_context_service.cc
index 23196e1..7f8a240 100644
--- a/chrome/browser/net/profile_network_context_service.cc
+++ b/chrome/browser/net/profile_network_context_service.cc
@@ -552,14 +552,14 @@
   // profile, client certificates will only be selected for the StoragePartition
   // currently used in the sign-in frame (see SigninPartitionManager).
   if (chromeos::switches::IsSigninFrameClientCertsEnabled() &&
-      (chromeos::ProfileHelper::IsSigninProfile(profile_) ||
-       chromeos::ProfileHelper::IsLockScreenProfile(profile_))) {
+      (ash::ProfileHelper::IsSigninProfile(profile_) ||
+       ash::ProfileHelper::IsLockScreenProfile(profile_))) {
     use_system_key_slot = true;
   }
 
   std::string username_hash;
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile_);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile_);
   if (user && !user->username_hash().empty()) {
     username_hash = user->username_hash();
 
@@ -867,12 +867,12 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   bool profile_supports_policy_certs = false;
-  if (chromeos::ProfileHelper::IsSigninProfile(profile_))
+  if (ash::ProfileHelper::IsSigninProfile(profile_))
     profile_supports_policy_certs = true;
   user_manager::UserManager* user_manager = user_manager::UserManager::Get();
   if (user_manager) {
     const user_manager::User* user =
-        chromeos::ProfileHelper::Get()->GetUserByProfile(profile_);
+        ash::ProfileHelper::Get()->GetUserByProfile(profile_);
     // No need to initialize NSS for users with empty username hash:
     // Getters for a user's NSS slots always return NULL slot if the user's
     // username hash is empty, even when the NSS is not initialized for the
diff --git a/chrome/browser/net/proxy_config_monitor.cc b/chrome/browser/net/proxy_config_monitor.cc
index 583ae4a36..88fad98 100644
--- a/chrome/browser/net/proxy_config_monitor.cc
+++ b/chrome/browser/net/proxy_config_monitor.cc
@@ -38,7 +38,7 @@
 // If this is the ChromeOS sign-in profile, just create the tracker from global
 // state.
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  if (chromeos::ProfileHelper::IsSigninProfile(profile)) {
+  if (ash::ProfileHelper::IsSigninProfile(profile)) {
     pref_proxy_config_tracker_ =
         ProxyServiceFactory::CreatePrefProxyConfigTrackerOfLocalState(
             g_browser_process->local_state());
diff --git a/chrome/browser/notifications/chrome_ash_message_center_client.cc b/chrome/browser/notifications/chrome_ash_message_center_client.cc
index a6eb62e..6592d02 100644
--- a/chrome/browser/notifications/chrome_ash_message_center_client.cc
+++ b/chrome/browser/notifications/chrome_ash_message_center_client.cc
@@ -33,7 +33,7 @@
 // All notifier actions are performed on the notifiers for the currently active
 // profile, so this just returns the active profile.
 Profile* GetProfileForNotifiers() {
-  return chromeos::ProfileHelper::Get()->GetProfileByUser(
+  return ash::ProfileHelper::Get()->GetProfileByUser(
       user_manager::UserManager::Get()->GetActiveUser());
 }
 
diff --git a/chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.cc b/chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.cc
index 046225b..90eb382c 100644
--- a/chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.cc
+++ b/chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.cc
@@ -53,7 +53,7 @@
   // are required are not available when the browser context for the signin
   // profile is created.
   Profile* profile = Profile::FromBrowserContext(context);
-  if (chromeos::ProfileHelper::IsSigninProfile(profile))
+  if (ash::ProfileHelper::IsSigninProfile(profile))
     return nullptr;
 #endif
   return new OptimizationGuideKeyedService(context);
diff --git a/chrome/browser/policy/chrome_policy_conversions_client.cc b/chrome/browser/policy/chrome_policy_conversions_client.cc
index e57c08ca..3c43181 100644
--- a/chrome/browser/policy/chrome_policy_conversions_client.cc
+++ b/chrome/browser/policy/chrome_policy_conversions_client.cc
@@ -125,9 +125,8 @@
   const bool for_signin_screen =
       policy_domain == POLICY_DOMAIN_SIGNIN_EXTENSIONS;
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  Profile* extension_profile = for_signin_screen
-                                   ? chromeos::ProfileHelper::GetSigninProfile()
-                                   : profile_;
+  Profile* extension_profile =
+      for_signin_screen ? ash::ProfileHelper::GetSigninProfile() : profile_;
 #else   // BUILDFLAG(IS_CHROMEOS_ASH)
   Profile* extension_profile = profile_;
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/policy/dm_token_utils.cc b/chrome/browser/policy/dm_token_utils.cc
index 330375a..da2bcaec 100644
--- a/chrome/browser/policy/dm_token_utils.cc
+++ b/chrome/browser/policy/dm_token_utils.cc
@@ -46,7 +46,7 @@
     return dm_token;
 
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   if (!user)
     return dm_token;
 
diff --git a/chrome/browser/policy/messaging_layer/public/report_client_unittest.cc b/chrome/browser/policy/messaging_layer/public/report_client_unittest.cc
index 098a793..f3fd0cc 100644
--- a/chrome/browser/policy/messaging_layer/public/report_client_unittest.cc
+++ b/chrome/browser/policy/messaging_layer/public/report_client_unittest.cc
@@ -76,7 +76,7 @@
         profile_->GetProfileUserName(), "12345"));
     const user_manager::User* user =
         mock_user_manager->AddPublicAccountUser(account_id);
-    chromeos::ProfileHelper::Get()->SetActiveUserIdForTesting(
+    ash::ProfileHelper::Get()->SetActiveUserIdForTesting(
         profile_->GetProfileUserName());
     mock_user_manager->UserLoggedIn(account_id, user->username_hash(),
                                     /*browser_restart=*/false,
diff --git a/chrome/browser/policy/policy_prefs_browsertest.cc b/chrome/browser/policy/policy_prefs_browsertest.cc
index 59e7976..7455b3a 100644
--- a/chrome/browser/policy/policy_prefs_browsertest.cc
+++ b/chrome/browser/policy/policy_prefs_browsertest.cc
@@ -151,7 +151,7 @@
 
 IN_PROC_BROWSER_TEST_F(SigninPolicyPrefsTest, PolicyToPrefsMapping) {
   PrefService* signin_profile_prefs =
-      chromeos::ProfileHelper::GetSigninProfile()->GetPrefs();
+      ash::ProfileHelper::GetSigninProfile()->GetPrefs();
 
   // Only checking signin_profile_prefs here since |local_state| is already
   // checked by PolicyPrefsTest.PolicyToPrefsMapping test.
diff --git a/chrome/browser/policy/profile_policy_connector_builder.cc b/chrome/browser/policy/profile_policy_connector_builder.cc
index 19ad393..3d551a4 100644
--- a/chrome/browser/policy/profile_policy_connector_builder.cc
+++ b/chrome/browser/policy/profile_policy_connector_builder.cc
@@ -48,8 +48,8 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   Profile* const profile = Profile::FromBrowserContext(context);
-  if (chromeos::ProfileHelper::IsRegularProfile(profile)) {
-    user = chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+  if (ash::ProfileHelper::IsRegularProfile(profile)) {
+    user = ash::ProfileHelper::Get()->GetUserByProfile(profile);
     CHECK(user);
   }
 
diff --git a/chrome/browser/policy/schema_registry_service_builder.cc b/chrome/browser/policy/schema_registry_service_builder.cc
index 937ea2a..00e49cd 100644
--- a/chrome/browser/policy/schema_registry_service_builder.cc
+++ b/chrome/browser/policy/schema_registry_service_builder.cc
@@ -36,7 +36,7 @@
 DeviceLocalAccountPolicyBroker* GetBroker(content::BrowserContext* context) {
   Profile* profile = Profile::FromBrowserContext(context);
 
-  if (chromeos::ProfileHelper::IsSigninProfile(profile))
+  if (ash::ProfileHelper::IsSigninProfile(profile))
     return NULL;
 
   if (!user_manager::UserManager::IsInitialized()) {
@@ -45,7 +45,7 @@
   }
 
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   if (!user)
     return NULL;
 
@@ -87,7 +87,7 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   Profile* const profile = Profile::FromBrowserContext(context);
-  if (chromeos::ProfileHelper::IsSigninProfile(profile)) {
+  if (ash::ProfileHelper::IsSigninProfile(profile)) {
     // Pass the SchemaRegistry of the signin profile to the device policy
     // managers, for being used for fetching the component policies.
     BrowserPolicyConnectorAsh* connector =
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
index 483d413c..8c5871eb 100644
--- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
+++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
@@ -541,6 +541,8 @@
             "Chrome.CrashReporting.LastSessionApplicationState";
 
     public static final String LOCALE_MANAGER_AUTO_SWITCH = "LocaleManager_PREF_AUTO_SWITCH";
+    public static final String LOCALE_MANAGER_MISSING_TIMEZONES =
+            "com.android.chrome.MISSING_TIMEZONES";
     public static final String LOCALE_MANAGER_PARTNER_PROMO_KEYWORD_SELECTED =
             "LocaleManager_PARTNER_PROMO_SELECTED_KEYWORD";
     public static final String LOCALE_MANAGER_PROMO_SHOWN = "LocaleManager_PREF_PROMO_SHOWN";
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/LegacyChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/LegacyChromePreferenceKeys.java
index cb1dd771..18781da4 100644
--- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/LegacyChromePreferenceKeys.java
+++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/LegacyChromePreferenceKeys.java
@@ -103,6 +103,7 @@
                 ChromePreferenceKeys.INCOGNITO_SHORTCUT_ADDED,
                 ChromePreferenceKeys.LATEST_UNSUPPORTED_VERSION,
                 ChromePreferenceKeys.LOCALE_MANAGER_AUTO_SWITCH,
+                ChromePreferenceKeys.LOCALE_MANAGER_MISSING_TIMEZONES,
                 ChromePreferenceKeys.LOCALE_MANAGER_PARTNER_PROMO_KEYWORD_SELECTED,
                 ChromePreferenceKeys.LOCALE_MANAGER_PROMO_SHOWN,
                 ChromePreferenceKeys.LOCALE_MANAGER_SEARCH_ENGINE_PROMO_SHOW_STATE,
diff --git a/chrome/browser/prefetch/no_state_prefetch/no_state_prefetch_navigation_throttle.cc b/chrome/browser/prefetch/no_state_prefetch/no_state_prefetch_navigation_throttle.cc
index ccfac15..2593a01 100644
--- a/chrome/browser/prefetch/no_state_prefetch/no_state_prefetch_navigation_throttle.cc
+++ b/chrome/browser/prefetch/no_state_prefetch/no_state_prefetch_navigation_throttle.cc
@@ -36,10 +36,9 @@
   if (!prefetch_url.SchemeIsHTTPOrHTTPS()) {
     return {CANCEL, net::ERR_BLOCKED_BY_CLIENT};
   }
-  url::Origin prefetch_origin = url::Origin::Create(prefetch_url);
   DCHECK(navigation_handle()->GetInitiatorOrigin());
-  if (!prefetch_origin.IsSameOriginWith(
-          navigation_handle()->GetInitiatorOrigin().value())) {
+  if (!navigation_handle()->GetInitiatorOrigin()->IsSameOriginWith(
+          prefetch_url)) {
     return {CANCEL, net::ERR_BLOCKED_BY_CLIENT};
   }
   return PROCEED;
diff --git a/chrome/browser/prefetch/prefetch_proxy/chrome_speculation_host_delegate.cc b/chrome/browser/prefetch/prefetch_proxy/chrome_speculation_host_delegate.cc
index 84202f5..066096e 100644
--- a/chrome/browser/prefetch/prefetch_proxy/chrome_speculation_host_delegate.cc
+++ b/chrome/browser/prefetch/prefetch_proxy/chrome_speculation_host_delegate.cc
@@ -48,15 +48,14 @@
   // non-private prefetches with subresources.
   std::vector<GURL> same_origin_prefetches_with_subresources;
 
-  const url::Origin origin = render_frame_host_.GetLastCommittedOrigin();
+  const url::Origin& origin = render_frame_host_.GetLastCommittedOrigin();
 
   // Returns true if the given entry is processed. Being processed means this
   // delegate has a corresponding strategy to process the candidate, so it
   // extracts the candidate's URL.
   auto should_process_entry =
       [&](const blink::mojom::SpeculationCandidatePtr& candidate) {
-        bool is_same_origin =
-            url::Origin::Create(candidate->url).IsSameOriginWith(origin);
+        bool is_same_origin = origin.IsSameOriginWith(candidate->url);
         bool private_prefetch =
             candidate->requires_anonymous_client_ip_when_cross_origin &&
             !is_same_origin;
diff --git a/chrome/browser/prerender/omnibox_prerender_browsertest.cc b/chrome/browser/prerender/omnibox_prerender_browsertest.cc
index 98171a3..751d757e 100644
--- a/chrome/browser/prerender/omnibox_prerender_browsertest.cc
+++ b/chrome/browser/prerender/omnibox_prerender_browsertest.cc
@@ -157,17 +157,9 @@
 }
 
 // Verifies that prerendering functions in document are properly exposed.
-// TODO(crbug.com/1286374): Flakes on Windows, Mac and Linux.
-#if defined(OS_LINUX) || defined(OS_WIN) || defined(OS_MAC)
-#define MAYBE_PrerenderFunctionsProperlyExportedWhenInitiatedByOmnibox \
-  DISABLED_PrerenderFunctionsProperlyExportedWhenInitiatedByOmnibox
-#else
-#define MAYBE_PrerenderFunctionsProperlyExportedWhenInitiatedByOmnibox \
-  PrerenderFunctionsProperlyExportedWhenInitiatedByOmnibox
-#endif
 IN_PROC_BROWSER_TEST_F(
     OmniboxPrerenderBrowserTest,
-    MAYBE_PrerenderFunctionsProperlyExportedWhenInitiatedByOmnibox) {
+    PrerenderFunctionsProperlyExportedWhenInitiatedByOmnibox) {
   const GURL kInitialUrl = embedded_test_server()->GetURL("/empty.html");
   ASSERT_TRUE(GetActiveWebContents());
   ASSERT_TRUE(content::NavigateToURL(GetActiveWebContents(), kInitialUrl));
@@ -206,7 +198,8 @@
   EXPECT_LT(
       0.0,
       EvalJs(prerender_frame_host,
-             "performance.getEntriesByType('navigation')[0].activationStart"));
+             "performance.getEntriesByType('navigation')[0].activationStart")
+          .ExtractDouble());
 }
 
 // Verifies that the exportation of prerendering functions in the document is
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.cc b/chrome/browser/profiles/off_the_record_profile_impl.cc
index 8672425f..f3c3a94 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl.cc
+++ b/chrome/browser/profiles/off_the_record_profile_impl.cc
@@ -241,7 +241,7 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   // Bypass profile lifetime recording for ChromeOS helper profiles (sign-in,
   // lockscreen, etc).
-  if (!chromeos::ProfileHelper::IsRegularProfile(profile_))
+  if (!ash::ProfileHelper::IsRegularProfile(profile_))
     return;
 #endif
   // Store incognito lifetime and navigations count histogram.
diff --git a/chrome/browser/profiles/profile_browsertest.cc b/chrome/browser/profiles/profile_browsertest.cc
index feb5e0e..f367b5c 100644
--- a/chrome/browser/profiles/profile_browsertest.cc
+++ b/chrome/browser/profiles/profile_browsertest.cc
@@ -552,7 +552,7 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   for (auto* loaded_profile : loaded_profiles) {
-    if (!chromeos::ProfileHelper::IsSigninProfile(loaded_profile)) {
+    if (!ash::ProfileHelper::IsSigninProfile(loaded_profile)) {
       profile = loaded_profile;
       break;
     }
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 97eafbff..c676ceb2 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -444,12 +444,11 @@
                         << "profile files to the root directory!";
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  const bool is_regular_profile =
-      chromeos::ProfileHelper::IsRegularProfile(this);
+  const bool is_regular_profile = ash::ProfileHelper::IsRegularProfile(this);
 
   if (is_regular_profile) {
     const user_manager::User* user =
-        chromeos::ProfileHelper::Get()->GetUserByProfile(this);
+        ash::ProfileHelper::Get()->GetUserByProfile(this);
     // A |User| instance should always exist for a profile which is not the
     // initial, the sign-in or the lock screen app profile.
     CHECK(user);
@@ -621,7 +620,7 @@
 
   bool is_signin_profile = false;
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  is_signin_profile = chromeos::ProfileHelper::IsSigninProfile(this);
+  is_signin_profile = ash::ProfileHelper::IsSigninProfile(this);
 #endif
   ::RegisterProfilePrefs(is_signin_profile,
                          g_browser_process->GetApplicationLocale(),
@@ -653,7 +652,7 @@
   // immediately. We need to cache the LacrosLaunchSwitch now, as the value is
   // needed later, while the profile is not fully initialized.
   if (force_immediate_policy_load &&
-      chromeos::ProfileHelper::IsPrimaryProfile(this)) {
+      ash::ProfileHelper::IsPrimaryProfile(this)) {
     auto& map = profile_policy_connector_->policy_service()->GetPolicies(
         policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string()));
     crosapi::browser_util::CacheLacrosLaunchSwitch(map);
@@ -1052,8 +1051,8 @@
 
 bool ProfileImpl::AllowsBrowserWindows() const {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  if (chromeos::ProfileHelper::IsSigninProfile(this) ||
-      chromeos::ProfileHelper::IsLockScreenAppProfile(this)) {
+  if (ash::ProfileHelper::IsSigninProfile(this) ||
+      ash::ProfileHelper::IsLockScreenAppProfile(this)) {
     return false;
   }
 #endif
@@ -1132,7 +1131,7 @@
     // or we are in tests. In both cases the first loaded locale is correct.
     OnLocaleReady(create_mode);
   } else {
-    if (chromeos::ProfileHelper::IsPrimaryProfile(this)) {
+    if (ash::ProfileHelper::IsPrimaryProfile(this)) {
       auto& map = profile_policy_connector_->policy_service()->GetPolicies(
           policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string()));
       crosapi::browser_util::CacheLacrosLaunchSwitch(map);
@@ -1460,7 +1459,7 @@
     local_state->SetString(language::prefs::kApplicationLocale, new_locale);
 
   if (user_manager::UserManager::Get()->GetOwnerAccountId() ==
-      chromeos::ProfileHelper::Get()->GetUserByProfile(this)->GetAccountId())
+      ash::ProfileHelper::Get()->GetUserByProfile(this)->GetAccountId())
     local_state->SetString(prefs::kOwnerLocale, new_locale);
 }
 
@@ -1473,7 +1472,7 @@
 void ProfileImpl::InitChromeOSPreferences() {
   chromeos_preferences_ = std::make_unique<ash::Preferences>();
   chromeos_preferences_->Init(
-      this, chromeos::ProfileHelper::Get()->GetUserByProfile(this));
+      this, ash::ProfileHelper::Get()->GetUserByProfile(this));
 }
 
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
index 4339f23..efb5169 100644
--- a/chrome/browser/profiles/profile_manager.cc
+++ b/chrome/browser/profiles/profile_manager.cc
@@ -584,7 +584,7 @@
   // since it may refer to profile that has been in use in previous session.
   // That profile dir may not be mounted in this session so instead return
   // active profile from current session.
-  profile_dir = chromeos::ProfileHelper::Get()->GetActiveUserProfileDir();
+  profile_dir = ash::ProfileHelper::Get()->GetActiveUserProfileDir();
 
   Profile* profile = profile_manager->GetProfileByPath(
       profile_manager->user_data_dir().Append(profile_dir));
@@ -674,7 +674,7 @@
       return nullptr;
 
     // Note: The ProfileHelper will take care of guest profiles.
-    return chromeos::ProfileHelper::Get()->GetProfileByUserUnsafe(user);
+    return ash::ProfileHelper::Get()->GetProfileByUserUnsafe(user);
   }
 #endif
 
@@ -700,7 +700,7 @@
     // yet created we load the profile using the profile directly.
     // TODO: This should be cleaned up with the new profile manager.
     if (user && user->is_profile_created())
-      return chromeos::ProfileHelper::Get()->GetProfileByUserUnsafe(user);
+      return ash::ProfileHelper::Get()->GetProfileByUserUnsafe(user);
   }
 #endif
   Profile* profile = profile_manager->GetActiveUserOrOffTheRecordProfile();
@@ -840,7 +840,7 @@
 base::FilePath ProfileManager::GetInitialProfileDir() {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   if (IsLoggedIn())
-    return chromeos::ProfileHelper::Get()->GetActiveUserProfileDir();
+    return ash::ProfileHelper::Get()->GetActiveUserProfileDir();
 #endif
   base::FilePath relative_profile_dir;
   // TODO(mirandac): should not automatically be default profile.
@@ -1234,7 +1234,7 @@
   // If profile type has changed, remove ProfileAttributesEntry for it to make
   // sure it is fully re-initialized later.
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   if (user) {
     const bool user_is_child =
         (user->GetType() == user_manager::USER_TYPE_CHILD);
@@ -1582,10 +1582,10 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kDisableLoginScreenApps) &&
-      chromeos::ProfileHelper::IsSigninProfile(profile)) {
+      ash::ProfileHelper::IsSigninProfile(profile)) {
     extensions_enabled = true;
   }
-  if (chromeos::ProfileHelper::IsLockScreenAppProfile(profile))
+  if (ash::ProfileHelper::IsLockScreenAppProfile(profile))
     extensions_enabled = true;
 #endif
   extensions::ExtensionSystem::Get(profile)->InitForRegularProfile(
@@ -1627,7 +1627,7 @@
   UnifiedConsentServiceFactory::GetForProfile(profile);
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  if (!chromeos::ProfileHelper::IsSigninProfile(profile))
+  if (!ash::ProfileHelper::IsSigninProfile(profile))
     captions::LiveCaptionControllerFactory::GetForProfile(profile)->Init();
 #elif !defined(OS_ANDROID)  // !OS_ANDROID && !IS_CHROMEOS_ASH
   captions::LiveCaptionControllerFactory::GetForProfile(profile)->Init();
@@ -2210,7 +2210,7 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   if (user)
     init_params.account_id = user->GetAccountId();
 #endif
@@ -2236,7 +2236,7 @@
 
 bool ProfileManager::ShouldGoOffTheRecord(Profile* profile) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  if (!chromeos::ProfileHelper::IsRegularProfile(profile)) {
+  if (!ash::ProfileHelper::IsRegularProfile(profile)) {
     return true;
   }
 #endif
diff --git a/chrome/browser/profiles/profile_manager_browsertest.cc b/chrome/browser/profiles/profile_manager_browsertest.cc
index 7e1e1510e..e8c6cdb 100644
--- a/chrome/browser/profiles/profile_manager_browsertest.cc
+++ b/chrome/browser/profiles/profile_manager_browsertest.cc
@@ -227,10 +227,9 @@
   std::vector<ProfileAttributesEntry*> entries =
       storage->GetAllProfilesAttributesSortedByName();
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  const base::FilePath signin_path =
-      chromeos::ProfileHelper::GetSigninProfileDir();
+  const base::FilePath signin_path = ash::ProfileHelper::GetSigninProfileDir();
   const base::FilePath lock_screen_apps_path =
-      chromeos::ProfileHelper::GetLockScreenAppProfilePath();
+      ash::ProfileHelper::GetLockScreenAppProfilePath();
 
   for (ProfileAttributesEntry* entry : entries) {
     base::FilePath profile_path = entry->GetPath();
diff --git a/chrome/browser/profiles/profile_manager_unittest.cc b/chrome/browser/profiles/profile_manager_unittest.cc
index 453eabfd..8bb35dd 100644
--- a/chrome/browser/profiles/profile_manager_unittest.cc
+++ b/chrome/browser/profiles/profile_manager_unittest.cc
@@ -245,7 +245,7 @@
   // Helper function to register an user with id |user_id| and create profile
   // with a correct path.
   void RegisterUser(const AccountId& account_id) {
-    chromeos::ProfileHelper* profile_helper = chromeos::ProfileHelper::Get();
+    ash::ProfileHelper* profile_helper = ash::ProfileHelper::Get();
     const std::string user_id_hash =
         profile_helper->GetUserIdHashByUserIdForTesting(
             account_id.GetUserEmail());
@@ -263,7 +263,7 @@
       bool user_is_child,
       bool profile_is_managed,
       absl::optional<bool> arc_is_managed) {
-    chromeos::ProfileHelper* profile_helper = chromeos::ProfileHelper::Get();
+    ash::ProfileHelper* profile_helper = ash::ProfileHelper::Get();
     user_manager::UserManager* user_manager = user_manager::UserManager::Get();
 
     const std::string user_email = "user_for_transition@example.com";
@@ -390,7 +390,7 @@
   user_manager->SwitchActiveUser(test_account_id);
 
   base::FilePath expected_logged_in(
-      chromeos::ProfileHelper::GetUserProfileDir(active_user->username_hash()));
+      ash::ProfileHelper::GetUserProfileDir(active_user->username_hash()));
   EXPECT_EQ(expected_logged_in.value(),
             profile_manager->GetInitialProfileDir().value());
   VLOG(1) << temp_dir_.GetPath()
@@ -400,7 +400,7 @@
 
 // Test Get[ActiveUser|PrimaryUser|LastUsed]Profile does not load user profile.
 TEST_F(ProfileManagerTest, UserProfileLoading) {
-  using chromeos::ProfileHelper;
+  using ::ash::ProfileHelper;
 
   Profile* const signin_profile = ProfileHelper::GetSigninProfile();
 
diff --git a/chrome/browser/profiles/reporting_util.cc b/chrome/browser/profiles/reporting_util.cc
index b602df64..c0b864e 100644
--- a/chrome/browser/profiles/reporting_util.cc
+++ b/chrome/browser/profiles/reporting_util.cc
@@ -110,7 +110,7 @@
     return std::string();
 
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   if (!user)
     return std::string();
 
diff --git a/chrome/browser/renderer_context_menu/quick_answers_menu_observer.cc b/chrome/browser/renderer_context_menu/quick_answers_menu_observer.cc
index 29479181..8708930 100644
--- a/chrome/browser/renderer_context_menu/quick_answers_menu_observer.cc
+++ b/chrome/browser/renderer_context_menu/quick_answers_menu_observer.cc
@@ -42,7 +42,7 @@
 constexpr int kMaxSurroundingTextLength = 300;
 
 bool IsInternalUser(Profile* profile) {
-  auto* user = chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+  auto* user = ash::ProfileHelper::Get()->GetUserByProfile(profile);
   // TODO(b/186906279): Add user login support for browser test.
   if (!user)
     return false;
diff --git a/chrome/browser/resources/chromeos/emoji_picker/constants.js b/chrome/browser/resources/chromeos/emoji_picker/constants.js
index 872b5acf..0bad62110 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/constants.js
+++ b/chrome/browser/resources/chromeos/emoji_picker/constants.js
@@ -30,6 +30,7 @@
 export const V2_EMOJI_PICKER_SIDE_PADDING = 20;
 export const V2_EMOJI_ICON_SIZE = 32;
 export const V2_GROUP_PER_ROW = 10;
+export const V2_EMOJI_PER_ROW = 9;
 export const V2_EMOJI_GROUP_SPACING =
     (V2_EMOJI_PICKER_WIDTH - 2 * V2_EMOJI_PICKER_SIDE_PADDING -
      V2_GROUP_PER_ROW * V2_EMOJI_ICON_SIZE) /
@@ -37,6 +38,10 @@
 export const V2_EMOJI_PICKER_TOTAL_EMOJI_WIDTH =
     V2_EMOJI_ICON_SIZE + V2_EMOJI_GROUP_SPACING;
 export const V2_TAB_BUTTON_MARGIN = 5;
+export const V2_EMOJI_SPACING =
+    (V2_EMOJI_PICKER_WIDTH - 2 * V2_EMOJI_PICKER_SIDE_PADDING -
+     V2_EMOJI_PER_ROW * V2_EMOJI_ICON_SIZE) /
+    (V2_EMOJI_PER_ROW - 1);
 
 export const V2_EMOJI_PICKER_HEIGHT_PX = `${V2_EMOJI_PICKER_HEIGHT}px`;
 export const V2_EMOJI_PICKER_WIDTH_PX = `${V2_EMOJI_PICKER_WIDTH}px`;
@@ -47,3 +52,4 @@
 export const V2_EMOJI_PICKER_TOTAL_EMOJI_WIDTH_PX =
     `${V2_EMOJI_PICKER_TOTAL_EMOJI_WIDTH}px`;
 export const V2_TAB_BUTTON_MARGIN_PX = `${V2_TAB_BUTTON_MARGIN}px`;
+export const V2_EMOJI_SPACING_PX = `${V2_EMOJI_SPACING}px`;
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_group.html b/chrome/browser/resources/chromeos/emoji_picker/emoji_group.html
index 0ddd8f86..a476487 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_group.html
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_group.html
@@ -87,6 +87,11 @@
     background-color: var(--cros-button-background-color-secondary-hover);
     border: 2px solid var(--cros-button-background-color-secondary-hover);
   }
+
+  :host([v2-enabled]) {
+    --emoji-size: var(--v2-emoji-size);
+    --emoji-spacing: var(--v2-emoji-spacing);
+  }
 </style>
 
 <div id="heading" role="heading" aria-level="2" tabindex="-1">
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.html b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.html
index 017666b..bfa92f38 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.html
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.html
@@ -339,13 +339,15 @@
     -->
     <div data-group="history">
       <template is="dom-if" if="[[history.emoji.length]]">
-        <emoji-group data="[[history]]" preferred="{}" clearable>
+        <emoji-group data="[[history]]" preferred="{}" clearable
+          v2-enabled$="[[v2Enabled]]">
         </emoji-group>
       </template>
     </div>
     <template is="dom-repeat" items="[[emojiData]]">
       <div data-group$="[[index]]">
-        <emoji-group data="[[item]]" preferred="[[preferenceMapping]]">
+        <emoji-group data="[[item]]" preferred="[[preferenceMapping]]"
+          v2-enabled$="[[v2Enabled]]">
         </emoji-group>
       </div>
     </template>
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.js b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.js
index c00f526..c588866 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.js
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.js
@@ -12,7 +12,7 @@
 import {assert} from 'chrome://resources/js/assert.m.js';
 import {afterNextRender, html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-import {EMOJI_GROUP_SIZE_PX, EMOJI_ICON_SIZE, EMOJI_PER_ROW, EMOJI_PICKER_HEIGHT_PX, EMOJI_PICKER_SIDE_PADDING, EMOJI_PICKER_SIDE_PADDING_PX, EMOJI_PICKER_TOP_PADDING_PX, EMOJI_PICKER_TOTAL_EMOJI_WIDTH, EMOJI_PICKER_TOTAL_EMOJI_WIDTH_PX, EMOJI_PICKER_WIDTH, EMOJI_PICKER_WIDTH_PX, EMOJI_SIZE_PX, EMOJI_SPACING_PX, GROUP_ICON_SIZE, GROUP_PER_ROW, V2_EMOJI_GROUP_SPACING_PX, V2_EMOJI_ICON_SIZE, V2_EMOJI_ICON_SIZE_PX, V2_EMOJI_PICKER_HEIGHT_PX, V2_EMOJI_PICKER_SIDE_PADDING_PX, V2_EMOJI_PICKER_TOTAL_EMOJI_WIDTH, V2_EMOJI_PICKER_WIDTH_PX, V2_TAB_BUTTON_MARGIN, V2_TAB_BUTTON_MARGIN_PX} from './constants.js';
+import {EMOJI_GROUP_SIZE_PX, EMOJI_ICON_SIZE, EMOJI_PER_ROW, EMOJI_PICKER_HEIGHT_PX, EMOJI_PICKER_SIDE_PADDING, EMOJI_PICKER_SIDE_PADDING_PX, EMOJI_PICKER_TOP_PADDING_PX, EMOJI_PICKER_TOTAL_EMOJI_WIDTH, EMOJI_PICKER_TOTAL_EMOJI_WIDTH_PX, EMOJI_PICKER_WIDTH, EMOJI_PICKER_WIDTH_PX, EMOJI_SIZE_PX, EMOJI_SPACING_PX, GROUP_ICON_SIZE, GROUP_PER_ROW, V2_EMOJI_GROUP_SPACING_PX, V2_EMOJI_ICON_SIZE, V2_EMOJI_ICON_SIZE_PX, V2_EMOJI_PICKER_HEIGHT_PX, V2_EMOJI_PICKER_SIDE_PADDING_PX, V2_EMOJI_PICKER_TOTAL_EMOJI_WIDTH, V2_EMOJI_PICKER_WIDTH_PX, V2_EMOJI_SPACING_PX, V2_TAB_BUTTON_MARGIN, V2_TAB_BUTTON_MARGIN_PX} from './constants.js';
 import {EmojiButton} from './emoji_button.js';
 import {Feature} from './emoji_picker.mojom-webui.js';
 import {EmojiPickerApiProxy, EmojiPickerApiProxyImpl} from './emoji_picker_api_proxy.js';
@@ -283,6 +283,7 @@
       '--v2-emoji-size': V2_EMOJI_ICON_SIZE_PX,
       '--v2-emoji-group-spacing': V2_EMOJI_GROUP_SPACING_PX,
       '--v2-tab-button-margin': V2_TAB_BUTTON_MARGIN_PX,
+      '--v2-emoji-spacing': V2_EMOJI_SPACING_PX,
     });
   }
 
diff --git a/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_device_detail_subpage.html b/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_device_detail_subpage.html
index 7104b7d..253db7f 100644
--- a/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_device_detail_subpage.html
+++ b/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_device_detail_subpage.html
@@ -27,7 +27,7 @@
 <div id="container">
   <div id="deviceStateSettings" class="settings-box two-line first">
     <iron-icon id="statusIcon"
-        icon="[[getBluetoothStateIcon_(device_.*, pageState_)]]">
+        icon="[[getBluetoothStateIcon_(isDeviceConnected_)]]">
     </iron-icon>
     <div id="bluetoothState"
         class="middle settings-box-text">
@@ -110,7 +110,8 @@
     </cr-button>
   </div>
   <template is="dom-if"
-      if="[[shouldShowChangeMouseDeviceSettings_(device_.*)]]" restamp>
+      if="[[shouldShowChangeMouseDeviceSettings_(device_.*,
+          isDeviceConnected_)]]" restamp>
     <cr-link-row
         id="changeMouseSettings"
         class="hr settings-box"
@@ -119,7 +120,8 @@
     </cr-link-row>
   </template>
   <template is="dom-if"
-      if="[[shouldShowChangeKeyboardDeviceSettings_(device_.*)]]" restamp>
+      if="[[shouldShowChangeKeyboardDeviceSettings_(device_.*,
+          isDeviceConnected_)]]" restamp>
     <cr-link-row
         id="changeKeyboardSettings"
         class="hr settings-box"
diff --git a/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_device_detail_subpage.js b/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_device_detail_subpage.js
index 745ef13..81f9a9b 100644
--- a/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_device_detail_subpage.js
+++ b/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_device_detail_subpage.js
@@ -91,7 +91,7 @@
       isDeviceConnected_: {
         reflectToAttribute: true,
         type: Boolean,
-        computed: 'computeIsDeviceConnected_(pageState_)',
+        computed: 'computeIsDeviceConnected_(device_.*)',
       },
 
       /** @private */
@@ -138,11 +138,12 @@
     super.currentRouteChanged(route, opt_oldRoute);
 
     if (route !== this.route_) {
-      this.deviceId_ = '';
-      this.pageState_ = PageState.DISCONNECTED;
       return;
     }
 
+    this.deviceId_ = '';
+    this.pageState_ = PageState.DISCONNECTED;
+
     const queryParams = Router.getInstance().getQueryParameters();
     const deviceId = queryParams.get('id') || '';
     if (!deviceId) {
@@ -179,7 +180,11 @@
    * @private
    */
   computeIsDeviceConnected_() {
-    return this.pageState_ === PageState.CONNECTED;
+    if (!this.device_) {
+      return false;
+    }
+    return this.device_.deviceProperties.connectionState ===
+        mojom.DeviceConnectionState.kConnected;
   }
 
   /**
@@ -187,9 +192,8 @@
    * @private
    */
   getBluetoothStateIcon_() {
-    return this.pageState_ === PageState.CONNECTED ?
-        'os-settings:bluetooth-connected' :
-        'os-settings:bluetooth-disabled';
+    return this.isDeviceConnected_ ? 'os-settings:bluetooth-connected' :
+                                     'os-settings:bluetooth-disabled';
   }
 
   /**
@@ -425,7 +429,7 @@
    * @private
    */
   shouldShowChangeMouseDeviceSettings_() {
-    if (!this.device_) {
+    if (!this.device_ || !this.isDeviceConnected_) {
       return false;
     }
     return this.device_.deviceProperties.deviceType === mojom.DeviceType.kMouse;
@@ -436,7 +440,7 @@
    * @private
    */
   shouldShowChangeKeyboardDeviceSettings_() {
-    if (!this.device_) {
+    if (!this.device_ || !this.isDeviceConnected_) {
       return false;
     }
     return this.device_.deviceProperties.deviceType ===
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.cc b/chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.cc
index 00ae150..25728ae 100644
--- a/chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.cc
+++ b/chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.cc
@@ -72,9 +72,7 @@
 
   // Ensure URL construction didn't change origin.
   const GURL download_root(kDownloadRootPath);
-  const url::Origin known_good_origin = url::Origin::Create(download_root);
-  url::Origin current_origin = url::Origin::Create(download_url);
-  if (!current_origin.IsSameOriginWith(known_good_origin))
+  if (!url::IsSameOriginWith(download_url, download_root))
     return GetStableDownloadURL();
 
   return download_url;
diff --git a/chrome/browser/send_tab_to_self/send_tab_to_self_client_service_factory.cc b/chrome/browser/send_tab_to_self/send_tab_to_self_client_service_factory.cc
index e7f5057..a510efa 100644
--- a/chrome/browser/send_tab_to_self/send_tab_to_self_client_service_factory.cc
+++ b/chrome/browser/send_tab_to_self/send_tab_to_self_client_service_factory.cc
@@ -59,7 +59,7 @@
   // users that are not Gaia users, such as public account users. Do not
   // create the service for them.
   user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   // Ensure that the profile is a user profile.
   if (!user)
     return nullptr;
diff --git a/chrome/browser/serial/serial_chooser_context.cc b/chrome/browser/serial/serial_chooser_context.cc
index f591b22..f8834802 100644
--- a/chrome/browser/serial/serial_chooser_context.cc
+++ b/chrome/browser/serial/serial_chooser_context.cc
@@ -571,7 +571,7 @@
 
 bool SerialChooserContext::CanApplyPortSpecificPolicy() {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  auto* profile_helper = chromeos::ProfileHelper::Get();
+  auto* profile_helper = ash::ProfileHelper::Get();
   DCHECK(profile_helper);
   user_manager::User* user = profile_helper->GetUserByProfile(profile_);
   DCHECK(user);
diff --git a/chrome/browser/sessions/exit_type_service_factory.cc b/chrome/browser/sessions/exit_type_service_factory.cc
index 4ab651d0..04a7fc27 100644
--- a/chrome/browser/sessions/exit_type_service_factory.cc
+++ b/chrome/browser/sessions/exit_type_service_factory.cc
@@ -43,7 +43,7 @@
     return nullptr;
     // TODO(sky): is this necessary?
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  if (chromeos::ProfileHelper::IsSigninProfile(profile))
+  if (ash::ProfileHelper::IsSigninProfile(profile))
     return nullptr;
 #endif
   return new ExitTypeService(profile);
diff --git a/chrome/browser/sharesheet/sharesheet_service_factory.cc b/chrome/browser/sharesheet/sharesheet_service_factory.cc
index 7b679a6a..7692876 100644
--- a/chrome/browser/sharesheet/sharesheet_service_factory.cc
+++ b/chrome/browser/sharesheet/sharesheet_service_factory.cc
@@ -53,7 +53,7 @@
   }
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  if (chromeos::ProfileHelper::IsSigninProfile(profile)) {
+  if (ash::ProfileHelper::IsSigninProfile(profile)) {
     return nullptr;
   }
 
diff --git a/chrome/browser/signin/chrome_device_id_helper.cc b/chrome/browser/signin/chrome_device_id_helper.cc
index 7b28246d2..d184122bc 100644
--- a/chrome/browser/signin/chrome_device_id_helper.cc
+++ b/chrome/browser/signin/chrome_device_id_helper.cc
@@ -34,7 +34,7 @@
     return std::string();
 
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   if (!user)
     return std::string();
 
@@ -62,7 +62,7 @@
     return;
 
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   if (!user)
     return;
   const AccountId account_id = user->GetAccountId();
diff --git a/chrome/browser/signin/chromeos_mirror_account_consistency_browsertest.cc b/chrome/browser/signin/chromeos_mirror_account_consistency_browsertest.cc
index b5b9b6a..f6b51aab 100644
--- a/chrome/browser/signin/chromeos_mirror_account_consistency_browsertest.cc
+++ b/chrome/browser/signin/chromeos_mirror_account_consistency_browsertest.cc
@@ -119,7 +119,7 @@
   user_manager::User* user = user_manager::UserManager::Get()->GetActiveUser();
   ASSERT_EQ(user, user_manager::UserManager::Get()->GetPrimaryUser());
   ASSERT_EQ(user, user_manager::UserManager::Get()->FindUser(account_id_));
-  Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+  Profile* profile = ash::ProfileHelper::Get()->GetProfileByUser(user);
 
   // Supervised flag uses `FindExtendedAccountInfoForAccountWithRefreshToken`,
   // so wait for tokens to be loaded.
@@ -157,7 +157,7 @@
   user_manager::User* user = user_manager::UserManager::Get()->GetActiveUser();
   ASSERT_EQ(user, user_manager::UserManager::Get()->GetPrimaryUser());
   ASSERT_EQ(user, user_manager::UserManager::Get()->FindUser(account_id_));
-  Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+  Profile* profile = ash::ProfileHelper::Get()->GetProfileByUser(user);
 
   // Supervised flag uses `FindExtendedAccountInfoForAccountWithRefreshToken`,
   // so wait for tokens to be loaded.
diff --git a/chrome/browser/signin/identity_manager_factory.cc b/chrome/browser/signin/identity_manager_factory.cc
index cac771b..3eccd53 100644
--- a/chrome/browser/signin/identity_manager_factory.cc
+++ b/chrome/browser/signin/identity_manager_factory.cc
@@ -135,8 +135,7 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   params.account_manager_facade =
       GetAccountManagerFacade(profile->GetPath().value());
-  params.is_regular_profile =
-      chromeos::ProfileHelper::IsRegularProfile(profile);
+  params.is_regular_profile = ash::ProfileHelper::IsRegularProfile(profile);
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
diff --git a/chrome/browser/signin/signin_ui_util.cc b/chrome/browser/signin/signin_ui_util.cc
index 18c541f..1bbdb265 100644
--- a/chrome/browser/signin/signin_ui_util.cc
+++ b/chrome/browser/signin/signin_ui_util.cc
@@ -188,7 +188,7 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
     // See https://crbug.com/994798 for details.
     user_manager::User* user =
-        chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+        ash::ProfileHelper::Get()->GetUserByProfile(profile);
     // |user| may be null in tests.
     if (user)
       user_display_name = user->GetDisplayEmail();
diff --git a/chrome/browser/ssl/https_first_mode_settings_tracker.cc b/chrome/browser/ssl/https_first_mode_settings_tracker.cc
index 898a79e..bc90d229 100644
--- a/chrome/browser/ssl/https_first_mode_settings_tracker.cc
+++ b/chrome/browser/ssl/https_first_mode_settings_tracker.cc
@@ -96,7 +96,7 @@
     return nullptr;
   }
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  if (chromeos::ProfileHelper::IsSigninProfile(profile)) {
+  if (ash::ProfileHelper::IsSigninProfile(profile)) {
     return nullptr;
   }
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ssl/ssl_browsertest.cc b/chrome/browser/ssl/ssl_browsertest.cc
index 6b345352b..4e83154 100644
--- a/chrome/browser/ssl/ssl_browsertest.cc
+++ b/chrome/browser/ssl/ssl_browsertest.cc
@@ -5869,8 +5869,7 @@
           kSecondProfileHash, false);
       // Set up the secondary profile.
       base::FilePath profile_dir = user_data_directory.Append(
-          chromeos::ProfileHelper::GetUserProfileDir(kSecondProfileHash)
-              .BaseName());
+          ash::ProfileHelper::GetUserProfileDir(kSecondProfileHash).BaseName());
       profile_2_ =
           g_browser_process->profile_manager()->GetProfile(profile_dir);
     }
diff --git a/chrome/browser/supervised_user/child_accounts/child_account_service.cc b/chrome/browser/supervised_user/child_accounts/child_account_service.cc
index 30a94f78..b49b1f3 100644
--- a/chrome/browser/supervised_user/child_accounts/child_account_service.cc
+++ b/chrome/browser/supervised_user/child_accounts/child_account_service.cc
@@ -354,10 +354,10 @@
 void ChildAccountService::PropagateChildStatusToUser(bool is_child) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile_);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile_);
   if (user && is_child != (user->GetType() == user_manager::USER_TYPE_CHILD))
     LOG(FATAL) << "User child flag has changed: " << is_child;
-  if (!user && chromeos::ProfileHelper::IsRegularProfile(profile_))
+  if (!user && ash::ProfileHelper::IsRegularProfile(profile_))
     LOG(DFATAL) << "User instance not found while setting child account flag.";
 #endif
 }
diff --git a/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc b/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc
index c653ab6..760f06f1 100644
--- a/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc
@@ -2,12 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <memory>
 #include <utility>
 
 #include "base/guid.h"
+#include "base/metrics/statistics_recorder.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/time/time.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/test/integration/bookmarks_helper.h"
@@ -23,6 +27,7 @@
 #include "components/sync/driver/sync_service_impl.h"
 #include "components/sync/engine/bookmark_update_preprocessing.h"
 #include "components/sync/engine/loopback_server/loopback_server_entity.h"
+#include "components/sync/engine/sync_engine_switches.h"
 #include "components/sync/protocol/bookmark_specifics.pb.h"
 #include "components/sync/protocol/entity_specifics.pb.h"
 #include "components/sync/protocol/sync_entity.pb.h"
@@ -155,6 +160,18 @@
   base::test::ScopedFeatureList features_override_;
 };
 
+class SingleClientBookmarksSyncTestWithEnabledThrottling : public SyncTest {
+ public:
+  SingleClientBookmarksSyncTestWithEnabledThrottling()
+      : SyncTest(SINGLE_CLIENT) {
+    features_override_.InitAndEnableFeature(
+        switches::kSyncExtensionTypesThrottling);
+  }
+
+ private:
+  base::test::ScopedFeatureList features_override_;
+};
+
 IN_PROC_BROWSER_TEST_F(SingleClientBookmarksSyncTest, Sanity) {
   ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
 
@@ -1716,4 +1733,79 @@
                 .value());
 }
 
+IN_PROC_BROWSER_TEST_F(SingleClientBookmarksSyncTestWithEnabledThrottling,
+                       DepleteQuota) {
+  ASSERT_TRUE(SetupClients());
+  // Add enough bookmarks to deplete quota in the initial cycle.
+  const BookmarkNode* folder = AddFolder(
+      kSingleProfileIndex, GetOtherNode(kSingleProfileIndex), 0, "Title");
+  // Default number of entities per message on the client are 25, thus the quota
+  // is fully depleted in 25*101 messages.
+  for (int i = 0; i < 2525; i++) {
+    AddURL(kSingleProfileIndex, folder, 0, base::StringPrintf("url %u", i),
+           GURL(base::StringPrintf("http://mail.google.com/%u", i)));
+  }
+
+  ASSERT_TRUE(SetupSync());
+  ASSERT_TRUE(BookmarkModelMatchesFakeServerChecker(
+                  kSingleProfileIndex, GetSyncService(kSingleProfileIndex),
+                  GetFakeServer())
+                  .Wait());
+
+  base::HistogramTester histogram_tester;
+
+  // Adding another entity does not trigger an update (long nudge delay).
+  std::string client_title = "Foo";
+  AddFolder(kSingleProfileIndex, GetOtherNode(kSingleProfileIndex), 0,
+            client_title);
+
+  // The quota is depleted for the last commit -- gets recorded in a histogram.
+  // Make sure the histogram gets propagated from the sync engine sequence.
+  base::StatisticsRecorder::ImportProvidedHistograms();
+  EXPECT_EQ(1, histogram_tester.GetBucketCount(
+                   "Sync.ModelTypeCommitWithDepletedQuota",
+                   ModelTypeHistogramValue(syncer::BOOKMARKS)));
+  // TODO(crbug.com/1145138): Add further tests that configure the long delay
+  // and thus test that it takes longer to commit this entity but it gets
+  // committed, eventually.
+}
+
+IN_PROC_BROWSER_TEST_F(SingleClientBookmarksSyncTestWithEnabledThrottling,
+                       DoNotDepleteQuota) {
+  ASSERT_TRUE(SetupClients());
+  // Add not enough bookmarks to deplete quota in the initial cycle.
+  const BookmarkNode* folder = AddFolder(
+      kSingleProfileIndex, GetOtherNode(kSingleProfileIndex), 0, "Title");
+  // Default number of entities per message on the client are 25, thus the quota
+  // would get almost depleted in 25*100 messages. Leave a bit of headroom for
+  // the entities getting distributed in more commit messages (as there are
+  // other data types to commit).
+  for (int i = 0; i < 2000; i++) {
+    AddURL(kSingleProfileIndex, folder, 0, base::StringPrintf("url %u", i),
+           GURL(base::StringPrintf("http://mail.google.com/%u", i)));
+  }
+
+  ASSERT_TRUE(SetupSync());
+  ASSERT_TRUE(BookmarkModelMatchesFakeServerChecker(
+                  kSingleProfileIndex, GetSyncService(kSingleProfileIndex),
+                  GetFakeServer())
+                  .Wait());
+
+  base::HistogramTester histogram_tester;
+
+  // Adding another entity does again trigger an update (normal nudge delay).
+  std::string client_title = "Foo";
+  AddFolder(kSingleProfileIndex, GetOtherNode(kSingleProfileIndex), 0,
+            client_title);
+  ASSERT_TRUE(BookmarkModelMatchesFakeServerChecker(
+                  kSingleProfileIndex, GetSyncService(kSingleProfileIndex),
+                  GetFakeServer())
+                  .Wait());
+
+  // Make sure the histogram gets propagated from the sync engine sequence.
+  base::StatisticsRecorder::ImportProvidedHistograms();
+  // There is no record in the depleted quota histogram.
+  histogram_tester.ExpectTotalCount("Sync.ModelTypeCommitWithDepletedQuota", 0);
+}
+
 }  // namespace
diff --git a/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc b/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc
index 85bbc19..30cd6cc 100644
--- a/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc
@@ -3,7 +3,10 @@
 // found in the LICENSE file.
 
 #include "base/bind.h"
+#include "base/metrics/statistics_recorder.h"
 #include "base/test/bind.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/browser/sync/test/integration/bookmarks_helper.h"
@@ -16,6 +19,7 @@
 #include "chrome/browser/sync/test/integration/sync_test.h"
 #include "chrome/browser/sync/test/integration/user_events_helper.h"
 #include "chrome/browser/sync/user_event_service_factory.h"
+#include "components/sync/engine/sync_engine_switches.h"
 #include "components/sync/protocol/user_event_specifics.pb.h"
 #include "components/sync_user_events/user_event_service.h"
 #include "content/public/test/browser_test.h"
@@ -46,6 +50,18 @@
   }
 };
 
+class SingleClientUserEventsSyncTestWithEnabledThrottling
+    : public SingleClientUserEventsSyncTest {
+ public:
+  SingleClientUserEventsSyncTestWithEnabledThrottling() {
+    features_override_.InitAndEnableFeature(
+        switches::kSyncExtensionTypesThrottling);
+  }
+
+ private:
+  base::test::ScopedFeatureList features_override_;
+};
+
 IN_PROC_BROWSER_TEST_F(SingleClientUserEventsSyncTest, Sanity) {
   ASSERT_TRUE(SetupSync());
   EXPECT_EQ(
@@ -230,4 +246,40 @@
   EXPECT_TRUE(ExpectUserEvents({}));
 }
 
+// This is an analogy to SingleClientBookmarksSyncTest.DepleteQuota, tested on
+// a datatype that has no quota restrictions.
+IN_PROC_BROWSER_TEST_F(SingleClientUserEventsSyncTestWithEnabledThrottling,
+                       NoQuotaApplied) {
+  ASSERT_TRUE(SetupSync());
+  // Add enough user events that would deplete quota in the initial cycle.
+  syncer::UserEventService* event_service =
+      browser_sync::UserEventServiceFactory::GetForProfile(GetProfile(0));
+
+  std::vector<UserEventSpecifics> expected_specifics;
+  base::Time zero;
+  // Default number of entities per message on the client are 25, thus the quota
+  // would be fully depleted in 25*101 messages.
+  for (int i = 0; i < 2525; i++) {
+    const UserEventSpecifics specifics =
+        CreateTestEvent(zero + base::Milliseconds(i));
+    event_service->RecordUserEvent(specifics);
+    expected_specifics.push_back(specifics);
+  }
+  EXPECT_TRUE(ExpectUserEvents(expected_specifics));
+
+  base::HistogramTester histogram_tester;
+
+  // Adding another entity again triggers sync immediately (as there's no
+  // quota).
+  const UserEventSpecifics specifics = CreateTestEvent(zero + base::Seconds(3));
+  event_service->RecordUserEvent(specifics);
+  expected_specifics.push_back(specifics);
+  EXPECT_TRUE(ExpectUserEvents(expected_specifics));
+
+  // Make sure the histogram gets propagated from the sync engine sequence.
+  base::StatisticsRecorder::ImportProvidedHistograms();
+  // There is no record in the depleted quota histogram.
+  histogram_tester.ExpectTotalCount("Sync.ModelTypeCommitWithDepletedQuota", 0);
+}
+
 }  // namespace
diff --git a/chrome/browser/sync/wifi_configuration_sync_service_factory.cc b/chrome/browser/sync/wifi_configuration_sync_service_factory.cc
index 8ca42da..4ab6408 100644
--- a/chrome/browser/sync/wifi_configuration_sync_service_factory.cc
+++ b/chrome/browser/sync/wifi_configuration_sync_service_factory.cc
@@ -40,7 +40,7 @@
     const Profile* profile) {
   // Run when signed in to a real account.  Skip during tests when network stack
   // has not been initialized.
-  return profile && chromeos::ProfileHelper::IsRegularProfile(profile) &&
+  return profile && ash::ProfileHelper::IsRegularProfile(profile) &&
          !profile->IsOffTheRecord() &&
          chromeos::NetworkHandler::IsInitialized();
 }
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 5f02ed8..d3b042a7 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -2711,8 +2711,8 @@
       "webui/chromeos/video_source.h",
       "webui/chromeos/vm/vm_ui.cc",
       "webui/chromeos/vm/vm_ui.h",
-      "webui/extensions/chromeos/kiosk_apps_handler.cc",
-      "webui/extensions/chromeos/kiosk_apps_handler.h",
+      "webui/extensions/ash/kiosk_apps_handler.cc",
+      "webui/extensions/ash/kiosk_apps_handler.h",
       "webui/help/help_utils_chromeos.cc",
       "webui/help/help_utils_chromeos.h",
       "webui/help/version_updater_chromeos.cc",
diff --git a/chrome/browser/ui/app_list/app_context_menu_unittest.cc b/chrome/browser/ui/app_list/app_context_menu_unittest.cc
index a3cbf205d..cb286fa 100644
--- a/chrome/browser/ui/app_list/app_context_menu_unittest.cc
+++ b/chrome/browser/ui/app_list/app_context_menu_unittest.cc
@@ -698,7 +698,7 @@
     // Creates profile().
     AppContextMenuTest::SetUp();
 
-    ASSERT_TRUE(chromeos::ProfileHelper::Get()->IsPrimaryProfile(profile()));
+    ASSERT_TRUE(ash::ProfileHelper::Get()->IsPrimaryProfile(profile()));
   }
 
  private:
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service_factory.cc b/chrome/browser/ui/app_list/app_list_syncable_service_factory.cc
index 1045927..f7316a98 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service_factory.cc
+++ b/chrome/browser/ui/app_list/app_list_syncable_service_factory.cc
@@ -40,7 +40,7 @@
 std::unique_ptr<KeyedService> AppListSyncableServiceFactory::BuildInstanceFor(
     content::BrowserContext* browser_context) {
   Profile* profile = static_cast<Profile*>(browser_context);
-  if (!chromeos::ProfileHelper::IsRegularProfile(profile)) {
+  if (!ash::ProfileHelper::IsRegularProfile(profile)) {
     return nullptr;
   }
   VLOG(1) << "BuildInstanceFor: " << profile->GetDebugName()
@@ -95,7 +95,7 @@
     return nullptr;
 
   // No service for sign in profile.
-  if (chromeos::ProfileHelper::IsSigninProfile(profile))
+  if (ash::ProfileHelper::IsSigninProfile(profile))
     return nullptr;
 
   // Use profile as-is for guest session.
diff --git a/chrome/browser/ui/app_list/arc/arc_app_test.cc b/chrome/browser/ui/app_list/arc/arc_app_test.cc
index fb92a96a..067b498 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_test.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_test.cc
@@ -92,8 +92,7 @@
   // If for any reason the garbage collector kicks in while we are waiting for
   // an icon, have the user-to-profile mapping ready to avoid using the real
   // profile manager (which is null).
-  chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(user,
-                                                                    profile_);
+  ash::ProfileHelper::Get()->SetUserToProfileMappingForTesting(user, profile_);
 
   // A valid |arc_app_list_prefs_| is needed for the ARC bridge service and the
   // ARC auth service.
diff --git a/chrome/browser/ui/app_list/chrome_app_list_model_updater_browsertest.cc b/chrome/browser/ui/app_list/chrome_app_list_model_updater_browsertest.cc
index 81f6d9c5..3ac7d57 100644
--- a/chrome/browser/ui/app_list/chrome_app_list_model_updater_browsertest.cc
+++ b/chrome/browser/ui/app_list/chrome_app_list_model_updater_browsertest.cc
@@ -56,9 +56,9 @@
     const std::string& email =
         login_mixin_.users()[0].account_id.GetUserEmail();
     const std::string user_id_hash =
-        chromeos::ProfileHelper::GetUserIdHashByUserIdForTesting(email);
+        ash::ProfileHelper::GetUserIdHashByUserIdForTesting(email);
     const base::FilePath user_profile_path = user_data_dir.Append(
-        chromeos::ProfileHelper::GetUserProfileDir(user_id_hash));
+        ash::ProfileHelper::GetUserProfileDir(user_id_hash));
     base::CreateDirectory(user_profile_path);
 
     base::FilePath src_dir;
diff --git a/chrome/browser/ui/app_list/search/files/zero_state_file_provider.cc b/chrome/browser/ui/app_list/search/files/zero_state_file_provider.cc
index fe0a3d8..d26e10e 100644
--- a/chrome/browser/ui/app_list/search/files/zero_state_file_provider.cc
+++ b/chrome/browser/ui/app_list/search/files/zero_state_file_provider.cc
@@ -97,7 +97,7 @@
     files_ranker_ = std::make_unique<RecurrenceRanker>(
         "ZeroStateLocalFiles",
         profile->GetPath().AppendASCII("zero_state_local_files.pb"), config,
-        chromeos::ProfileHelper::IsEphemeralUserProfile(profile));
+        ash::ProfileHelper::IsEphemeralUserProfile(profile));
   }
 }
 
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/chip_ranker.cc b/chrome/browser/ui/app_list/search/search_result_ranker/chip_ranker.cc
index 262ec9ae..8bc685d 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/chip_ranker.cc
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/chip_ranker.cc
@@ -95,7 +95,7 @@
 
   type_ranker_ = std::make_unique<RecurrenceRanker>(
       "", profile_->GetPath().AppendASCII("suggested_files_ranker.pb"), config,
-      chromeos::ProfileHelper::IsEphemeralUserProfile(profile_));
+      ash::ProfileHelper::IsEphemeralUserProfile(profile_));
 }
 
 ChipRanker::~ChipRanker() = default;
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.cc b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.cc
index acda2f7..289a4ed 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.cc
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.cc
@@ -184,7 +184,7 @@
                       ranker->profile_->GetPath().AppendASCII(
                           "zero_state_group_ranker.pb"),
                       parsed_config ? parsed_config.value() : default_config,
-                      chromeos::ProfileHelper::IsEphemeralUserProfile(
+                      ash::ProfileHelper::IsEphemeralUserProfile(
                           ranker->profile_));
             },
             base::Unretained(this), default_config));
@@ -204,7 +204,7 @@
 
   app_ranker_ = std::make_unique<RecurrenceRanker>(
       "AppRanker", profile_->GetPath().AppendASCII("app_ranker.pb"), config,
-      chromeos::ProfileHelper::IsEphemeralUserProfile(profile_));
+      ash::ProfileHelper::IsEphemeralUserProfile(profile_));
 }
 
 void SearchResultRanker::FetchRankings(const std::u16string& query) {
diff --git a/chrome/browser/ui/ash/ambient/ambient_client_impl.cc b/chrome/browser/ui/ash/ambient/ambient_client_impl.cc
index 43570cb..d7aa2e10 100644
--- a/chrome/browser/ui/ash/ambient/ambient_client_impl.cc
+++ b/chrome/browser/ui/ash/ambient/ambient_client_impl.cc
@@ -75,7 +75,7 @@
 Profile* GetProfileForActiveUser() {
   const user_manager::User* const active_user = GetActiveUser();
   DCHECK(active_user);
-  return chromeos::ProfileHelper::Get()->GetProfileByUser(active_user);
+  return ash::ProfileHelper::Get()->GetProfileByUser(active_user);
 }
 
 bool IsPrimaryUser() {
diff --git a/chrome/browser/ui/ash/assistant/assistant_context_util.cc b/chrome/browser/ui/ash/assistant/assistant_context_util.cc
index df70bc8f..63182526 100644
--- a/chrome/browser/ui/ash/assistant/assistant_context_util.cc
+++ b/chrome/browser/ui/ash/assistant/assistant_context_util.cc
@@ -78,7 +78,7 @@
 
   // Only returns context from the profile with assistant, which is primary
   // profile.
-  if (!chromeos::ProfileHelper::IsPrimaryProfile(browser->profile())) {
+  if (!ash::ProfileHelper::IsPrimaryProfile(browser->profile())) {
     std::move(callback).Run(nullptr, nullptr);
     return;
   }
diff --git a/chrome/browser/ui/ash/assistant/assistant_state_client.cc b/chrome/browser/ui/ash/assistant/assistant_state_client.cc
index ca5a283..acfadde 100644
--- a/chrome/browser/ui/ash/assistant/assistant_state_client.cc
+++ b/chrome/browser/ui/ash/assistant/assistant_state_client.cc
@@ -65,7 +65,7 @@
 }
 
 void AssistantStateClient::SetProfileByUser(const user_manager::User* user) {
-  SetProfile(chromeos::ProfileHelper::Get()->GetProfileByUser(user));
+  SetProfile(ash::ProfileHelper::Get()->GetProfileByUser(user));
 }
 
 void AssistantStateClient::SetProfile(Profile* profile) {
diff --git a/chrome/browser/ui/ash/assistant/device_actions.cc b/chrome/browser/ui/ash/assistant/device_actions.cc
index bf0d1f4..bf3a42e 100644
--- a/chrome/browser/ui/ash/assistant/device_actions.cc
+++ b/chrome/browser/ui/ash/assistant/device_actions.cc
@@ -123,7 +123,7 @@
 void DeviceActions::SetBluetoothEnabled(bool enabled) {
   const user_manager::User* const user =
       user_manager::UserManager::Get()->GetActiveUser();
-  Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+  Profile* profile = ash::ProfileHelper::Get()->GetProfileByUser(user);
   DCHECK(profile);
   // Simply toggle the user pref, which is being observed by ash's bluetooth
   // power controller.
@@ -162,7 +162,7 @@
 void DeviceActions::SetNightLightEnabled(bool enabled) {
   const user_manager::User* const user =
       user_manager::UserManager::Get()->GetActiveUser();
-  Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+  Profile* profile = ash::ProfileHelper::Get()->GetProfileByUser(user);
   DCHECK(profile);
   // Simply toggle the user pref, which is being observed by ash's night
   // light controller.
@@ -172,7 +172,7 @@
 void DeviceActions::SetSwitchAccessEnabled(bool enabled) {
   const user_manager::User* const user =
       user_manager::UserManager::Get()->GetActiveUser();
-  Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+  Profile* profile = ash::ProfileHelper::Get()->GetProfileByUser(user);
   DCHECK(profile);
   profile->GetPrefs()->SetBoolean(ash::prefs::kAccessibilitySwitchAccessEnabled,
                                   enabled);
diff --git a/chrome/browser/ui/ash/calendar/calendar_keyed_service_factory.cc b/chrome/browser/ui/ash/calendar/calendar_keyed_service_factory.cc
index 5859b63..bcba7089 100644
--- a/chrome/browser/ui/ash/calendar/calendar_keyed_service_factory.cc
+++ b/chrome/browser/ui/ash/calendar/calendar_keyed_service_factory.cc
@@ -36,8 +36,7 @@
 KeyedService* CalendarKeyedServiceFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
   Profile* const profile = Profile::FromBrowserContext(context);
-  user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+  user_manager::User* user = ProfileHelper::Get()->GetUserByProfile(profile);
   if (!user)
     return nullptr;
 
diff --git a/chrome/browser/ui/ash/capture_mode/capture_mode_browsertest.cc b/chrome/browser/ui/ash/capture_mode/capture_mode_browsertest.cc
index 1240131..c99e658 100644
--- a/chrome/browser/ui/ash/capture_mode/capture_mode_browsertest.cc
+++ b/chrome/browser/ui/ash/capture_mode/capture_mode_browsertest.cc
@@ -415,15 +415,11 @@
   loop.Run();
 }
 
-class AdvancedSettingsCaptureModeBrowserTest
-    : public extensions::ExtensionBrowserTest {
+class CaptureModeSettingsBrowserTest : public extensions::ExtensionBrowserTest {
  public:
-  AdvancedSettingsCaptureModeBrowserTest() {
-    scoped_feature_list_.InitAndEnableFeature(
-        ash::features::kImprovedScreenCaptureSettings);
-  }
+  CaptureModeSettingsBrowserTest() {}
 
-  ~AdvancedSettingsCaptureModeBrowserTest() override = default;
+  ~CaptureModeSettingsBrowserTest() override = default;
 
   // extensions::ExtensionBrowserTest:
   void SetUpOnMainThread() override {
@@ -438,7 +434,7 @@
 
 // Tests that the capture mode folder selection dialog window gets parented
 // correctly when a browser window is available.
-IN_PROC_BROWSER_TEST_F(AdvancedSettingsCaptureModeBrowserTest,
+IN_PROC_BROWSER_TEST_F(CaptureModeSettingsBrowserTest,
                        FolderSelectionDialogParentedCorrectly) {
   ASSERT_TRUE(browser());
   ash::CaptureModeTestApi test_api;
diff --git a/chrome/browser/ui/ash/cast_config_controller_media_router.cc b/chrome/browser/ui/ash/cast_config_controller_media_router.cc
index a50278f..a2f9cd9 100644
--- a/chrome/browser/ui/ash/cast_config_controller_media_router.cc
+++ b/chrome/browser/ui/ash/cast_config_controller_media_router.cc
@@ -38,7 +38,7 @@
   if (!user)
     return nullptr;
 
-  return chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+  return ash::ProfileHelper::Get()->GetProfileByUser(user);
 }
 
 // Returns the MediaRouter instance for the current primary profile, if there is
diff --git a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
index 45d7eda..08b24f0 100644
--- a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
+++ b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
@@ -363,8 +363,8 @@
   // session_manager::SessionManagerObserver:
   void OnUserProfileLoaded(const AccountId& account_id) override {
     Profile* profile =
-        chromeos::ProfileHelper::Get()->GetProfileByAccountId(account_id);
-    if (chromeos::ProfileHelper::IsRegularProfile(profile) &&
+        ash::ProfileHelper::Get()->GetProfileByAccountId(account_id);
+    if (ash::ProfileHelper::IsRegularProfile(profile) &&
         !profile->IsGuestSession()) {
       // Start the error notifier services to show auth/sync notifications.
       ash::SigninErrorNotifierFactory::GetForProfile(profile);
diff --git a/chrome/browser/ui/ash/chrome_new_window_client.cc b/chrome/browser/ui/ash/chrome_new_window_client.cc
index bb74e62..7c1d1245 100644
--- a/chrome/browser/ui/ash/chrome_new_window_client.cc
+++ b/chrome/browser/ui/ash/chrome_new_window_client.cc
@@ -620,7 +620,7 @@
 
   // |profile| may be null if sign-in has happened but the profile isn't loaded
   // yet.
-  Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+  Profile* profile = ash::ProfileHelper::Get()->GetProfileByUser(user);
   if (!profile)
     return;
 
@@ -787,7 +787,7 @@
 
   // |profile| may be null if sign-in has happened but the profile isn't loaded
   // yet.
-  Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+  Profile* profile = ash::ProfileHelper::Get()->GetProfileByUser(user);
   if (!profile)
     return;
 
diff --git a/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc b/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc
index 8d164af..8d9b2d3 100644
--- a/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc
+++ b/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc
@@ -47,7 +47,7 @@
 constexpr char kTestUser2GaiaId[] = "2222222222";
 
 void CreateAndStartUserSession(const AccountId& account_id) {
-  using chromeos::ProfileHelper;
+  using ::ash::ProfileHelper;
   using session_manager::SessionManager;
 
   user_manager::known_user::SetProfileRequiresPolicy(
diff --git a/chrome/browser/ui/ash/clipboard_history_browsertest.cc b/chrome/browser/ui/ash/clipboard_history_browsertest.cc
index f3bb4e2..defabd4 100644
--- a/chrome/browser/ui/ash/clipboard_history_browsertest.cc
+++ b/chrome/browser/ui/ash/clipboard_history_browsertest.cc
@@ -739,7 +739,7 @@
 
   // Create a browser and cache its active web contents.
   auto* browser = CreateBrowser(
-      chromeos::ProfileHelper::Get()->GetProfileByAccountId(account_id1_));
+      ash::ProfileHelper::Get()->GetProfileByAccountId(account_id1_));
   auto* web_contents = browser->tab_strip_model()->GetActiveWebContents();
   ASSERT_TRUE(web_contents);
 
diff --git a/chrome/browser/ui/ash/desks_templates/desks_templates_client_browsertest.cc b/chrome/browser/ui/ash/desks_templates/desks_templates_client_browsertest.cc
index d327344..56f219e9 100644
--- a/chrome/browser/ui/ash/desks_templates/desks_templates_client_browsertest.cc
+++ b/chrome/browser/ui/ash/desks_templates/desks_templates_client_browsertest.cc
@@ -172,6 +172,23 @@
   event_generator.ClickLeftButton();
 }
 
+void ClickSaveDeskAsTemplateButton() {
+  views::Button* save_desk_as_template_button =
+      ash::GetSaveDeskAsTemplateButton();
+  DCHECK(save_desk_as_template_button);
+  ClickButton(save_desk_as_template_button);
+  ash::WaitForDesksTemplatesUI();
+}
+
+void ClickFirstTemplateItem() {
+  views::Button* template_item = ash::GetTemplateItemButton(/*index=*/0);
+  DCHECK(template_item);
+  ClickButton(template_item);
+
+  // We need to wait for the template to be fetched from the model.
+  ash::WaitForDesksTemplatesUI();
+}
+
 class MockDesksTemplatesAppLaunchHandler
     : public DesksTemplatesAppLaunchHandler {
  public:
@@ -975,7 +992,43 @@
   EXPECT_FALSE(iter != app_id_to_launch_list.end());
 }
 
+// Tests that captured desk templates can be recalled as a JSON string.
+IN_PROC_BROWSER_TEST_F(DesksTemplatesClientTest, GetDeskTemplateJson) {
+  // Test that Singleton was properly initialized.
+  ASSERT_TRUE(DesksTemplatesClient::Get());
+
+  // Change |browser|'s bounds.
+  const gfx::Rect browser_bounds = gfx::Rect(0, 0, 800, 200);
+  aura::Window* window = browser()->window()->GetNativeWindow();
+  window->SetBounds(browser_bounds);
+  // Make window visible on all desks.
+  window->SetProperty(aura::client::kWindowWorkspaceKey,
+                      aura::client::kWindowWorkspaceVisibleOnAllWorkspaces);
+
+  // Create the settings app, which is a system web app.
+  web_app::AppId settings_app_id =
+      CreateSettingsSystemWebApp(browser()->profile());
+
+  // Change the Settings app's bounds too.
+  const gfx::Rect settings_app_bounds = gfx::Rect(100, 100, 800, 300);
+  aura::Window* settings_window = FindBrowserWindow(kSettingsWindowId);
+  ASSERT_TRUE(settings_window);
+  settings_window->SetBounds(settings_app_bounds);
+
+  std::unique_ptr<ash::DeskTemplate> desk_template =
+      CaptureActiveDeskAndSaveTemplate();
+
+  std::string template_json = GetTemplateJson(
+      desk_template->uuid().AsLowercaseString(), browser()->profile());
+
+  // content of the conversion is tested in:
+  // components/desks_storage/core/desk_template_conversion_unittests.cc in this
+  // case we're simply interested in whether or not we got content back.
+  ASSERT_TRUE(!template_json.empty());
+}
+
 // Tests that basic operations using the native UI work as expected.
+// TODO(crbug.com/1286515): Remove the NativeUI prefix from these tests.
 IN_PROC_BROWSER_TEST_F(DesksTemplatesClientTest, NativeUIBasic) {
   auto* desk_model = DesksTemplatesClient::Get()->GetDeskModel();
   ASSERT_EQ(0, desk_model->GetEntryCount());
@@ -1037,19 +1090,10 @@
   // Enter overview and save the current desk as a template.
   ash::ToggleOverview();
   ash::WaitForOverviewEnterAnimation();
-  views::Button* save_desk_as_template_button =
-      ash::GetSaveDeskAsTemplateButton();
-  ASSERT_TRUE(save_desk_as_template_button);
-  ClickButton(save_desk_as_template_button);
 
-  ash::WaitForDesksTemplatesUI();
+  ClickSaveDeskAsTemplateButton();
 
-  views::Button* template_item = ash::GetTemplateItemButton(/*index=*/0);
-  ASSERT_TRUE(template_item);
-  ClickButton(template_item);
-
-  // We need to wait for the template to be fetched from the model.
-  ash::WaitForDesksTemplatesUI();
+  ClickFirstTemplateItem();
 
   // Wait for the tabs to load.
   content::RunAllTasksUntilIdle();
@@ -1088,10 +1132,8 @@
   // Enter overview and save the current desk as a template.
   ash::ToggleOverview();
   ash::WaitForOverviewEnterAnimation();
-  views::Button* save_desk_as_template_button =
-      ash::GetSaveDeskAsTemplateButton();
-  ASSERT_TRUE(save_desk_as_template_button);
-  ClickButton(save_desk_as_template_button);
+
+  ClickSaveDeskAsTemplateButton();
 
   // Exit overview and close the settings window. We'll need to verify if it
   // reopens later.
@@ -1107,18 +1149,14 @@
   // template.
   ash::ToggleOverview();
   ash::WaitForOverviewEnterAnimation();
+
   views::Button* zero_state_templates_button =
       ash::GetZeroStateDesksTemplatesButton();
   ASSERT_TRUE(zero_state_templates_button);
   ClickButton(zero_state_templates_button);
-
   ash::WaitForDesksTemplatesUI();
-  views::Button* template_item = ash::GetTemplateItemButton(/*index=*/0);
-  ASSERT_TRUE(template_item);
-  ClickButton(template_item);
 
-  // We need to wait for the template to be fetched from the model.
-  ash::WaitForDesksTemplatesUI();
+  ClickFirstTemplateItem();
 
   for (auto* browser : *BrowserList::GetInstance()) {
     aura::Window* window = browser->window()->GetNativeWindow();
@@ -1157,10 +1195,8 @@
   // Enter overview and save the current desk as a template.
   ash::ToggleOverview();
   ash::WaitForOverviewEnterAnimation();
-  views::Button* save_desk_as_template_button =
-      ash::GetSaveDeskAsTemplateButton();
-  ASSERT_TRUE(save_desk_as_template_button);
-  ClickButton(save_desk_as_template_button);
+
+  ClickSaveDeskAsTemplateButton();
 
   // Exit overview and move the settings window to a new place and stack it on
   // top so that we can later verify that it has been placed and stacked
@@ -1178,11 +1214,9 @@
       ash::GetZeroStateDesksTemplatesButton();
   ASSERT_TRUE(zero_state_templates_button);
   ClickButton(zero_state_templates_button);
-
   ash::WaitForDesksTemplatesUI();
-  views::Button* template_item = ash::GetTemplateItemButton(/*index=*/0);
-  ASSERT_TRUE(template_item);
-  ClickButton(template_item);
+
+  ClickFirstTemplateItem();
 
   // Wait for the tabs to load.
   content::RunAllTasksUntilIdle();
@@ -1271,11 +1305,8 @@
   // Enter overview and save the current desk as a template.
   ash::ToggleOverview();
   ash::WaitForOverviewEnterAnimation();
-  views::Button* save_desk_as_template_button =
-      ash::GetSaveDeskAsTemplateButton();
-  ASSERT_TRUE(save_desk_as_template_button);
-  ClickButton(save_desk_as_template_button);
-  ash::WaitForDesksTemplatesUI();
+
+  ClickSaveDeskAsTemplateButton();
   ASSERT_EQ(1, desk_model->GetEntryCount());
 
   // Exit overview and close the Arc window. We'll need to verify if it
@@ -1293,13 +1324,10 @@
       ash::GetZeroStateDesksTemplatesButton();
   ASSERT_TRUE(zero_state_templates_button);
   ClickButton(zero_state_templates_button);
-
   ash::WaitForDesksTemplatesUI();
-  views::Button* template_item = ash::GetTemplateItemButton(/*index=*/0);
-  ASSERT_TRUE(template_item);
-  ClickButton(template_item);
 
-  ash::WaitForDesksTemplatesUI();
+  ClickFirstTemplateItem();
+
   ash::ToggleOverview();
   ash::WaitForOverviewExitAnimation();
 
@@ -1346,7 +1374,7 @@
 
     LoginUser(account_id1_);
     ::full_restore::SetActiveProfilePath(
-        chromeos::ProfileHelper::Get()
+        ash::ProfileHelper::Get()
             ->GetProfileByAccountId(account_id1_)
             ->GetPath());
   }
@@ -1359,8 +1387,7 @@
 };
 
 IN_PROC_BROWSER_TEST_F(DesksTemplatesClientMultiProfileTest, MultiProfileTest) {
-  CreateBrowser(
-      chromeos::ProfileHelper::Get()->GetProfileByAccountId(account_id1_));
+  CreateBrowser(ash::ProfileHelper::Get()->GetProfileByAccountId(account_id1_));
   // Capture the active desk, which contains the browser windows.
   std::unique_ptr<ash::DeskTemplate> desk_template =
       CaptureActiveDeskAndSaveTemplate();
@@ -1389,38 +1416,3 @@
   AddUser(account_id2_);
   EXPECT_EQ(get_templates_size(), 0);
 }
-
-// Tests that captured desk templates can be recalled as a JSON string.
-IN_PROC_BROWSER_TEST_F(DesksTemplatesClientTest, GetDeskTemplateJson) {
-  // Test that Singleton was properly initialized.
-  ASSERT_TRUE(DesksTemplatesClient::Get());
-
-  // Change |browser|'s bounds.
-  const gfx::Rect browser_bounds = gfx::Rect(0, 0, 800, 200);
-  aura::Window* window = browser()->window()->GetNativeWindow();
-  window->SetBounds(browser_bounds);
-  // Make window visible on all desks.
-  window->SetProperty(aura::client::kWindowWorkspaceKey,
-                      aura::client::kWindowWorkspaceVisibleOnAllWorkspaces);
-
-  // Create the settings app, which is a system web app.
-  web_app::AppId settings_app_id =
-      CreateSettingsSystemWebApp(browser()->profile());
-
-  // Change the Settings app's bounds too.
-  const gfx::Rect settings_app_bounds = gfx::Rect(100, 100, 800, 300);
-  aura::Window* settings_window = FindBrowserWindow(kSettingsWindowId);
-  ASSERT_TRUE(settings_window);
-  settings_window->SetBounds(settings_app_bounds);
-
-  std::unique_ptr<ash::DeskTemplate> desk_template =
-      CaptureActiveDeskAndSaveTemplate();
-
-  std::string template_json = GetTemplateJson(
-      desk_template->uuid().AsLowercaseString(), browser()->profile());
-
-  // content of the conversion is tested in:
-  // components/desks_storage/core/desk_template_conversion_unittests.cc in this
-  // case we're simply interested in whether or not we got content back.
-  ASSERT_TRUE(!template_json.empty());
-}
diff --git a/chrome/browser/ui/ash/fwupd_download_client_impl.cc b/chrome/browser/ui/ash/fwupd_download_client_impl.cc
index b19756c..1edb13287 100644
--- a/chrome/browser/ui/ash/fwupd_download_client_impl.cc
+++ b/chrome/browser/ui/ash/fwupd_download_client_impl.cc
@@ -18,8 +18,7 @@
 FwupdDownloadClientImpl::GetURLLoaderFactory() {
   user_manager::User* active_user =
       user_manager::UserManager::Get()->GetActiveUser();
-  Profile* profile =
-      chromeos::ProfileHelper::Get()->GetProfileByUser(active_user);
+  Profile* profile = ProfileHelper::Get()->GetProfileByUser(active_user);
   DCHECK(profile);
 
   return profile->GetURLLoaderFactory();
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_browsertest.cc b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_browsertest.cc
index 1b25a8c..a8d3bab 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_browsertest.cc
+++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_browsertest.cc
@@ -354,9 +354,8 @@
   drive::DriveIntegrationService* CreateDriveIntegrationService(
       Profile* profile) {
     // Ignore signin and lock screen apps profile.
-    if (profile->GetPath() == chromeos::ProfileHelper::GetSigninProfileDir() ||
-        profile->GetPath() ==
-            chromeos::ProfileHelper::GetLockScreenAppProfilePath()) {
+    if (profile->GetPath() == ProfileHelper::GetSigninProfileDir() ||
+        profile->GetPath() == ProfileHelper::GetLockScreenAppProfilePath()) {
       return nullptr;
     }
 
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_factory.cc b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_factory.cc
index aadd907..87b515c 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_factory.cc
+++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_factory.cc
@@ -90,8 +90,7 @@
   Profile* const profile = Profile::FromBrowserContext(context);
   DCHECK_EQ(profile->IsGuestSession(), profile->IsOffTheRecord());
 
-  user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+  user_manager::User* user = ProfileHelper::Get()->GetUserByProfile(profile);
   if (!user)
     return nullptr;
 
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_persistence_delegate.cc b/chrome/browser/ui/ash/holding_space/holding_space_persistence_delegate.cc
index b21356e4c..7a84e80 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_persistence_delegate.cc
+++ b/chrome/browser/ui/ash/holding_space/holding_space_persistence_delegate.cc
@@ -25,7 +25,7 @@
 bool ShouldIgnoreItem(Profile* profile, const HoldingSpaceItem* item) {
   return file_manager::util::GetAndroidFilesPath().IsParent(
              item->file_path()) &&
-         !chromeos::ProfileHelper::IsPrimaryProfile(profile);
+         !ProfileHelper::IsPrimaryProfile(profile);
 }
 
 }  // namespace
diff --git a/chrome/browser/ui/ash/image_downloader_impl.cc b/chrome/browser/ui/ash/image_downloader_impl.cc
index 1a2537a..1a02016 100644
--- a/chrome/browser/ui/ash/image_downloader_impl.cc
+++ b/chrome/browser/ui/ash/image_downloader_impl.cc
@@ -22,7 +22,7 @@
       user_manager::UserManager::Get()->GetActiveUser();
   DCHECK(active_user);
 
-  return chromeos::ProfileHelper::Get()->GetProfileByUser(active_user);
+  return ash::ProfileHelper::Get()->GetProfileByUser(active_user);
 }
 
 // DownloadTask ----------------------------------------------------------------
diff --git a/chrome/browser/ui/ash/in_session_auth_dialog_client_unittest.cc b/chrome/browser/ui/ash/in_session_auth_dialog_client_unittest.cc
index e79ba95..7784652 100644
--- a/chrome/browser/ui/ash/in_session_auth_dialog_client_unittest.cc
+++ b/chrome/browser/ui/ash/in_session_auth_dialog_client_unittest.cc
@@ -65,8 +65,7 @@
     auto* user = user_manager::UserManager::Get()->GetActiveUser();
     ASSERT_TRUE(user);
     // Set the profile mapping to avoid crashing in |OnPasswordAuthSuccess|.
-    chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(user,
-                                                                      nullptr);
+    ash::ProfileHelper::Get()->SetUserToProfileMappingForTesting(user, nullptr);
   }
 
   void SetExpectedContext(const UserContext& expected_user_context) {
diff --git a/chrome/browser/ui/ash/login_screen_client_impl.cc b/chrome/browser/ui/ash/login_screen_client_impl.cc
index 8492eda..563c04f 100644
--- a/chrome/browser/ui/ash/login_screen_client_impl.cc
+++ b/chrome/browser/ui/ash/login_screen_client_impl.cc
@@ -373,7 +373,7 @@
   } else {
     const user_manager::User* user =
         user_manager::UserManager::Get()->FindUser(prefilled_account);
-    Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+    Profile* profile = ash::ProfileHelper::Get()->GetProfileByUser(user);
     DCHECK(session_manager::SessionManager::Get()->IsScreenLocked());
     auto* password_sync_manager =
         ash::InSessionPasswordSyncManagerFactory::GetForProfile(profile);
diff --git a/chrome/browser/ui/ash/media_client_impl.cc b/chrome/browser/ui/ash/media_client_impl.cc
index ea9448a..b31a952 100644
--- a/chrome/browser/ui/ash/media_client_impl.cc
+++ b/chrome/browser/ui/ash/media_client_impl.cc
@@ -319,7 +319,7 @@
   auto* manager = user_manager::UserManager::Get();
   for (user_manager::User* user : manager->GetLRULoggedInUsers()) {
     capture_states[user->GetAccountId()] = GetMediaCaptureStateOfAllWebContents(
-        chromeos::ProfileHelper::Get()->GetProfileByUser(user));
+        ash::ProfileHelper::Get()->GetProfileByUser(user));
   }
 
   const user_manager::User* primary_user = manager->GetPrimaryUser();
diff --git a/chrome/browser/ui/ash/microphone_mute_notification_delegate_impl.cc b/chrome/browser/ui/ash/microphone_mute_notification_delegate_impl.cc
index fb17b4df..650009fc 100644
--- a/chrome/browser/ui/ash/microphone_mute_notification_delegate_impl.cc
+++ b/chrome/browser/ui/ash/microphone_mute_notification_delegate_impl.cc
@@ -40,8 +40,7 @@
     return nullptr;
 
   auto account_id = active_user->GetAccountId();
-  Profile* profile =
-      chromeos::ProfileHelper::Get()->GetProfileByUser(active_user);
+  Profile* profile = ash::ProfileHelper::Get()->GetProfileByUser(active_user);
   apps::AppServiceProxy* proxy =
       apps::AppServiceProxyFactory::GetForProfile(profile);
   return &proxy->AppRegistryCache();
diff --git a/chrome/browser/ui/ash/multi_user/multi_profile_support_unittest.cc b/chrome/browser/ui/ash/multi_user/multi_profile_support_unittest.cc
index 97ea147..0560541 100644
--- a/chrome/browser/ui/ash/multi_user/multi_profile_support_unittest.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_profile_support_unittest.cc
@@ -197,8 +197,7 @@
     fake_user_manager_->LoginUser(account_id);
     TestingProfile* profile =
         profile_manager()->CreateTestingProfile(account_id.GetUserEmail());
-    chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(user,
-                                                                      profile);
+    ProfileHelper::Get()->SetUserToProfileMappingForTesting(user, profile);
     return user;
   }
 
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_util.cc b/chrome/browser/ui/ash/multi_user/multi_user_util.cc
index 0160e3ec..f1b2fd99 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_util.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_util.cc
@@ -17,9 +17,8 @@
 AccountId GetAccountIdFromProfile(const Profile* profile) {
   // This will guarantee an nonempty AccountId be returned if a valid profile is
   // provided.
-  const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(
-          profile->GetOriginalProfile());
+  const user_manager::User* user = ash::ProfileHelper::Get()->GetUserByProfile(
+      profile->GetOriginalProfile());
   return user ? user->GetAccountId() : EmptyAccountId();
 }
 
@@ -33,8 +32,7 @@
 Profile* GetProfileFromAccountId(const AccountId& account_id) {
   const user_manager::User* user =
       user_manager::UserManager::Get()->FindUser(account_id);
-  return user ? chromeos::ProfileHelper::Get()->GetProfileByUser(user)
-              : nullptr;
+  return user ? ash::ProfileHelper::Get()->GetProfileByUser(user) : nullptr;
 }
 
 Profile* GetProfileFromWindow(aura::Window* window) {
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_util_chromeos_unittest.cc b/chrome/browser/ui/ash/multi_user/multi_user_util_chromeos_unittest.cc
index 3bc969f8..1bef9ca 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_util_chromeos_unittest.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_util_chromeos_unittest.cc
@@ -66,8 +66,7 @@
         multi_user_util::GetAccountIdFromEmail(account_info.email));
     fake_user_manager_->UserLoggedIn(
         multi_user_util::GetAccountIdFromEmail(account_info.email),
-        chromeos::ProfileHelper::GetUserIdHashByUserIdForTesting(
-            account_info.email),
+        ProfileHelper::GetUserIdHashByUserIdForTesting(account_info.email),
         false /* browser_restart */, false /* is_child */);
 
     return account_info.account_id;
diff --git a/chrome/browser/ui/ash/session_controller_client_impl.cc b/chrome/browser/ui/ash/session_controller_client_impl.cc
index d42b3c61..fda3cb6 100644
--- a/chrome/browser/ui/ash/session_controller_client_impl.cc
+++ b/chrome/browser/ui/ash/session_controller_client_impl.cc
@@ -84,7 +84,7 @@
   const uint32_t user_session_id = GetSessionId(user);
   DCHECK_NE(0u, user_session_id);
 
-  Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(&user);
+  Profile* profile = ash::ProfileHelper::Get()->GetProfileByUser(&user);
   DCHECK(profile);
 
   auto session = std::make_unique<ash::UserSession>();
@@ -299,7 +299,7 @@
 }
 
 PrefService* SessionControllerClientImpl::GetSigninScreenPrefService() {
-  return chromeos::ProfileHelper::Get()->GetSigninProfile()->GetPrefs();
+  return ash::ProfileHelper::Get()->GetSigninProfile()->GetPrefs();
 }
 
 PrefService* SessionControllerClientImpl::GetUserPrefService(
@@ -375,7 +375,7 @@
 bool SessionControllerClientImpl::ShouldLockScreenAutomatically() {
   const UserList logged_in_users = UserManager::Get()->GetLoggedInUsers();
   for (auto* user : logged_in_users) {
-    Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+    Profile* profile = ash::ProfileHelper::Get()->GetProfileByUser(user);
     if (profile &&
         profile->GetPrefs()->GetBoolean(ash::prefs::kEnableAutoScreenLock)) {
       return true;
@@ -499,13 +499,13 @@
 void SessionControllerClientImpl::OnUserProfileLoaded(
     const AccountId& account_id) {
   OnLoginUserProfilePrepared(
-      chromeos::ProfileHelper::Get()->GetProfileByAccountId(account_id));
+      ash::ProfileHelper::Get()->GetProfileByAccountId(account_id));
 }
 
 void SessionControllerClientImpl::OnCustodianInfoChanged() {
   DCHECK(supervised_user_profile_);
-  User* user = chromeos::ProfileHelper::Get()->GetUserByProfile(
-      supervised_user_profile_);
+  User* user =
+      ash::ProfileHelper::Get()->GetUserByProfile(supervised_user_profile_);
   if (user)
     SendUserSession(*user);
 }
@@ -525,7 +525,7 @@
 }
 
 void SessionControllerClientImpl::OnLoginUserProfilePrepared(Profile* profile) {
-  const User* user = chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+  const User* user = ash::ProfileHelper::Get()->GetUserByProfile(profile);
   DCHECK(user);
 
   if (profile->IsChild()) {
@@ -583,7 +583,7 @@
   // Check user profile via GetProfileByUser() instead of is_profile_created()
   // flag because many tests have only setup testing user profile in
   // ProfileHelper but do not have the flag updated.
-  if (!chromeos::ProfileHelper::Get()->GetProfileByUser(&user)) {
+  if (!ash::ProfileHelper::Get()->GetProfileByUser(&user)) {
     pending_users_.insert(user.GetAccountId());
     return;
   }
diff --git a/chrome/browser/ui/ash/session_controller_client_impl_unittest.cc b/chrome/browser/ui/ash/session_controller_client_impl_unittest.cc
index 6ac5b62..03e5b81 100644
--- a/chrome/browser/ui/ash/session_controller_client_impl_unittest.cc
+++ b/chrome/browser/ui/ash/session_controller_client_impl_unittest.cc
@@ -80,8 +80,7 @@
     // depends on prefs::kAllowScreenLock.
     user_manager::UserList unlock_users;
     for (user_manager::User* user : users_) {
-      Profile* user_profile =
-          chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+      Profile* user_profile = ash::ProfileHelper::Get()->GetProfileByUser(user);
       // Skip if user has a profile and kAllowScreenLock is set to false.
       if (user_profile &&
           !user_profile->GetPrefs()->GetBoolean(ash::prefs::kAllowScreenLock)) {
@@ -153,7 +152,7 @@
                  : user_manager()->AddUser(account_id);
     session_manager_.CreateSession(
         account_id,
-        chromeos::ProfileHelper::GetUserIdHashByUserIdForTesting(
+        ash::ProfileHelper::GetUserIdHashByUserIdForTesting(
             account_id.GetUserEmail()),
         is_child);
 
@@ -191,8 +190,7 @@
     TestingProfile* profile =
         profile_manager_->CreateTestingProfile(account_id.GetUserEmail());
     profile->set_profile_name(account_id.GetUserEmail());
-    chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(user,
-                                                                      profile);
+    ash::ProfileHelper::Get()->SetUserToProfileMappingForTesting(user, profile);
     return profile;
   }
 
@@ -461,7 +459,7 @@
   CreateTestingProfile(user);
   session_manager_.CreateSession(
       account_id,
-      chromeos::ProfileHelper::GetUserIdHashByUserIdForTesting(
+      ash::ProfileHelper::GetUserIdHashByUserIdForTesting(
           account_id.GetUserEmail()),
       false);
   session_manager_.SetSessionState(SessionState::ACTIVE);
@@ -516,7 +514,7 @@
   const user_manager::User* user = user_manager()->AddUser(account_id);
   session_manager_.CreateSession(
       account_id,
-      chromeos::ProfileHelper::GetUserIdHashByUserIdForTesting(
+      ash::ProfileHelper::GetUserIdHashByUserIdForTesting(
           account_id.GetUserEmail()),
       false);
 
diff --git a/chrome/browser/ui/ash/session_util.cc b/chrome/browser/ui/ash/session_util.cc
index 21272bd..3e7f118 100644
--- a/chrome/browser/ui/ash/session_util.cc
+++ b/chrome/browser/ui/ash/session_util.cc
@@ -70,7 +70,7 @@
 }
 
 gfx::ImageSkia GetAvatarImageForContext(content::BrowserContext* context) {
-  return GetAvatarImageForUser(chromeos::ProfileHelper::Get()->GetUserByProfile(
+  return GetAvatarImageForUser(ash::ProfileHelper::Get()->GetUserByProfile(
       Profile::FromBrowserContext(context)));
 }
 
diff --git a/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_crostini_tracker.cc b/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_crostini_tracker.cc
index b462436..2f7da92 100644
--- a/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_crostini_tracker.cc
+++ b/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_crostini_tracker.cc
@@ -100,7 +100,7 @@
       user_manager::UserManager::Get()->GetPrimaryUser()->GetAccountId();
 
   Profile* primary_account_profile =
-      chromeos::ProfileHelper::Get()->GetProfileByAccountId(primary_account_id);
+      ash::ProfileHelper::Get()->GetProfileByAccountId(primary_account_id);
 
   // Windows without an application id set will get filtered out here.
   const std::string& crostini_shelf_app_id = crostini::GetCrostiniShelfAppId(
@@ -224,7 +224,7 @@
   // future, this may be replaced by some way of matching the container that
   // runs this app with the user that owns it.
   const Profile* primary_account_profile =
-      chromeos::ProfileHelper::Get()->GetProfileByAccountId(
+      ash::ProfileHelper::Get()->GetProfileByAccountId(
           user_manager::UserManager::Get()->GetPrimaryUser()->GetAccountId());
   std::string shelf_app_id = crostini::GetCrostiniShelfAppId(
       primary_account_profile, exo::GetShellApplicationId(window),
diff --git a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc
index b9dd7073..29e14ed 100644
--- a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc
+++ b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc
@@ -1213,7 +1213,7 @@
     // Creates profile().
     ChromeShelfControllerTestBase::SetUp();
 
-    ASSERT_TRUE(chromeos::ProfileHelper::Get()->IsPrimaryProfile(profile()));
+    ASSERT_TRUE(ash::ProfileHelper::Get()->IsPrimaryProfile(profile()));
   }
 
  private:
diff --git a/chrome/browser/ui/ash/shelf/chrome_shelf_prefs.cc b/chrome/browser/ui/ash/shelf/chrome_shelf_prefs.cc
index 545ae90..bcfd3d93 100644
--- a/chrome/browser/ui/ash/shelf/chrome_shelf_prefs.cc
+++ b/chrome/browser/ui/ash/shelf/chrome_shelf_prefs.cc
@@ -407,7 +407,7 @@
   // is pinned. Lacros doesn't support multi-signin, so only add the icon for
   // the primary user.
   if (crosapi::browser_util::IsLacrosEnabled() &&
-      chromeos::ProfileHelper::IsPrimaryProfile(profile_)) {
+      ash::ProfileHelper::IsPrimaryProfile(profile_)) {
     syncer::StringOrdinal lacros_position =
         syncable_service->GetPinPosition(extension_misc::kLacrosAppId);
     if (!lacros_position.IsValid()) {
diff --git a/chrome/browser/ui/ash/shelf/shelf_spinner_controller.cc b/chrome/browser/ui/ash/shelf/shelf_spinner_controller.cc
index ef35459..06019fb 100644
--- a/chrome/browser/ui/ash/shelf/shelf_spinner_controller.cc
+++ b/chrome/browser/ui/ash/shelf/shelf_spinner_controller.cc
@@ -234,8 +234,7 @@
 void ShelfSpinnerController::CloseCrostiniSpinners() {
   std::vector<std::string> app_ids_to_close;
   const Profile* profile =
-      chromeos::ProfileHelper::Get()->GetProfileByAccountId(
-          current_account_id_);
+      ash::ProfileHelper::Get()->GetProfileByAccountId(current_account_id_);
   for (const auto& app_id_controller_pair : app_controller_map_) {
     if (crostini::IsCrostiniShelfAppId(profile, app_id_controller_pair.first))
       app_ids_to_close.push_back(app_id_controller_pair.first);
diff --git a/chrome/browser/ui/ash/system_tray_client_impl_browsertest.cc b/chrome/browser/ui/ash/system_tray_client_impl_browsertest.cc
index 2a70c2c..5650c0f 100644
--- a/chrome/browser/ui/ash/system_tray_client_impl_browsertest.cc
+++ b/chrome/browser/ui/ash/system_tray_client_impl_browsertest.cc
@@ -38,7 +38,7 @@
 #include "ui/chromeos/devicetype_utils.h"
 #include "url/gurl.h"
 
-using chromeos::ProfileHelper;
+using ::ash::ProfileHelper;
 using user_manager::UserManager;
 
 using SystemTrayClientEnterpriseTest = policy::DevicePolicyCrosBrowserTest;
diff --git a/chrome/browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc b/chrome/browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc
index 7862e8c..e37812a 100644
--- a/chrome/browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc
+++ b/chrome/browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc
@@ -30,7 +30,7 @@
 #include "ui/message_center/message_center.h"
 #include "url/gurl.h"
 
-using chromeos::ProfileHelper;
+using ::ash::ProfileHelper;
 using testing::_;
 using user_manager::UserManager;
 
diff --git a/chrome/browser/ui/ash/vpn_list_forwarder.cc b/chrome/browser/ui/ash/vpn_list_forwarder.cc
index b0e23c6..168a36d7 100644
--- a/chrome/browser/ui/ash/vpn_list_forwarder.cc
+++ b/chrome/browser/ui/ash/vpn_list_forwarder.cc
@@ -67,7 +67,7 @@
   if (!primary_user)
     return nullptr;
 
-  return chromeos::ProfileHelper::Get()->GetProfileByUser(primary_user);
+  return ash::ProfileHelper::Get()->GetProfileByUser(primary_user);
 }
 
 }  // namespace
diff --git a/chrome/browser/ui/ash/wallpaper_controller_client_impl.cc b/chrome/browser/ui/ash/wallpaper_controller_client_impl.cc
index e45beac..6882e09 100644
--- a/chrome/browser/ui/ash/wallpaper_controller_client_impl.cc
+++ b/chrome/browser/ui/ash/wallpaper_controller_client_impl.cc
@@ -64,7 +64,7 @@
 #include "ui/display/screen.h"
 #include "url/gurl.h"
 
-using chromeos::ProfileHelper;
+using ::ash::ProfileHelper;
 using extension_misc::kWallpaperManagerId;
 using file_manager::VolumeManager;
 using session_manager::SessionManager;
diff --git a/chrome/browser/ui/browser_finder_chromeos_unittest.cc b/chrome/browser/ui/browser_finder_chromeos_unittest.cc
index f5e4381..aa7459bf 100644
--- a/chrome/browser/ui/browser_finder_chromeos_unittest.cc
+++ b/chrome/browser/ui/browser_finder_chromeos_unittest.cc
@@ -41,9 +41,9 @@
     TestingProfile* profile =
         profile_manager()->CreateTestingProfile(account_id.GetUserEmail());
     const user_manager::User* user = fake_user_manager_->AddUser(account_id);
-    chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
+    ash::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
         const_cast<user_manager::User*>(user), profile);
-    chromeos::ProfileHelper::Get()->SetProfileToUserMappingForTesting(
+    ash::ProfileHelper::Get()->SetProfileToUserMappingForTesting(
         const_cast<user_manager::User*>(user));
     // Force creation of MultiProfileSupport.
     GetMultiUserWindowManager();
diff --git a/chrome/browser/ui/browser_navigator_browsertest_chromeos.cc b/chrome/browser/ui/browser_navigator_browsertest_chromeos.cc
index 15f769a..f71869a4 100644
--- a/chrome/browser/ui/browser_navigator_browsertest_chromeos.cc
+++ b/chrome/browser/ui/browser_navigator_browsertest_chromeos.cc
@@ -48,7 +48,7 @@
 
   EXPECT_EQ(Browser::CreationStatus::kErrorProfileUnsuitable,
             Browser::GetCreationStatusForProfile(
-                chromeos::ProfileHelper::GetSigninProfile()));
+                ash::ProfileHelper::GetSigninProfile()));
 }
 
 // Verify that page navigation is blocked in locked fullscreen mode.
diff --git a/chrome/browser/ui/login/login_handler.cc b/chrome/browser/ui/login/login_handler.cc
index 1f2bf7f0..1e42eb8d 100644
--- a/chrome/browser/ui/login/login_handler.cc
+++ b/chrome/browser/ui/login/login_handler.cc
@@ -408,8 +408,8 @@
     dialog_form.scheme = PasswordForm::Scheme::kOther;
   }
   dialog_form.url = auth_info.challenger.GetURL();
-  DCHECK(auth_info.is_proxy || auth_info.challenger.IsSameOriginWith(
-                                   url::Origin::Create(request_url)));
+  DCHECK(auth_info.is_proxy ||
+         auth_info.challenger.IsSameOriginWith(request_url));
   dialog_form.signon_realm = GetSignonRealm(dialog_form.url, auth_info);
   return dialog_form;
 }
diff --git a/chrome/browser/ui/page_info/page_info_unittest.cc b/chrome/browser/ui/page_info/page_info_unittest.cc
index a05cd5c..b7d954b 100644
--- a/chrome/browser/ui/page_info/page_info_unittest.cc
+++ b/chrome/browser/ui/page_info/page_info_unittest.cc
@@ -166,10 +166,9 @@
     auto account_id =
         AccountId::FromUserEmailGaiaId(profile()->GetProfileUserName(), "id");
     user_ = std::make_unique<FakeAffiliatedUser>(account_id);
-    chromeos::ProfileHelper::Get()->SetProfileToUserMappingForTesting(
-        user_.get());
-    chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(
-        user_.get(), profile());
+    ash::ProfileHelper::Get()->SetProfileToUserMappingForTesting(user_.get());
+    ash::ProfileHelper::Get()->SetUserToProfileMappingForTesting(user_.get(),
+                                                                 profile());
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
     infobars::ContentInfoBarManager::CreateForWebContents(web_contents());
diff --git a/chrome/browser/ui/startup/startup_browser_creator.cc b/chrome/browser/ui/startup/startup_browser_creator.cc
index 5071ccd2..bbb5b28 100644
--- a/chrome/browser/ui/startup/startup_browser_creator.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator.cc
@@ -876,7 +876,7 @@
 
   if (chrome::IsRunningInForcedAppMode()) {
     user_manager::User* user =
-        chromeos::ProfileHelper::Get()->GetUserByProfile(last_used_profile);
+        ash::ProfileHelper::Get()->GetUserByProfile(last_used_profile);
     if (user && user->GetType() == user_manager::USER_TYPE_KIOSK_APP) {
       chromeos::LaunchAppOrDie(
           last_used_profile,
diff --git a/chrome/browser/ui/views/chrome_web_dialog_view.cc b/chrome/browser/ui/views/chrome_web_dialog_view.cc
index 9debcd3..9aec42e 100644
--- a/chrome/browser/ui/views/chrome_web_dialog_view.cc
+++ b/chrome/browser/ui/views/chrome_web_dialog_view.cc
@@ -75,9 +75,8 @@
   gfx::NativeWindow window =
       CreateWebDialogWidget(std::move(params), view, show);
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(
-          Profile::FromBrowserContext(context));
+  const user_manager::User* user = ash::ProfileHelper::Get()->GetUserByProfile(
+      Profile::FromBrowserContext(context));
   if (user && session_manager::SessionManager::Get()->session_state() ==
                   session_manager::SessionState::ACTIVE) {
     // Dialogs should not be shown for other users when logged in and the
diff --git a/chrome/browser/ui/views/frame/system_menu_model_builder_browsertest_chromeos.cc b/chrome/browser/ui/views/frame/system_menu_model_builder_browsertest_chromeos.cc
index 1eaf901..fc34b154 100644
--- a/chrome/browser/ui/views/frame/system_menu_model_builder_browsertest_chromeos.cc
+++ b/chrome/browser/ui/views/frame/system_menu_model_builder_browsertest_chromeos.cc
@@ -18,8 +18,8 @@
 #include "content/public/test/browser_test.h"
 #include "ui/base/models/menu_model.h"
 
+using ::ash::ProfileHelper;
 using chrome::SettingsWindowManager;
-using chromeos::ProfileHelper;
 using user_manager::UserManager;
 
 namespace {
diff --git a/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc b/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc
index f0fcbb4..b254fc4 100644
--- a/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc
+++ b/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc
@@ -37,7 +37,7 @@
 
 struct WidgetEventPair {
   views::Widget* widget;
-  ui::MouseEvent event;
+  std::unique_ptr<ui::MouseEvent> event;
 };
 
 WidgetEventPair GetParentWidgetAndEvent(views::View* this_view,
@@ -47,24 +47,26 @@
   // forwarding.
   views::Widget* this_widget = this_view->GetWidget();
   views::Widget* parent_widget = this_widget->parent();
+  std::unique_ptr<ui::MouseEvent> event(
+      static_cast<ui::MouseEvent*>(ui::Event::Clone(*this_event).release()));
   if (!parent_widget)
-    return {nullptr, *this_event};
+    return {nullptr, std::move(event)};
 
   views::Widget* top_level = parent_widget->GetTopLevelWidgetForNativeView(
       parent_widget->GetNativeView());
   DCHECK_NE(this_widget, top_level);
   if (!top_level)
-    return {nullptr, *this_event};
+    return {nullptr, std::move(event)};
 
   gfx::Point event_location = this_event->location();
   views::View::ConvertPointToScreen(this_view, &event_location);
   views::View::ConvertPointFromScreen(top_level->GetRootView(),
                                       &event_location);
 
-  ui::MouseEvent top_level_event(*this_event);
-  top_level_event.set_location(event_location);
+  // Convert location to top level widget coordinate.
+  event->set_location(event_location);
 
-  return {top_level, top_level_event};
+  return {top_level, std::move(event)};
 }
 
 #endif  // !USE_AURA
@@ -121,13 +123,13 @@
   void OnMouseMoved(const ui::MouseEvent& event) override {
     auto pair = GetParentWidgetAndEvent(this, &event);
     if (pair.widget)
-      pair.widget->OnMouseEvent(&pair.event);
+      pair.widget->OnMouseEvent(pair.event.get());
   }
 
   void OnMouseEvent(ui::MouseEvent* event) override {
     auto pair = GetParentWidgetAndEvent(this, event);
     if (pair.widget)
-      pair.widget->OnMouseEvent(&pair.event);
+      pair.widget->OnMouseEvent(pair.event.get());
 
     // If the original event isn't marked as "handled" then it will propagate up
     // the view hierarchy and might be double-handled. https://crbug.com/870341
@@ -139,8 +141,8 @@
     if (pair.widget) {
       views::View* omnibox_view =
           pair.widget->GetRootView()->GetEventHandlerForPoint(
-              pair.event.location());
-      return omnibox_view->GetCursor(pair.event);
+              pair.event->location());
+      return omnibox_view->GetCursor(*pair.event);
     }
 
     return nullptr;
@@ -274,13 +276,13 @@
 void RoundedOmniboxResultsFrame::OnMouseMoved(const ui::MouseEvent& event) {
   auto pair = GetParentWidgetAndEvent(this, &event);
   if (pair.widget)
-    pair.widget->OnMouseEvent(&pair.event);
+    pair.widget->OnMouseEvent(pair.event.get());
 }
 
 void RoundedOmniboxResultsFrame::OnMouseEvent(ui::MouseEvent* event) {
   auto pair = GetParentWidgetAndEvent(this, event);
   if (pair.widget)
-    pair.widget->OnMouseEvent(&pair.event);
+    pair.widget->OnMouseEvent(pair.event.get());
 }
 
 #endif  // !USE_AURA
diff --git a/chrome/browser/ui/views/plugin_vm/plugin_vm_installer_view_browsertest.cc b/chrome/browser/ui/views/plugin_vm/plugin_vm_installer_view_browsertest.cc
index 654ba398..3043e48b 100644
--- a/chrome/browser/ui/views/plugin_vm/plugin_vm_installer_view_browsertest.cc
+++ b/chrome/browser/ui/views/plugin_vm/plugin_vm_installer_view_browsertest.cc
@@ -178,7 +178,7 @@
     auto user_manager = std::make_unique<ash::FakeChromeUserManager>();
     user_manager->AddUserWithAffiliation(account_id, true);
     user_manager->LoginUser(account_id);
-    chromeos::ProfileHelper::Get()->SetProfileToUserMappingForTesting(
+    ash::ProfileHelper::Get()->SetProfileToUserMappingForTesting(
         user_manager->GetActiveUser());
     scoped_user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
         std::move(user_manager));
diff --git a/chrome/browser/ui/views/select_file_dialog_extension.cc b/chrome/browser/ui/views/select_file_dialog_extension.cc
index 5def12d..303e39c 100644
--- a/chrome/browser/ui/views/select_file_dialog_extension.cc
+++ b/chrome/browser/ui/views/select_file_dialog_extension.cc
@@ -509,7 +509,7 @@
 
   // Handle the cases where |web_contents| is not available or |web_contents| is
   // associated with Default profile.
-  if (!web_contents || chromeos::ProfileHelper::IsSigninProfile(profile_))
+  if (!web_contents || ash::ProfileHelper::IsSigninProfile(profile_))
     profile_ = ProfileManager::GetActiveUserProfile();
 
   DCHECK(profile_);
diff --git a/chrome/browser/ui/web_applications/system_web_app_ui_utils.cc b/chrome/browser/ui/web_applications/system_web_app_ui_utils.cc
index cb9f953..e243ea2 100644
--- a/chrome/browser/ui/web_applications/system_web_app_ui_utils.cc
+++ b/chrome/browser/ui/web_applications/system_web_app_ui_utils.cc
@@ -49,7 +49,7 @@
   if (profile->IsSystemProfile())
     return nullptr;
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  if (chromeos::ProfileHelper::IsSigninProfile(profile))
+  if (ash::ProfileHelper::IsSigninProfile(profile))
     return nullptr;
 #endif
 
diff --git a/chrome/browser/ui/web_applications/test/system_web_app_interactive_uitest.cc b/chrome/browser/ui/web_applications/test/system_web_app_interactive_uitest.cc
index 48379b84e..bd83ea5 100644
--- a/chrome/browser/ui/web_applications/test/system_web_app_interactive_uitest.cc
+++ b/chrome/browser/ui/web_applications/test/system_web_app_interactive_uitest.cc
@@ -597,7 +597,7 @@
 
   // Wait for System Apps to be installed on both user profiles.
   auto* user_manager = user_manager::UserManager::Get();
-  Profile* profile1 = chromeos::ProfileHelper::Get()->GetProfileByUser(
+  Profile* profile1 = ash::ProfileHelper::Get()->GetProfileByUser(
       user_manager->FindUser(account_id1_));
   WaitForSystemWebAppInstall(profile1);
 
@@ -606,7 +606,7 @@
   ash::UserAddingScreen::Get()->Start();
   AddUser(account_id2_);
   base::RunLoop().RunUntilIdle();
-  Profile* profile2 = chromeos::ProfileHelper::Get()->GetProfileByUser(
+  Profile* profile2 = ash::ProfileHelper::Get()->GetProfileByUser(
       user_manager->FindUser(account_id2_));
   WaitForSystemWebAppInstall(profile2);
   // Set user 1 to be active.
@@ -651,7 +651,7 @@
 
   // Wait for System Apps to be installed on both user profiles.
   auto* user_manager = user_manager::UserManager::Get();
-  Profile* profile1 = chromeos::ProfileHelper::Get()->GetProfileByUser(
+  Profile* profile1 = ash::ProfileHelper::Get()->GetProfileByUser(
       user_manager->FindUser(account_id1_));
   WaitForSystemWebAppInstall(profile1);
 
@@ -660,7 +660,7 @@
   ash::UserAddingScreen::Get()->Start();
   AddUser(account_id2_);
   base::RunLoop().RunUntilIdle();
-  Profile* profile2 = chromeos::ProfileHelper::Get()->GetProfileByUser(
+  Profile* profile2 = ash::ProfileHelper::Get()->GetProfileByUser(
       user_manager->FindUser(account_id2_));
   WaitForSystemWebAppInstall(profile2);
 
@@ -726,7 +726,7 @@
                        LaunchFromSignInProfile) {
   WaitForTestSystemAppInstall();
 
-  Profile* signin_profile = chromeos::ProfileHelper::GetSigninProfile();
+  Profile* signin_profile = ash::ProfileHelper::GetSigninProfile();
 
   EXPECT_EQ(1U, chrome::GetTotalBrowserCount());
 
diff --git a/chrome/browser/ui/webui/certificate_provisioning_ui_handler.cc b/chrome/browser/ui/webui/certificate_provisioning_ui_handler.cc
index 05caf506..59f8f68 100644
--- a/chrome/browser/ui/webui/certificate_provisioning_ui_handler.cc
+++ b/chrome/browser/ui/webui/certificate_provisioning_ui_handler.cc
@@ -286,7 +286,7 @@
 bool CertificateProvisioningUiHandler::ShouldUseDeviceWideProcesses(
     Profile* user_profile) {
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(user_profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(user_profile);
   return user && user->IsAffiliated();
 }
 
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index 9fa018d..be51ec4 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -1440,12 +1440,14 @@
       GURL(chrome::kChromeUINetworkUrl), GURL(chrome::kOsUINetworkUrl),
       GURL(chrome::kChromeUIOSCreditsURL), GURL(chrome::kOsUIOSSettingsURL),
       GURL(chrome::kChromeUIPowerUrl),
-      GURL(chrome::kChromeUIPrintManagementUrl), GURL(chrome::kOsUIRestartURL),
-      GURL(chrome::kChromeUIScanningAppURL), GURL(chrome::kOsUIScanningAppURL),
-      GURL(chrome::kChromeUISetTimeURL), GURL(chrome::kChromeUIOSSettingsURL),
-      GURL(chrome::kChromeUISettingsURL), GURL(chrome::kOsUISettingsURL),
-      GURL(chrome::kOsUISignInInternalsUrl), GURL(chrome::kChromeUISlowURL),
-      GURL(chrome::kChromeUISmbShareURL), GURL(chrome::kOsUISyncInternalsUrl),
+      GURL(chrome::kChromeUIPrintManagementUrl),
+      GURL(chromeos::multidevice::kChromeUIProximityAuthURL),
+      GURL(chrome::kOsUIRestartURL), GURL(chrome::kChromeUIScanningAppURL),
+      GURL(chrome::kOsUIScanningAppURL), GURL(chrome::kChromeUISetTimeURL),
+      GURL(chrome::kChromeUIOSSettingsURL), GURL(chrome::kChromeUISettingsURL),
+      GURL(chrome::kOsUISettingsURL), GURL(chrome::kOsUISignInInternalsUrl),
+      GURL(chrome::kChromeUISlowURL), GURL(chrome::kChromeUISmbShareURL),
+      GURL(chrome::kOsUISyncInternalsUrl),
       GURL(chrome::kChromeUISysInternalsUrl),
       GURL(chrome::kChromeUIUserImageURL), GURL(chrome::kOsUIVersionURL),
       GURL(chrome::kChromeUIVmUrl),
diff --git a/chrome/browser/ui/webui/cookies_tree_model_util.cc b/chrome/browser/ui/webui/cookies_tree_model_util.cc
index b040bdc..c7d6e06 100644
--- a/chrome/browser/ui/webui/cookies_tree_model_util.cc
+++ b/chrome/browser/ui/webui/cookies_tree_model_util.cc
@@ -252,13 +252,14 @@
     case CookieTreeNode::DetailedInfo::TYPE_MEDIA_LICENSE: {
       dict->SetStringKey(kKeyType, "media_license");
 
-      const BrowsingDataMediaLicenseHelper::MediaLicenseInfo&
-          media_license_info = *node.GetDetailedInfo().media_license_info;
-      dict->SetStringKey(kKeyOrigin, media_license_info.origin.spec());
-      dict->SetStringKey(kKeySize, ui::FormatBytes(media_license_info.size));
+      const content::StorageUsageInfo& usage_info =
+          *node.GetDetailedInfo().media_license_usage_info;
+      dict->SetStringKey(kKeyOrigin, usage_info.origin.GetURL().spec());
+      dict->SetStringKey(kKeySize,
+                         ui::FormatBytes(usage_info.total_size_bytes));
       dict->SetStringKey(kKeyModified,
                          base::UTF16ToUTF8(base::TimeFormatFriendlyDateAndTime(
-                             media_license_info.last_modified_time)));
+                             usage_info.last_modified)));
       break;
     }
     default:
diff --git a/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.cc b/chrome/browser/ui/webui/extensions/ash/kiosk_apps_handler.cc
similarity index 98%
rename from chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.cc
rename to chrome/browser/ui/webui/extensions/ash/kiosk_apps_handler.cc
index f403153..40b41e4 100644
--- a/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.cc
+++ b/chrome/browser/ui/webui/extensions/ash/kiosk_apps_handler.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.h"
+#include "chrome/browser/ui/webui/extensions/ash/kiosk_apps_handler.h"
 
 #include <stddef.h>
 
@@ -34,7 +34,7 @@
 #include "ui/base/webui/web_ui_util.h"
 #include "url/gurl.h"
 
-namespace chromeos {
+namespace ash {
 
 namespace {
 
@@ -338,4 +338,4 @@
   kiosk_app_manager_->RemoveApp(app_id, owner_settings_service_);
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.h b/chrome/browser/ui/webui/extensions/ash/kiosk_apps_handler.h
similarity index 84%
rename from chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.h
rename to chrome/browser/ui/webui/extensions/ash/kiosk_apps_handler.h
index d9fcb64d..2671788 100644
--- a/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.h
+++ b/chrome/browser/ui/webui/extensions/ash/kiosk_apps_handler.h
@@ -2,24 +2,23 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_WEBUI_EXTENSIONS_CHROMEOS_KIOSK_APPS_HANDLER_H_
-#define CHROME_BROWSER_UI_WEBUI_EXTENSIONS_CHROMEOS_KIOSK_APPS_HANDLER_H_
+#ifndef CHROME_BROWSER_UI_WEBUI_EXTENSIONS_ASH_KIOSK_APPS_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_EXTENSIONS_ASH_KIOSK_APPS_HANDLER_H_
 
 #include <string>
 
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ash/app_mode/kiosk_app_manager.h"
 #include "chrome/browser/ash/app_mode/kiosk_app_manager_observer.h"
-// TODO(https://crbug.com/1164001): move OwnerSettingsServiceAsh to forward
-// declaration when moved to chrome/browser/ash/.
-#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
 #include "content/public/browser/web_ui_message_handler.h"
 
 namespace base {
 class ListValue;
 }
 
-namespace chromeos {
+namespace ash {
+
+class OwnerSettingsServiceAsh;
 
 class KioskAppsHandler : public content::WebUIMessageHandler,
                          public KioskAppManagerObserver {
@@ -73,6 +72,6 @@
   base::WeakPtrFactory<KioskAppsHandler> weak_ptr_factory_{this};
 };
 
-}  // namespace chromeos
+}  // namespace ash
 
-#endif  // CHROME_BROWSER_UI_WEBUI_EXTENSIONS_CHROMEOS_KIOSK_APPS_HANDLER_H_
+#endif  // CHROME_BROWSER_UI_WEBUI_EXTENSIONS_ASH_KIOSK_APPS_HANDLER_H_
diff --git a/chrome/browser/ui/webui/extensions/extensions_ui.cc b/chrome/browser/ui/webui/extensions/extensions_ui.cc
index 1c3a3b2..2dee644c 100644
--- a/chrome/browser/ui/webui/extensions/extensions_ui.cc
+++ b/chrome/browser/ui/webui/extensions/extensions_ui.cc
@@ -49,7 +49,7 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
-#include "chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.h"
+#include "chrome/browser/ui/webui/extensions/ash/kiosk_apps_handler.h"
 #endif
 
 namespace extensions {
@@ -360,7 +360,7 @@
   ManagedUIHandler::Initialize(web_ui, source);
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  auto kiosk_app_handler = std::make_unique<chromeos::KioskAppsHandler>(
+  auto kiosk_app_handler = std::make_unique<ash::KioskAppsHandler>(
       ash::OwnerSettingsServiceAshFactory::GetForBrowserContext(profile));
   web_ui->AddMessageHandler(std::move(kiosk_app_handler));
 #endif
diff --git a/chrome/browser/ui/webui/flags/flags_ui.cc b/chrome/browser/ui/webui/flags/flags_ui.cc
index 7bcfd68..b7db9d61 100644
--- a/chrome/browser/ui/webui/flags/flags_ui.cc
+++ b/chrome/browser/ui/webui/flags/flags_ui.cc
@@ -138,7 +138,7 @@
   }
 
   // Show a warning info bar for secondary users.
-  if (!chromeos::ProfileHelper::IsPrimaryProfile(profile)) {
+  if (!ash::ProfileHelper::IsPrimaryProfile(profile)) {
     CreateSimpleAlertInfoBar(
         infobars::ContentInfoBarManager::FromWebContents(
             flags_ui->web_ui()->GetWebContents()),
diff --git a/chrome/browser/ui/webui/management/management_ui_handler.cc b/chrome/browser/ui/webui/management/management_ui_handler.cc
index 84fef7e..9f9080b 100644
--- a/chrome/browser/ui/webui/management/management_ui_handler.cc
+++ b/chrome/browser/ui/webui/management/management_ui_handler.cc
@@ -947,9 +947,8 @@
   std::string account_manager = GetAccountManager(profile);
   auto* primary_user = user_manager::UserManager::Get()->GetPrimaryUser();
   auto* primary_profile =
-      primary_user
-          ? chromeos::ProfileHelper::Get()->GetProfileByUser(primary_user)
-          : nullptr;
+      primary_user ? ash::ProfileHelper::Get()->GetProfileByUser(primary_user)
+                   : nullptr;
   const bool primary_user_managed =
       primary_profile ? IsProfileManaged(primary_profile) : false;
 
diff --git a/chrome/browser/ui/webui/nearby_internals/quick_pair/quick_pair_handler.cc b/chrome/browser/ui/webui/nearby_internals/quick_pair/quick_pair_handler.cc
index bfe10cd..4d114c29 100644
--- a/chrome/browser/ui/webui/nearby_internals/quick_pair/quick_pair_handler.cc
+++ b/chrome/browser/ui/webui/nearby_internals/quick_pair/quick_pair_handler.cc
@@ -3860,7 +3860,8 @@
 
 void QuickPairHandler::OnImageDecodedFastPairDiscovery(gfx::Image image) {
   fast_pair_notification_controller_->ShowDiscoveryNotification(
-      kTestDeviceName, image, base::DoNothing(), base::DoNothing());
+      kTestDeviceName, image, base::DoNothing(), base::DoNothing(),
+      base::DoNothing());
 }
 
 void QuickPairHandler::NotifyFastPairPairing(const base::ListValue* args) {
diff --git a/chrome/browser/ui/webui/policy/policy_ui_browsertest.cc b/chrome/browser/ui/webui/policy/policy_ui_browsertest.cc
index 879fa59..7d0375e8 100644
--- a/chrome/browser/ui/webui/policy/policy_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/policy/policy_ui_browsertest.cc
@@ -715,7 +715,7 @@
   Profile* extension_profile() const {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
     if (UseSigninProfile()) {
-      return chromeos::ProfileHelper::GetSigninProfile();
+      return ash::ProfileHelper::GetSigninProfile();
     }
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
     return browser()->profile();
diff --git a/chrome/browser/ui/webui/policy/policy_ui_handler.cc b/chrome/browser/ui/webui/policy/policy_ui_handler.cc
index 7ea8ee3de..7301dba 100644
--- a/chrome/browser/ui/webui/policy/policy_ui_handler.cc
+++ b/chrome/browser/ui/webui/policy/policy_ui_handler.cc
@@ -148,7 +148,7 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   if (!user)
     return;
   dict->SetBoolean("isAffiliated", user->IsAffiliated());
@@ -1018,7 +1018,7 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   Profile* extension_profile =
       policy_domain == policy::POLICY_DOMAIN_SIGNIN_EXTENSIONS
-          ? chromeos::ProfileHelper::GetSigninProfile()
+          ? ash::ProfileHelper::GetSigninProfile()
           : Profile::FromWebUI(web_ui());
 #else   // BUILDFLAG(IS_CHROMEOS_ASH)
   Profile* extension_profile = Profile::FromWebUI(web_ui());
diff --git a/chrome/browser/ui/webui/settings/about_handler.cc b/chrome/browser/ui/webui/settings/about_handler.cc
index 127f194..4d3faf0 100644
--- a/chrome/browser/ui/webui/settings/about_handler.cc
+++ b/chrome/browser/ui/webui/settings/about_handler.cc
@@ -128,7 +128,7 @@
 
     // Get the currently logged-in user and check if it is affiliated.
     const user_manager::User* user =
-        profile ? chromeos::ProfileHelper::Get()->GetUserByProfile(profile)
+        profile ? ash::ProfileHelper::Get()->GetUserByProfile(profile)
                 : nullptr;
     return user && user->IsAffiliated();
   }
diff --git a/chrome/browser/ui/webui/settings/languages_handler.cc b/chrome/browser/ui/webui/settings/languages_handler.cc
index 19ae7db..d9396ead 100644
--- a/chrome/browser/ui/webui/settings/languages_handler.cc
+++ b/chrome/browser/ui/webui/settings/languages_handler.cc
@@ -76,7 +76,7 @@
   // Secondary users and public session users cannot change the locale.
   user_manager::UserManager* user_manager = user_manager::UserManager::Get();
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile_);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile_);
   const std::string& language_code = args->GetList()[0].GetString();
   if (user &&
       user->GetAccountId() == user_manager->GetPrimaryUser()->GetAccountId() &&
diff --git a/chrome/browser/ui/webui/settings/profile_info_handler.cc b/chrome/browser/ui/webui/settings/profile_info_handler.cc
index ef6bd7c5..a5651ff 100644
--- a/chrome/browser/ui/webui/settings/profile_info_handler.cc
+++ b/chrome/browser/ui/webui/settings/profile_info_handler.cc
@@ -139,7 +139,7 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile_);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile_);
   DCHECK(user);
   name = base::UTF16ToUTF8(user->GetDisplayName());
 
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc
index d06bd15..8001fe39 100644
--- a/chrome/browser/ui/webui/settings/settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -295,7 +295,7 @@
   html_source->AddBoolean(
       "userCannotManuallyEnterPassword",
       !ash::password_visibility::AccountHasUserFacingPassword(
-          chromeos::ProfileHelper::Get()
+          ash::ProfileHelper::Get()
               ->GetUserByProfile(profile)
               ->GetAccountId()));
 
diff --git a/chrome/browser/ui/webui/signin/inline_login_ui.cc b/chrome/browser/ui/webui/signin/inline_login_ui.cc
index 3a25f52..f8da340 100644
--- a/chrome/browser/ui/webui/signin/inline_login_ui.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_ui.cc
@@ -200,7 +200,7 @@
           ui::GetChromeOSDeviceName()));
 
   user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+      ash::ProfileHelper::Get()->GetUserByProfile(profile);
   DCHECK(user);
   source->AddString("userName", user->GetGivenName());
   source->AddString("accountManagerOsSettingsUrl",
@@ -255,7 +255,7 @@
   content::WebUIDataSource* source = CreateWebUIDataSource(profile);
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   std::u16string username =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile)->GetGivenName();
+      ash::ProfileHelper::Get()->GetUserByProfile(profile)->GetGivenName();
   AddEduStrings(source, username);
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   content::WebUIDataSource::Add(profile, source);
diff --git a/chrome/browser/usb/web_usb_detector_unittest.cc b/chrome/browser/usb/web_usb_detector_unittest.cc
index 37c4147..0232fc0 100644
--- a/chrome/browser/usb/web_usb_detector_unittest.cc
+++ b/chrome/browser/usb/web_usb_detector_unittest.cc
@@ -78,7 +78,7 @@
     GetFakeUserManager()->AddUser(user_manager::StubAccountId());
     GetFakeUserManager()->LoginUser(user_manager::StubAccountId());
 
-    chromeos::ProfileHelper::Get()->SetActiveUserIdForTesting(kProfileName);
+    ash::ProfileHelper::Get()->SetActiveUserIdForTesting(kProfileName);
 #endif
     BrowserList::SetLastActive(browser());
     TestingBrowserProcess::GetGlobal()->SetSystemNotificationHelper(
diff --git a/chrome/browser/web_applications/preinstalled_web_app_manager.cc b/chrome/browser/web_applications/preinstalled_web_app_manager.cc
index af734bb7..ae7b735 100644
--- a/chrome/browser/web_applications/preinstalled_web_app_manager.cc
+++ b/chrome/browser/web_applications/preinstalled_web_app_manager.cc
@@ -737,7 +737,7 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   // Exclude sign-in and lock screen profiles.
-  if (!chromeos::ProfileHelper::IsRegularProfile(profile_)) {
+  if (!ash::ProfileHelper::IsRegularProfile(profile_)) {
     return {};
   }
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/web_applications/system_web_apps/test/system_web_app_manager_browsertest.cc b/chrome/browser/web_applications/system_web_apps/test/system_web_app_manager_browsertest.cc
index a2007e7c..f864ecb 100644
--- a/chrome/browser/web_applications/system_web_apps/test/system_web_app_manager_browsertest.cc
+++ b/chrome/browser/web_applications/system_web_apps/test/system_web_app_manager_browsertest.cc
@@ -1147,6 +1147,10 @@
 // aforementioned crbug is fixed.
 IN_PROC_BROWSER_TEST_P(SystemWebAppManagerInstallAllAppsBrowserTest,
                        WebAppProtoEntryDefined) {
+  // Wait for apps to install before performing assertions, otherwise the test
+  // might flake. See https://crbug.com/1286600#c6.
+  WaitForSystemAppsSynchronized();
+
   const auto& app_map = GetManager().GetRegisteredSystemAppsForTesting();
   ASSERT_GT(app_map.size(), 0U);
 
diff --git a/chrome/browser/web_applications/web_app_utils.cc b/chrome/browser/web_applications/web_app_utils.cc
index 1beac8b..4c04f4e 100644
--- a/chrome/browser/web_applications/web_app_utils.cc
+++ b/chrome/browser/web_applications/web_app_utils.cc
@@ -58,7 +58,7 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   // Web Apps should not be installed to the ChromeOS system profiles.
-  if (!chromeos::ProfileHelper::IsRegularProfile(original_profile)) {
+  if (!ash::ProfileHelper::IsRegularProfile(original_profile)) {
     return false;
   }
   // Disable Web Apps if running any kiosk app.
@@ -142,13 +142,13 @@
 
 std::string GetProfileCategoryForLogging(Profile* profile) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  if (!chromeos::ProfileHelper::IsRegularProfile(profile)) {
+  if (!ash::ProfileHelper::IsRegularProfile(profile)) {
     return "SigninOrLockScreen";
   } else if (user_manager::UserManager::Get()->IsLoggedInAsAnyKioskApp()) {
     return "Kiosk";
-  } else if (chromeos::ProfileHelper::IsEphemeralUserProfile(profile)) {
+  } else if (ash::ProfileHelper::IsEphemeralUserProfile(profile)) {
     return "Ephemeral";
-  } else if (chromeos::ProfileHelper::IsPrimaryProfile(profile)) {
+  } else if (ash::ProfileHelper::IsPrimaryProfile(profile)) {
     return "Primary";
   } else {
     return "Other";
diff --git a/chrome/browser/web_applications/web_app_utils_unittest.cc b/chrome/browser/web_applications/web_app_utils_unittest.cc
index d6d5961..0303c66 100644
--- a/chrome/browser/web_applications/web_app_utils_unittest.cc
+++ b/chrome/browser/web_applications/web_app_utils_unittest.cc
@@ -84,7 +84,7 @@
       signin_profile->GetPrimaryOTRProfile(/*create_if_needed=*/true)));
 
   Profile* lock_screen_profile = profile_manager.CreateTestingProfile(
-      chromeos::ProfileHelper::GetLockScreenAppProfileName());
+      ash::ProfileHelper::GetLockScreenAppProfileName());
   EXPECT_FALSE(AreWebAppsEnabled(lock_screen_profile));
   EXPECT_FALSE(AreWebAppsEnabled(
       lock_screen_profile->GetPrimaryOTRProfile(/*create_if_needed=*/true)));
@@ -149,7 +149,7 @@
       signin_profile->GetPrimaryOTRProfile(/*create_if_needed=*/true)));
 
   Profile* lock_screen_profile = profile_manager.CreateTestingProfile(
-      chromeos::ProfileHelper::GetLockScreenAppProfileName());
+      ash::ProfileHelper::GetLockScreenAppProfileName());
   EXPECT_FALSE(AreWebAppsUserInstallable(lock_screen_profile));
   EXPECT_FALSE(AreWebAppsUserInstallable(
       lock_screen_profile->GetPrimaryOTRProfile(/*create_if_needed=*/true)));
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
index 940d509a..01ed448e 100644
--- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
+++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
@@ -697,7 +697,7 @@
 
   const GURL test_site("https://webauthndemo.appspot.com");
   DCHECK(test_site.is_valid());
-  return origin.IsSameOriginWith(url::Origin::Create(test_site));
+  return origin.IsSameOriginWith(test_site);
 }
 
 void ChromeAuthenticatorRequestDelegate::HandleCablePairingEvent(
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index fafbe53..bef86e9 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1642010411-12c22ef7f8f5650de4b50b11575ceca3dfdb10c4.profdata
+chrome-linux-main-1642053592-c701c55b80cde61f0a1f914c56eac06a11fc6abb.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index a9e4b93..e9ed011f 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1642010411-dbdb65009bb7480f8206556395c15cad6bfe8f29.profdata
+chrome-mac-main-1642031908-55c538a72d36cd8ed81b176da7e7eb2641e7e90e.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 35cf623d..a15dffe1 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1642020849-ad8083771b169b33cd0bf5f7d5497cec68dbd03d.profdata
+chrome-win32-main-1642042377-fdac5dda08154114e6accd50fbd0f1bd0913a14c.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 91a76e6c..cafdc5e1 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1642010380-c9376231ee023211d2f5354c824ee5be4c58d74c.profdata
+chrome-win64-main-1642042377-42f525f4065ffdafdcf4df388d8754bf5aa936dc.profdata
diff --git a/chrome/common/extensions/api/developer_private.idl b/chrome/common/extensions/api/developer_private.idl
index d3cc055..452deae 100644
--- a/chrome/common/extensions/api/developer_private.idl
+++ b/chrome/common/extensions/api/developer_private.idl
@@ -357,6 +357,14 @@
     boolean? useDraggedPath;
   };
 
+  dictionary UserSiteSettings {
+    // The list of origins where the user has allowed all extensions to run on.
+    DOMString[] permittedSites;
+    // The list of origins where the user has blocked all extensions from
+    // running on.
+    DOMString[] restrictedSites;
+  };
+
   enum PackStatus {
     SUCCESS,
     ERROR,
@@ -534,6 +542,7 @@
       void (RequestFileSourceResponse response);
   callback LoadErrorCallback = void (optional LoadError error);
   callback DragInstallInProgressCallback = void (DOMString loadGuid);
+  callback UserSiteSettingsCallback = void (UserSiteSettings settings);
 
   interface Functions {
     // Runs auto update for extensions and apps immediately.
@@ -707,6 +716,11 @@
         DOMString host,
         optional VoidCallback callback);
 
+    // Returns the user specified site settings (which origins can extensions
+    // always/never run on) for the current profile.
+    [supportsPromises] static void getUserSiteSettings(
+        optional UserSiteSettingsCallback callback);
+
     [nocompile, deprecated="Use management.setEnabled"]
         static void enable(DOMString id,
                            boolean enabled,
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc
index 62702b5..1e305b5 100644
--- a/chrome/common/url_constants.cc
+++ b/chrome/common/url_constants.cc
@@ -335,9 +335,10 @@
 
 const char kArcTermsURLPath[] = "arc/terms";
 
-// TODO(crbug.com/1248270): Use real link to Bluetooth pairing learn more.
+// TODO(crbug.com/1010321): Remove 'm100' prefix from link once Bluetooth Revamp
+// has shipped.
 const char kBluetoothPairingLearnMoreUrl[] =
-    "https://support.google.com/chromebook/?p=bluetooth_pairing";
+    "https://support.google.com/chromebook?p=bluetooth_revamp_m100";
 
 const char kChromeAccessibilityHelpURL[] =
     "https://support.google.com/chromebook/topic/6323347";
diff --git a/chrome/renderer/media/media_feeds.cc b/chrome/renderer/media/media_feeds.cc
index d512dbf..60a7f77 100644
--- a/chrome/renderer/media/media_feeds.cc
+++ b/chrome/renderer/media/media_feeds.cc
@@ -65,8 +65,7 @@
 
     // If the URL is not the same origin as the document then we should throw
     // and error.
-    auto feed_origin = url::Origin::Create(url);
-    if (!document_origin.IsSameOriginWith(feed_origin)) {
+    if (!document_origin.IsSameOriginWith(url)) {
       frame->AddMessageToConsole(blink::mojom::ConsoleMessageLevel::kWarning,
                                  "The Media Feed URL needs to be the same "
                                  "origin as the document URL.");
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 2c7d2d7..152bb0d 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2137,6 +2137,8 @@
       "data/webui/certificate_viewer_ui_test-inl.h",
       "data/webui/chrome_send_browsertest.cc",
       "data/webui/chrome_send_browsertest.h",
+      "data/webui/chrome_timeticks_browsertest.cc",
+      "data/webui/chrome_timeticks_browsertest.h",
       "data/webui/history_ui_browsertest.cc",
       "data/webui/history_ui_browsertest.h",
       "data/webui/mojo/mojo_js_interface_broker_browsertest.cc",
@@ -3196,6 +3198,7 @@
         "../browser/ash/file_manager/file_manager_jstest_base.h",
         "../browser/ash/file_manager/file_tasks_browsertest.cc",
         "../browser/ash/file_manager/image_loader_jstest.cc",
+        "../browser/ash/file_manager/open_with_browser_browsertest.cc",
         "../browser/ash/first_run/drive_first_run_browsertest.cc",
         "../browser/ash/guest_os/guest_os_registry_service_icon_browsertest.cc",
         "../browser/ash/input_method/input_method_engine_browsertests.cc",
diff --git a/chrome/test/base/testing_profile_manager.cc b/chrome/test/base/testing_profile_manager.cc
index 2a1466f5..e06a877 100644
--- a/chrome/test/base/testing_profile_manager.cc
+++ b/chrome/test/base/testing_profile_manager.cc
@@ -79,11 +79,10 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   if (profile_name != chrome::kInitialProfile &&
       profile_name != chrome::kLockScreenProfile &&
-      profile_name != chromeos::ProfileHelper::GetLockScreenAppProfileName()) {
+      profile_name != ash::ProfileHelper::GetLockScreenAppProfileName()) {
     profile_path =
-        profile_path.Append(chromeos::ProfileHelper::Get()->GetUserProfileDir(
-            chromeos::ProfileHelper::GetUserIdHashByUserIdForTesting(
-                profile_name)));
+        profile_path.Append(ash::ProfileHelper::Get()->GetUserProfileDir(
+            ash::ProfileHelper::GetUserIdHashByUserIdForTesting(profile_name)));
   } else {
     profile_path = profile_path.AppendASCII(profile_name);
   }
diff --git a/chrome/test/data/extensions/webui/sanity_check_available_apis.js b/chrome/test/data/extensions/webui/sanity_check_available_apis.js
index 3ef7e93..eacc896 100644
--- a/chrome/test/data/extensions/webui/sanity_check_available_apis.js
+++ b/chrome/test/data/extensions/webui/sanity_check_available_apis.js
@@ -23,6 +23,7 @@
   'runtime',
   'send',
   'test',
+  'timeTicks'
 ];
 var actual = Object.keys(chrome).sort();
 
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index 32f3f7a..6ef0cfa 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -13,6 +13,7 @@
 import("//third_party/closure_compiler/compile_js.gni")
 import("//tools/grit/grit_rule.gni")
 import("//tools/typescript/ts_definitions.gni")
+import("//tools/typescript/ts_library.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
 import("//ui/webui/webui_features.gni")
 
@@ -76,6 +77,7 @@
       "assertions.js",
       "async_gen.js",
       "bookmarks/bookmarks_browsertest.js",
+      "chrome_timeticks_browsertest.js",
       "cr_components/cr_components_browsertest.js",
       "cr_elements/cr_elements_browsertest.js",
       "download_shelf/download_shelf_browsertest.js",
@@ -618,6 +620,7 @@
 
   deps = [
     ":build_chai_grdp",
+    ":build_ts",
     ":build_web_ui_test_mojo_grdp",
     "bookmarks:build_grdp",
     "cr_components:build_grdp",
@@ -666,6 +669,8 @@
     grdp_files +=
         [ "$target_gen_dir/chromeos/personalization_app/resources.grdp" ]
   }
+
+  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
 }
 
 # TypeScript related targets
@@ -697,3 +702,19 @@
     "//ui/webui/resources:generate_definitions",
   ]
 }
+
+ts_library("build_ts") {
+  root_dir = "."
+  out_dir = "$target_gen_dir/tsc"
+  composite = true
+  tsconfig_base = "tsconfig_base.json"
+  path_mappings = [ "chrome://webui-test/*|" +
+                    rebase_path("$root_gen_dir/chrome/test/data/webui/tsc/*",
+                                target_gen_dir) ]
+  in_files = [ "chrome_timeticks_test.ts" ]
+  extra_deps = [ ":generate_definitions" ]
+  definitions = [
+    "//tools/typescript/definitions/chrome_send.d.ts",
+    "//tools/typescript/definitions/chrome_timeticks.d.ts",
+  ]
+}
diff --git a/chrome/test/data/webui/chrome_timeticks_browsertest.cc b/chrome/test/data/webui/chrome_timeticks_browsertest.cc
new file mode 100644
index 0000000..cf180143
--- /dev/null
+++ b/chrome/test/data/webui/chrome_timeticks_browsertest.cc
@@ -0,0 +1,48 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/test/data/webui/chrome_timeticks_browsertest.h"
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/values.h"
+#include "content/public/browser/web_ui.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using content::WebUIMessageHandler;
+
+ChromeTimeTicksBrowserTest::ChromeTimeTicksBrowserTest() = default;
+
+ChromeTimeTicksBrowserTest::~ChromeTimeTicksBrowserTest() = default;
+
+ChromeTimeTicksBrowserTest::ChromeTimeTicksWebUIMessageHandler::
+    ChromeTimeTicksWebUIMessageHandler() = default;
+
+ChromeTimeTicksBrowserTest::ChromeTimeTicksWebUIMessageHandler::
+    ~ChromeTimeTicksWebUIMessageHandler() = default;
+
+void ChromeTimeTicksBrowserTest::ChromeTimeTicksWebUIMessageHandler::
+    RegisterMessages() {
+  web_ui()->RegisterMessageCallback(
+      "checkTimeticks",
+      base::BindRepeating(
+          &ChromeTimeTicksWebUIMessageHandler::HandleCheckTimeTicks,
+          weak_ptr_factory_.GetWeakPtr()));
+}
+
+void ChromeTimeTicksBrowserTest::ChromeTimeTicksWebUIMessageHandler::
+    HandleCheckTimeTicks(base::Value::ConstListView args) {
+  int64_t timeTicks_in_us;
+  EXPECT_TRUE(base::StringToInt64(args[0].GetString(), &timeTicks_in_us));
+  // Renderer's chrome.timeTicks.nowInMicroseconds() should be close to
+  // browser's base::TimeTicks::Now().
+  EXPECT_LE(base::TimeTicks::Now().since_origin() -
+                base::Microseconds(timeTicks_in_us),
+            base::Milliseconds(100));
+}
+
+WebUIMessageHandler* ChromeTimeTicksBrowserTest::GetMockMessageHandler() {
+  return &message_handler_;
+}
diff --git a/chrome/test/data/webui/chrome_timeticks_browsertest.h b/chrome/test/data/webui/chrome_timeticks_browsertest.h
new file mode 100644
index 0000000..6d35e61
--- /dev/null
+++ b/chrome/test/data/webui/chrome_timeticks_browsertest.h
@@ -0,0 +1,47 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_TEST_DATA_WEBUI_CHROME_TIMETICKS_BROWSERTEST_H_
+#define CHROME_TEST_DATA_WEBUI_CHROME_TIMETICKS_BROWSERTEST_H_
+
+#include "base/memory/weak_ptr.h"
+#include "chrome/test/base/web_ui_browser_test.h"
+#include "content/public/browser/web_ui_message_handler.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+// Test fixture for testing if chrome.timeTicks.nowInMicroseconds() is close
+// to base::TimeTicks::Now().
+class ChromeTimeTicksBrowserTest : public WebUIBrowserTest {
+ public:
+  ChromeTimeTicksBrowserTest();
+
+  ChromeTimeTicksBrowserTest(const ChromeTimeTicksBrowserTest&) = delete;
+  ChromeTimeTicksBrowserTest& operator=(const ChromeTimeTicksBrowserTest&) =
+      delete;
+
+  ~ChromeTimeTicksBrowserTest() override;
+
+  class ChromeTimeTicksWebUIMessageHandler
+      : public content::WebUIMessageHandler {
+   public:
+    ChromeTimeTicksWebUIMessageHandler();
+    ~ChromeTimeTicksWebUIMessageHandler() override;
+
+    void HandleCheckTimeTicks(base::Value::ConstListView args);
+
+   private:
+    void RegisterMessages() override;
+
+    base::WeakPtrFactory<ChromeTimeTicksWebUIMessageHandler> weak_ptr_factory_{
+        this};
+  };
+
+ protected:
+  ChromeTimeTicksWebUIMessageHandler message_handler_;
+
+ private:
+  content::WebUIMessageHandler* GetMockMessageHandler() override;
+};
+
+#endif  // CHROME_TEST_DATA_WEBUI_CHROME_TIMETICKS_BROWSERTEST_H_
diff --git a/chrome/test/data/webui/chrome_timeticks_browsertest.js b/chrome/test/data/webui/chrome_timeticks_browsertest.js
new file mode 100644
index 0000000..0a563ae0
--- /dev/null
+++ b/chrome/test/data/webui/chrome_timeticks_browsertest.js
@@ -0,0 +1,40 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview Tests to ensure that chrome.timeticks.nowInMicroseconds()
+ * is close to C++ base::TimeTicks::Now().
+ */
+
+GEN('#include "chrome/test/data/webui/chrome_timeticks_browsertest.h"');
+GEN('#include "content/public/test/browser_test.h"');
+
+/* eslint-disable no-var */
+
+/** Test fixture for chrome.timeTicks WebUI testing. */
+var ChromeTimeTicksBrowserTest = class extends testing.Test {
+  /** @override */
+  get typedefCppFixture() {
+    return 'ChromeTimeTicksBrowserTest';
+  }
+
+  /** @override */
+  get browsePreload() {
+    return 'chrome://dummyurl';
+  }
+
+  /** @override */
+  get webuiHost() {
+    return 'dummyurl';
+  }
+
+  /** @override */
+  get browsePreload() {
+    return 'chrome://test/test_loader.html?module=chrome_timeticks_test.js&host=webui-test';
+  }
+};
+
+TEST_F('ChromeTimeTicksBrowserTest', 'All', function() {
+  mocha.run();
+});
\ No newline at end of file
diff --git a/chrome/test/data/webui/chrome_timeticks_test.ts b/chrome/test/data/webui/chrome_timeticks_test.ts
new file mode 100644
index 0000000..fdaa7da
--- /dev/null
+++ b/chrome/test/data/webui/chrome_timeticks_test.ts
@@ -0,0 +1,14 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {assertEquals} from 'chrome://webui-test/chai_assert.js';
+
+suite('ChromeTimeTicksTest', () => {
+  test('NowIsBigInt', () => {
+    const now = chrome.timeTicks.nowInMicroseconds();
+    assertEquals(typeof now, 'bigint');
+    // chrome.send() doesn't not support passing BigInt, so we use String.
+    chrome.send('checkTimeticks', [now.toString()]);
+  });
+});
\ No newline at end of file
diff --git a/chrome/test/data/webui/chromeos/personalization_app/personalization_main_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/personalization_main_element_test.ts
index 9be7815..4c949eba 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/personalization_main_element_test.ts
+++ b/chrome/test/data/webui/chromeos/personalization_app/personalization_main_element_test.ts
@@ -3,8 +3,8 @@
 // found in the LICENSE file.
 
 import {PersonalizationMain} from 'chrome://personalization/trusted/personalization_main_element.js';
-
-import {assertEquals} from 'chrome://webui-test/chai_assert.js';
+import {Paths, PersonalizationRouter} from 'chrome://personalization/trusted/personalization_router_element.js';
+import {assertDeepEquals, assertEquals} from 'chrome://webui-test/chai_assert.js';
 
 import {initElement, teardownElement} from './personalization_app_test_utils.js';
 
@@ -24,4 +24,26 @@
         'Personalization',
         personalizationMainElement.shadowRoot!.querySelector('h1')!.innerText);
   });
+
+  test('links to user subpage', async () => {
+    personalizationMainElement = initElement(PersonalizationMain);
+    const original = PersonalizationRouter.instance;
+    const goToRoutePromise = new Promise<[Paths, Object]>(resolve => {
+      PersonalizationRouter.instance = () => {
+        return {
+          goToRoute(path: Paths, queryParams: Object = {}) {
+            resolve([path, queryParams]);
+            PersonalizationRouter.instance = original;
+          }
+        } as PersonalizationRouter;
+      };
+    });
+    const userSubpageLink =
+        personalizationMainElement!.shadowRoot!.getElementById(
+            'userSubpageLink')!;
+    userSubpageLink.click();
+    const [path, queryParams] = await goToRoutePromise;
+    assertEquals(Paths.User, path);
+    assertDeepEquals({}, queryParams);
+  });
 }
diff --git a/chrome/test/data/webui/chromeos/shimless_rma/onboarding_network_page_test.js b/chrome/test/data/webui/chromeos/shimless_rma/onboarding_network_page_test.js
index 5b0fed6c..0bb66de5 100644
--- a/chrome/test/data/webui/chromeos/shimless_rma/onboarding_network_page_test.js
+++ b/chrome/test/data/webui/chromeos/shimless_rma/onboarding_network_page_test.js
@@ -43,7 +43,7 @@
   /**
    * @return {!Promise}
    */
-  function initializeChooseDestinationPage() {
+  function initializeOnboardingNetworkPage() {
     assertFalse(!!component);
 
     component = /** @type {!OnboardingNetworkPage} */ (
@@ -71,7 +71,7 @@
   }
 
   test('ComponentRenders', async () => {
-    await initializeChooseDestinationPage();
+    await initializeOnboardingNetworkPage();
     assertTrue(!!component);
 
     const networkList = component.shadowRoot.querySelector('#networkList');
@@ -81,7 +81,7 @@
 
   test('PopulatesNetworkList', async () => {
     networkConfigService.addNetworksForTest(fakeNetworks);
-    await initializeChooseDestinationPage();
+    await initializeOnboardingNetworkPage();
 
     const networkList = component.shadowRoot.querySelector('#networkList');
     assertTrue(!!networkList);
@@ -91,7 +91,7 @@
 
   test('NetworkSelectionDialog', async () => {
     networkConfigService.addNetworksForTest(fakeNetworks);
-    await initializeChooseDestinationPage();
+    await initializeOnboardingNetworkPage();
 
     const networkList = component.shadowRoot.querySelector('#networkList');
     component.onNetworkSelected_({detail: networkList.networks[1]});
@@ -108,7 +108,7 @@
 
   test('DialogConnectButtonBindsToDialog', async () => {
     networkConfigService.addNetworksForTest(fakeNetworks);
-    await initializeChooseDestinationPage();
+    await initializeOnboardingNetworkPage();
     await openNetworkConfigDialog();
 
     const connectButton = /** @type {!CrDialogElement} */ (
@@ -124,7 +124,7 @@
 
   test('DialogCloses', async () => {
     networkConfigService.addNetworksForTest(fakeNetworks);
-    await initializeChooseDestinationPage();
+    await initializeOnboardingNetworkPage();
 
     const dialog = /** @type {!CrDialogElement} */ (
         component.shadowRoot.querySelector('#dialog'));
@@ -166,4 +166,13 @@
     await flushTasks();
     assertEquals('nextButtonLabel', buttonLabelKey);
   });
+
+  test('DisableNetworkList', async () => {
+    await initializeOnboardingNetworkPage();
+
+    const networkList = component.shadowRoot.querySelector('#networkList');
+    assertEquals(undefined, networkList.disabled);
+    component.allButtonsDisabled = true;
+    assertTrue(networkList.disabled);
+  });
 }
diff --git a/chrome/test/data/webui/chromeos/shimless_rma/wrapup_finalize_page_test.js b/chrome/test/data/webui/chromeos/shimless_rma/wrapup_finalize_page_test.js
index 3be7649f..8c8f459 100644
--- a/chrome/test/data/webui/chromeos/shimless_rma/wrapup_finalize_page_test.js
+++ b/chrome/test/data/webui/chromeos/shimless_rma/wrapup_finalize_page_test.js
@@ -150,4 +150,14 @@
     await flushTasks();
     assertEquals(1, callCount);
   });
+
+  test('FinalizationRetryButtonDisabled', async () => {
+    await initializeFinalizePage();
+
+    const retryButton =
+        component.shadowRoot.querySelector('#retryFinalizationButton');
+    assertFalse(retryButton.disabled);
+    component.allButtonsDisabled = true;
+    assertTrue(retryButton.disabled);
+  });
 }
diff --git a/chrome/test/data/webui/settings/chromeos/os_bluetooth_device_detail_subpage_tests.js b/chrome/test/data/webui/settings/chromeos/os_bluetooth_device_detail_subpage_tests.js
index eef514f..6955cf0 100644
--- a/chrome/test/data/webui/settings/chromeos/os_bluetooth_device_detail_subpage_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/os_bluetooth_device_detail_subpage_tests.js
@@ -99,7 +99,7 @@
         bluetoothConfig.appendToPairedDeviceList([device1]);
         await flushAsync();
 
-        const params = new URLSearchParams();
+        let params = new URLSearchParams();
         params.append('id', id);
         settings.Router.getInstance().navigateTo(
             settings.routes.BLUETOOTH_DEVICE_DETAIL, params);
@@ -113,8 +113,11 @@
         await flushAsync();
         assertTrue(!!getConnectionFailedText());
 
-        settings.Router.getInstance().navigateToPreviousRoute();
-        await windowPopstatePromise;
+        params = new URLSearchParams();
+        params.append('id', id);
+        settings.Router.getInstance().navigateTo(
+            settings.routes.BLUETOOTH_DEVICE_DETAIL, params);
+        await flushAsync();
         assertFalse(!!getConnectionFailedText());
       });
 
@@ -183,12 +186,13 @@
     assertFalse(!!getChangeMouseSettings());
     assertFalse(!!getChangeKeyboardSettings());
 
-    let params = new URLSearchParams();
+    const params = new URLSearchParams();
     params.append('id', '12//345&6789');
     settings.Router.getInstance().navigateTo(
         settings.routes.BLUETOOTH_DEVICE_DETAIL, params);
 
     await flushAsync();
+    assertTrue(bluetoothDeviceDetailPage.getIsDeviceConnectedForTest());
     assertTrue(!!getChangeMouseSettings());
     assertFalse(!!getChangeKeyboardSettings());
     assertEquals(
@@ -196,6 +200,18 @@
             'bluetoothDeviceDetailChangeDeviceSettingsMouse'),
         getChangeMouseSettings().label);
 
+    device1.deviceProperties.connectionState =
+        mojom.DeviceConnectionState.kNotConnected;
+    bluetoothConfig.updatePairedDevice(device1);
+    await flushAsync();
+    assertFalse(!!getChangeMouseSettings());
+
+    device1.deviceProperties.connectionState =
+        mojom.DeviceConnectionState.kConnected;
+    bluetoothConfig.updatePairedDevice(device1);
+    await flushAsync();
+    assertTrue(!!getChangeMouseSettings());
+
     getChangeMouseSettings().click();
     await flushAsync();
 
@@ -211,6 +227,7 @@
     settings.Router.getInstance().navigateToPreviousRoute();
     await windowPopstatePromise;
 
+    assertTrue(bluetoothDeviceDetailPage.getIsDeviceConnectedForTest());
     // Check that |#changeMouseSettings| has been focused.
     assertEquals(
         getChangeMouseSettings(),
@@ -218,17 +235,23 @@
 
     device1.deviceProperties.deviceType = mojom.DeviceType.kKeyboard;
     bluetoothConfig.updatePairedDevice(device1);
-    await flushAsync();
-
-    params = new URLSearchParams();
-    params.append('id', '12//345&6789');
-    settings.Router.getInstance().navigateTo(
-        settings.routes.BLUETOOTH_DEVICE_DETAIL, params);
 
     await flushAsync();
     assertFalse(!!getChangeMouseSettings());
     assertTrue(!!getChangeKeyboardSettings());
 
+    device1.deviceProperties.connectionState =
+        mojom.DeviceConnectionState.kNotConnected;
+    bluetoothConfig.updatePairedDevice(device1);
+    await flushAsync();
+    assertFalse(!!getChangeKeyboardSettings());
+
+    device1.deviceProperties.connectionState =
+        mojom.DeviceConnectionState.kConnected;
+    bluetoothConfig.updatePairedDevice(device1);
+    await flushAsync();
+    assertTrue(!!getChangeKeyboardSettings());
+
     getChangeKeyboardSettings().click();
     await flushAsync();
 
@@ -244,6 +267,7 @@
     settings.Router.getInstance().navigateToPreviousRoute();
     await windowPopstatePromise;
 
+    assertTrue(bluetoothDeviceDetailPage.getIsDeviceConnectedForTest());
     // Check that |#changeKeyboardSettings| has been focused.
     assertEquals(
         getChangeKeyboardSettings(),
diff --git a/chrome/test/data/webui/tsconfig_base.json b/chrome/test/data/webui/tsconfig_base.json
new file mode 100644
index 0000000..cd9af8c9
--- /dev/null
+++ b/chrome/test/data/webui/tsconfig_base.json
@@ -0,0 +1,8 @@
+{
+  "extends": "../../../../tools/typescript/tsconfig_base.json",
+  "compilerOptions": {
+    "typeRoots": [
+        "./../../../../third_party/node/node_modules/@types"
+    ]
+  }
+}
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 577282a..86109c79 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-14451.0.0
\ No newline at end of file
+14452.0.0
\ No newline at end of file
diff --git a/chromeos/cryptohome/cryptohome_parameters.cc b/chromeos/cryptohome/cryptohome_parameters.cc
index 79f4632b..e343342d 100644
--- a/chromeos/cryptohome/cryptohome_parameters.cc
+++ b/chromeos/cryptohome/cryptohome_parameters.cc
@@ -9,6 +9,7 @@
 
 #include <memory>
 
+#include "base/memory/values_equivalent.h"
 #include "base/notreached.h"
 #include "chromeos/dbus/cryptohome/key.pb.h"
 #include "components/account_id/account_id.h"
@@ -136,15 +137,8 @@
 KeyDefinition::ProviderData::~ProviderData() = default;
 
 bool KeyDefinition::ProviderData::operator==(const ProviderData& other) const {
-  const bool has_number = number != nullptr;
-  const bool other_has_number = other.number != nullptr;
-  const bool has_bytes = bytes != nullptr;
-  const bool other_has_bytes = other.bytes != nullptr;
-  return name == other.name &&
-         has_number == other_has_number &&
-         has_bytes == other_has_bytes &&
-         (!has_number || (*number == *other.number)) &&
-         (!has_bytes || (*bytes == *other.bytes));
+  return name == other.name && base::ValuesEquivalent(number, other.number) &&
+         base::ValuesEquivalent(bytes, other.bytes);
 }
 
 bool KeyDefinition::Policy::operator==(const Policy& other) const {
diff --git a/components/download/internal/background_service/test/entry_utils.cc b/components/download/internal/background_service/test/entry_utils.cc
index 47b99ce..5ca9d2b4 100644
--- a/components/download/internal/background_service/test/entry_utils.cc
+++ b/components/download/internal/background_service/test/entry_utils.cc
@@ -5,6 +5,7 @@
 #include <algorithm>
 
 #include "base/guid.h"
+#include "base/memory/values_equivalent.h"
 #include "components/download/internal/background_service/test/entry_utils.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 
@@ -12,10 +13,7 @@
 namespace test {
 
 bool CompareEntry(const Entry* const& expected, const Entry* const& actual) {
-  if (expected == nullptr || actual == nullptr)
-    return expected == actual;
-
-  return *expected == *actual;
+  return base::ValuesEquivalent(expected, actual);
 }
 
 bool CompareEntryList(const std::vector<Entry*>& expected,
diff --git a/components/download/internal/common/download_response_handler.cc b/components/download/internal/common/download_response_handler.cc
index d42b4ea8e..6d6e070 100644
--- a/components/download/internal/common/download_response_handler.cc
+++ b/components/download/internal/common/download_response_handler.cc
@@ -173,8 +173,7 @@
     return;
   }
 
-  if (!first_origin_.IsSameOriginWith(
-          url::Origin::Create(redirect_info.new_url))) {
+  if (!first_origin_.IsSameOriginWith(redirect_info.new_url)) {
     // Cross-origin redirect.
     switch (cross_origin_redirects_) {
       case network::mojom::RedirectMode::kFollow:
diff --git a/components/embedder_support/android/util/android_stream_reader_url_loader.cc b/components/embedder_support/android/util/android_stream_reader_url_loader.cc
index d8d0dd8b..cef5ac3a 100644
--- a/components/embedder_support/android/util/android_stream_reader_url_loader.cc
+++ b/components/embedder_support/android/util/android_stream_reader_url_loader.cc
@@ -130,7 +130,7 @@
         security_options->disable_web_security ||
         (security_options->allow_cors_to_same_scheme &&
          resource_request.request_initiator->IsSameOriginWith(
-             url::Origin::Create(resource_request_.url)));
+             resource_request_.url));
     reject_cors_request_ = true;
   }
   response_head_->response_type = network::cors::CalculateResponseType(
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc
index 0ceca0e..3505a64 100644
--- a/components/omnibox/browser/omnibox_field_trial.cc
+++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -606,6 +606,10 @@
   return base::FeatureList::IsEnabled(omnibox::kOmniboxTabSwitchSuggestions);
 }
 
+bool OmniboxFieldTrial::IsFuzzyUrlSuggestionsEnabled() {
+  return base::FeatureList::IsEnabled(omnibox::kOmniboxFuzzyUrlSuggestions);
+}
+
 bool OmniboxFieldTrial::IsPedalsAndroidBatch1Enabled() {
   return base::FeatureList::IsEnabled(omnibox::kOmniboxPedalsAndroidBatch1);
 }
diff --git a/components/omnibox/browser/omnibox_field_trial.h b/components/omnibox/browser/omnibox_field_trial.h
index dbefbed4..c54c114 100644
--- a/components/omnibox/browser/omnibox_field_trial.h
+++ b/components/omnibox/browser/omnibox_field_trial.h
@@ -356,6 +356,9 @@
 // Returns true if the tab switch suggestions flag is enabled.
 bool IsTabSwitchSuggestionsEnabled();
 
+// Returns true if the fuzzy URL suggestions feature is enabled.
+bool IsFuzzyUrlSuggestionsEnabled();
+
 // Returns true if the first batch of Pedals on Android is enabled.
 bool IsPedalsAndroidBatch1Enabled();
 
diff --git a/components/omnibox/common/omnibox_features.cc b/components/omnibox/common/omnibox_features.cc
index e6bc0be..88673cc7 100644
--- a/components/omnibox/common/omnibox_features.cc
+++ b/components/omnibox/common/omnibox_features.cc
@@ -272,6 +272,10 @@
 const base::Feature kNtpRealboxTailSuggest{"NtpRealboxTailSuggest",
                                            base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Feature used to enable URL suggestions for inputs that may contain typos.
+const base::Feature kOmniboxFuzzyUrlSuggestions{
+    "OmniboxFuzzyUrlSuggestions", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Feature used to enable the first batch of Pedals on Android. The Pedals,
 // which will be enabled on Android, should be already enabled on desktop.
 const base::Feature kOmniboxPedalsAndroidBatch1{
diff --git a/components/omnibox/common/omnibox_features.h b/components/omnibox/common/omnibox_features.h
index d92ec55..fd8b3bc 100644
--- a/components/omnibox/common/omnibox_features.h
+++ b/components/omnibox/common/omnibox_features.h
@@ -74,6 +74,7 @@
 extern const base::Feature kNtpRealboxPedals;
 extern const base::Feature kNtpRealboxSuggestionAnswers;
 extern const base::Feature kNtpRealboxTailSuggest;
+extern const base::Feature kOmniboxFuzzyUrlSuggestions;
 extern const base::Feature kOmniboxPedalsAndroidBatch1;
 extern const base::Feature kOmniboxPedalsBatch2NonEnglish;
 extern const base::Feature kOmniboxPedalsBatch3;
diff --git a/components/on_load_script_injector/browser/on_load_script_injector_host.cc b/components/on_load_script_injector/browser/on_load_script_injector_host.cc
index 20277371..8936e4e 100644
--- a/components/on_load_script_injector/browser/on_load_script_injector_host.cc
+++ b/components/on_load_script_injector/browser/on_load_script_injector_host.cc
@@ -113,14 +113,12 @@
 bool OnLoadScriptInjectorHost<ScriptId>::IsUrlMatchedByOriginList(
     const GURL& url,
     const std::vector<url::Origin>& allowed_origins) {
-  url::Origin url_origin = url::Origin::Create(url);
-
   for (const url::Origin& allowed_origin : allowed_origins) {
     if (allowed_origin == kMatchAllOrigins)
       return true;
 
     DCHECK(!allowed_origin.opaque());
-    if (url_origin.IsSameOriginWith(allowed_origin))
+    if (allowed_origin.IsSameOriginWith(url))
       return true;
   }
 
diff --git a/components/payments/content/manifest_verifier.cc b/components/payments/content/manifest_verifier.cc
index 300fd9e..69c9754 100644
--- a/components/payments/content/manifest_verifier.cc
+++ b/components/payments/content/manifest_verifier.cc
@@ -104,10 +104,7 @@
       }
 
       // Same origin payment methods are always allowed.
-      url::Origin app_origin =
-          url::Origin::Create(app.second->scope.DeprecatedGetOriginAsURL());
-      if (url::Origin::Create(method_manifest_url.DeprecatedGetOriginAsURL())
-              .IsSameOriginWith(app_origin)) {
+      if (url::IsSameOriginWith(app.second->scope, method_manifest_url)) {
         verified_method_names.emplace_back(method);
         app.second->has_explicitly_verified_methods = true;
         continue;
diff --git a/components/payments/core/payment_details.cc b/components/payments/core/payment_details.cc
index 625908c6..8fa8d27 100644
--- a/components/payments/core/payment_details.cc
+++ b/components/payments/core/payment_details.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 
+#include "base/memory/values_equivalent.h"
 #include "base/values.h"
 
 namespace payments {
@@ -51,9 +52,7 @@
 }
 
 bool PaymentDetails::operator==(const PaymentDetails& other) const {
-  return id == other.id &&
-         ((!total && !other.total) ||
-          (total && other.total && *total == *other.total)) &&
+  return id == other.id && base::ValuesEquivalent(total, other.total) &&
          display_items == other.display_items &&
          shipping_options == other.shipping_options &&
          modifiers == other.modifiers && error == other.error;
diff --git a/components/payments/core/payment_details_modifier.cc b/components/payments/core/payment_details_modifier.cc
index 3d1105e..e7527a06 100644
--- a/components/payments/core/payment_details_modifier.cc
+++ b/components/payments/core/payment_details_modifier.cc
@@ -4,6 +4,7 @@
 
 #include "components/payments/core/payment_details_modifier.h"
 
+#include "base/memory/values_equivalent.h"
 #include "base/values.h"
 
 namespace payments {
@@ -44,8 +45,7 @@
 bool PaymentDetailsModifier::operator==(
     const PaymentDetailsModifier& other) const {
   return method_data == other.method_data &&
-         ((!total && !other.total) ||
-          (total && other.total && *total == *other.total)) &&
+         base::ValuesEquivalent(total, other.total) &&
          additional_display_items == other.additional_display_items;
 }
 
diff --git a/components/permissions/permission_context_base.cc b/components/permissions/permission_context_base.cc
index 57841d9..9383e61 100644
--- a/components/permissions/permission_context_base.cc
+++ b/components/permissions/permission_context_base.cc
@@ -293,8 +293,7 @@
       const GURL loaded_url = entry->GetURL();
       if (virtual_url.SchemeIsHTTPOrHTTPS() &&
           loaded_url.SchemeIsHTTPOrHTTPS() &&
-          !url::Origin::Create(virtual_url)
-               .IsSameOriginWith(url::Origin::Create(loaded_url))) {
+          !url::IsSameOriginWith(virtual_url, loaded_url)) {
         return PermissionResult(
             CONTENT_SETTING_BLOCK,
             PermissionStatusSource::VIRTUAL_URL_DIFFERENT_ORIGIN);
diff --git a/components/permissions/permission_request_manager.cc b/components/permissions/permission_request_manager.cc
index 63af2c42..952c7e5 100644
--- a/components/permissions/permission_request_manager.cc
+++ b/components/permissions/permission_request_manager.cc
@@ -203,8 +203,7 @@
   const GURL& main_frame_origin =
       PermissionUtil::GetLastCommittedOriginAsURL(web_contents());
   bool is_main_frame =
-      url::Origin::Create(main_frame_origin)
-          .IsSameOriginWith(url::Origin::Create(request->requesting_origin()));
+      url::IsSameOriginWith(main_frame_origin, request->requesting_origin());
 
   absl::optional<url::Origin> auto_approval_origin =
       PermissionsClient::Get()->GetAutoApprovalOrigin();
diff --git a/components/policy/core/common/policy_proto_decoders_unittest.cc b/components/policy/core/common/policy_proto_decoders_unittest.cc
index 7ae83406..afba91ee 100644
--- a/components/policy/core/common/policy_proto_decoders_unittest.cc
+++ b/components/policy/core/common/policy_proto_decoders_unittest.cc
@@ -4,18 +4,16 @@
 
 #include "components/policy/core/common/policy_proto_decoders.h"
 
+#include "base/strings/string_number_conversions.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
 #include "components/policy/core/common/cloud/test/policy_builder.h"
 #include "components/policy/core/common/policy_map.h"
 #include "components/policy/policy_constants.h"
+#include "components/strings/grit/components_strings.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace policy {
 
-namespace {
-const PolicyPerProfileFilter kFilter = PolicyPerProfileFilter::kAny;
-}
-
 class PolicyProtoDecodersTest : public testing::Test {
  public:
   PolicyMap policy_map_;
@@ -34,7 +32,7 @@
 
   DecodeProtoFields(user_policy_.payload(), external_data_manager_,
                     POLICY_SOURCE_CLOUD, POLICY_SCOPE_USER, &policy_map_,
-                    kFilter);
+                    PolicyPerProfileFilter::kAny);
 
   EXPECT_TRUE(expected_policy_map_.Equals(policy_map_));
 }
@@ -48,7 +46,7 @@
 
   DecodeProtoFields(user_policy_.payload(), external_data_manager_,
                     POLICY_SOURCE_CLOUD, POLICY_SCOPE_USER, &policy_map_,
-                    kFilter);
+                    PolicyPerProfileFilter::kAny);
 
   EXPECT_TRUE(expected_policy_map_.Equals(policy_map_));
 }
@@ -63,7 +61,7 @@
 
   DecodeProtoFields(user_policy_.payload(), external_data_manager_,
                     POLICY_SOURCE_CLOUD, POLICY_SCOPE_USER, &policy_map_,
-                    kFilter);
+                    PolicyPerProfileFilter::kAny);
 
   EXPECT_TRUE(expected_policy_map_.Equals(policy_map_));
 }
@@ -83,11 +81,179 @@
 
   DecodeProtoFields(user_policy_.payload(), external_data_manager_,
                     POLICY_SOURCE_CLOUD, POLICY_SCOPE_USER, &policy_map_,
-                    kFilter);
+                    PolicyPerProfileFilter::kAny);
 
   EXPECT_TRUE(expected_policy_map_.Equals(policy_map_));
 }
 
-// TODO(crbug.com/1278735): Add more tests cases for DecodeProtoFields
+TEST_F(PolicyProtoDecodersTest, PolicyWithOptionUnset) {
+  user_policy_.payload().mutable_searchsuggestenabled()->set_value(true);
+  user_policy_.payload()
+      .mutable_searchsuggestenabled()
+      ->mutable_policy_options()
+      ->set_mode(em::PolicyOptions::UNSET);
+
+  DecodeProtoFields(user_policy_.payload(), external_data_manager_,
+                    POLICY_SOURCE_CLOUD, POLICY_SCOPE_USER, &policy_map_,
+                    PolicyPerProfileFilter::kAny);
+
+  // Any values with PolicyOptions::UNSET will never set into policy_map_
+  EXPECT_TRUE(expected_policy_map_.Equals(policy_map_));
+}
+
+TEST_F(PolicyProtoDecodersTest, PolicyWithOptionRecommended) {
+  expected_policy_map_.Set(key::kSearchSuggestEnabled, POLICY_LEVEL_RECOMMENDED,
+                           POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
+                           base::Value(true), nullptr);
+
+  user_policy_.payload().mutable_searchsuggestenabled()->set_value(true);
+  user_policy_.payload()
+      .mutable_searchsuggestenabled()
+      ->mutable_policy_options()
+      ->set_mode(em::PolicyOptions::RECOMMENDED);
+
+  DecodeProtoFields(user_policy_.payload(), external_data_manager_,
+                    POLICY_SOURCE_CLOUD, POLICY_SCOPE_USER, &policy_map_,
+                    PolicyPerProfileFilter::kAny);
+
+  EXPECT_TRUE(expected_policy_map_.Equals(policy_map_));
+}
+
+TEST_F(PolicyProtoDecodersTest, IntegerPolicyWithValueLowerThanMinLimit) {
+  std::string too_small_value =
+      base::NumberToString(std::numeric_limits<int32_t>::min() - 1LL);
+
+  expected_policy_map_.Set(key::kIncognitoModeAvailability,
+                           POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+                           POLICY_SOURCE_CLOUD, base::Value(too_small_value),
+                           nullptr);
+  expected_policy_map_.AddMessage(
+      key::kIncognitoModeAvailability, PolicyMap::MessageType::kError,
+      IDS_POLICY_PROTO_PARSING_ERROR, {u"Number out of range - invalid int32"});
+
+  user_policy_.payload().mutable_incognitomodeavailability()->set_value(
+      std::numeric_limits<int32_t>::min() - 1LL);
+
+  DecodeProtoFields(user_policy_.payload(), external_data_manager_,
+                    POLICY_SOURCE_CLOUD, POLICY_SCOPE_USER, &policy_map_,
+                    PolicyPerProfileFilter::kAny);
+
+  EXPECT_TRUE(expected_policy_map_.Equals(policy_map_));
+}
+
+TEST_F(PolicyProtoDecodersTest, IntegerPolicyWithValueUpperThanMaxLimit) {
+  std::string too_big_value =
+      base::NumberToString(std::numeric_limits<int32_t>::max() + 1LL);
+
+  expected_policy_map_.Set(key::kIncognitoModeAvailability,
+                           POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+                           POLICY_SOURCE_CLOUD, base::Value(too_big_value),
+                           nullptr);
+  expected_policy_map_.AddMessage(
+      key::kIncognitoModeAvailability, PolicyMap::MessageType::kError,
+      IDS_POLICY_PROTO_PARSING_ERROR, {u"Number out of range - invalid int32"});
+
+  user_policy_.payload().mutable_incognitomodeavailability()->set_value(
+      std::numeric_limits<int32_t>::max() + 1LL);
+
+  DecodeProtoFields(user_policy_.payload(), external_data_manager_,
+                    POLICY_SOURCE_CLOUD, POLICY_SCOPE_USER, &policy_map_,
+                    PolicyPerProfileFilter::kAny);
+
+  EXPECT_TRUE(expected_policy_map_.Equals(policy_map_));
+}
+
+TEST_F(PolicyProtoDecodersTest, JsonPolicy) {
+  base::Value jsonPolicy(base::Value::Type::DICTIONARY);
+  jsonPolicy.SetKey("key", base::Value("value"));
+
+  expected_policy_map_.Set(key::kManagedBookmarks, POLICY_LEVEL_MANDATORY,
+                           POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
+                           std::move(jsonPolicy), nullptr);
+
+  std::string jsonPolicyStr = R"({
+    "key": "value"
+    })";
+  auto* disabled_managed_bookmarks_settings =
+      user_policy_.payload().mutable_managedbookmarks()->mutable_value();
+  disabled_managed_bookmarks_settings->append(jsonPolicyStr);
+
+  DecodeProtoFields(user_policy_.payload(), external_data_manager_,
+                    POLICY_SOURCE_CLOUD, POLICY_SCOPE_USER, &policy_map_,
+                    PolicyPerProfileFilter::kAny);
+
+  EXPECT_TRUE(expected_policy_map_.Equals(policy_map_));
+}
+
+TEST_F(PolicyProtoDecodersTest, InvalidJsonPolicy) {
+  std::string invalidDummyJson = R"({
+    "key": "value"
+  )";  // lacks a close brace
+
+  expected_policy_map_.Set(key::kManagedBookmarks, POLICY_LEVEL_MANDATORY,
+                           POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
+                           base::Value(invalidDummyJson), nullptr);
+  expected_policy_map_.AddMessage(
+      key::kManagedBookmarks, PolicyMap::MessageType::kError,
+      IDS_POLICY_PROTO_PARSING_ERROR, {u"Line: 3, column: 3, Syntax error."});
+
+  auto* disabled_managed_bookmarks_settings =
+      user_policy_.payload().mutable_managedbookmarks()->mutable_value();
+  disabled_managed_bookmarks_settings->append(invalidDummyJson);
+
+  DecodeProtoFields(user_policy_.payload(), external_data_manager_,
+                    POLICY_SOURCE_CLOUD, POLICY_SCOPE_USER, &policy_map_,
+                    PolicyPerProfileFilter::kAny);
+
+  EXPECT_TRUE(expected_policy_map_.Equals(policy_map_));
+}
+
+TEST_F(PolicyProtoDecodersTest, PolicyWithAnyFilter) {
+  expected_policy_map_.Set(key::kSearchSuggestEnabled, POLICY_LEVEL_MANDATORY,
+                           POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
+                           base::Value(true), nullptr);
+  expected_policy_map_.Set(key::kCloudReportingEnabled, POLICY_LEVEL_MANDATORY,
+                           POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
+                           base::Value(true), nullptr);
+
+  user_policy_.payload().mutable_searchsuggestenabled()->set_value(true);
+  user_policy_.payload().mutable_cloudreportingenabled()->set_value(true);
+
+  DecodeProtoFields(user_policy_.payload(), external_data_manager_,
+                    POLICY_SOURCE_CLOUD, POLICY_SCOPE_USER, &policy_map_,
+                    PolicyPerProfileFilter::kAny);
+
+  EXPECT_TRUE(expected_policy_map_.Equals(policy_map_));
+}
+
+TEST_F(PolicyProtoDecodersTest, PolicyWithTrueFilter) {
+  expected_policy_map_.Set(key::kSearchSuggestEnabled, POLICY_LEVEL_MANDATORY,
+                           POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
+                           base::Value(true), nullptr);
+
+  user_policy_.payload().mutable_searchsuggestenabled()->set_value(true);
+  user_policy_.payload().mutable_cloudreportingenabled()->set_value(true);
+
+  DecodeProtoFields(user_policy_.payload(), external_data_manager_,
+                    POLICY_SOURCE_CLOUD, POLICY_SCOPE_USER, &policy_map_,
+                    PolicyPerProfileFilter::kTrue);
+
+  EXPECT_TRUE(expected_policy_map_.Equals(policy_map_));
+}
+
+TEST_F(PolicyProtoDecodersTest, PolicyWithFalseFilter) {
+  expected_policy_map_.Set(key::kCloudReportingEnabled, POLICY_LEVEL_MANDATORY,
+                           POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
+                           base::Value(true), nullptr);
+
+  user_policy_.payload().mutable_searchsuggestenabled()->set_value(true);
+  user_policy_.payload().mutable_cloudreportingenabled()->set_value(true);
+
+  DecodeProtoFields(user_policy_.payload(), external_data_manager_,
+                    POLICY_SOURCE_CLOUD, POLICY_SCOPE_USER, &policy_map_,
+                    PolicyPerProfileFilter::kFalse);
+
+  EXPECT_TRUE(expected_policy_map_.Equals(policy_map_));
+}
 
 }  // namespace policy
diff --git a/components/prefs/mock_pref_change_callback.h b/components/prefs/mock_pref_change_callback.h
index 8541ee9..6227f8a 100644
--- a/components/prefs/mock_pref_change_callback.h
+++ b/components/prefs/mock_pref_change_callback.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/memory/raw_ptr.h"
+#include "base/memory/values_equivalent.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "components/prefs/pref_service.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -24,12 +25,7 @@
   if (!pref)
     return false;
 
-  const base::Value* actual_value = pref->GetValue();
-  if (!actual_value)
-    return value == NULL;
-  if (!value)
-    return actual_value == NULL;
-  return *value == *actual_value;
+  return base::ValuesEquivalent(value, pref->GetValue());
 }
 
 // A mock for testing preference notifications and easy setup of expectations.
diff --git a/components/sync/BUILD.gn b/components/sync/BUILD.gn
index e854b83e..74cee704 100644
--- a/components/sync/BUILD.gn
+++ b/components/sync/BUILD.gn
@@ -158,6 +158,7 @@
     "engine/cancelation_signal_unittest.cc",
     "engine/commit_contribution_impl_unittest.cc",
     "engine/commit_processor_unittest.cc",
+    "engine/cycle/commit_quota_unittest.cc",
     "engine/cycle/nudge_tracker_unittest.cc",
     "engine/cycle/status_controller_unittest.cc",
     "engine/cycle/sync_cycle_snapshot_unittest.cc",
diff --git a/components/sync/engine/BUILD.gn b/components/sync/engine/BUILD.gn
index 3c468be..1ede4ff 100644
--- a/components/sync/engine/BUILD.gn
+++ b/components/sync/engine/BUILD.gn
@@ -26,6 +26,8 @@
     "commit_util.cc",
     "commit_util.h",
     "configure_reason.h",
+    "cycle/commit_quota.cc",
+    "cycle/commit_quota.h",
     "cycle/data_type_tracker.cc",
     "cycle/data_type_tracker.h",
     "cycle/debug_info_getter.h",
diff --git a/components/sync/engine/cycle/commit_quota.cc b/components/sync/engine/cycle/commit_quota.cc
new file mode 100644
index 0000000..f02278169
--- /dev/null
+++ b/components/sync/engine/cycle/commit_quota.cc
@@ -0,0 +1,54 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/sync/engine/cycle/commit_quota.h"
+
+#include <algorithm>
+
+#include "base/time/time.h"
+
+namespace syncer {
+
+CommitQuota::CommitQuota(int initial_tokens, base::TimeDelta refill_interval)
+    : max_tokens_(initial_tokens),
+      refill_interval_(refill_interval),
+      tokens_(initial_tokens),
+      last_refilled_(base::TimeTicks::Now()) {
+  DCHECK_GT(refill_interval, base::TimeDelta());
+}
+
+CommitQuota::~CommitQuota() = default;
+
+bool CommitQuota::HasTokensAvailable() {
+  RefillTokens();
+  return tokens_ > 0;
+}
+
+void CommitQuota::ConsumeToken() {
+  RefillTokens();
+  if (tokens_ > 0) {
+    --tokens_;
+    return;
+  }
+
+  // When no token is available to consume, at least push away the next refill
+  // time to make sure any `HasTokensAvailable()` calls in the next
+  // `refill_interval_` period return false.
+  last_refilled_ = base::TimeTicks::Now();
+}
+
+void CommitQuota::RefillTokens() {
+  const base::TimeDelta since_last_refilled =
+      base::TimeTicks::Now() - last_refilled_;
+  const int new_tokens = since_last_refilled / refill_interval_;
+  if (new_tokens == 0) {
+    return;
+  }
+
+  tokens_ = std::min(tokens_ + new_tokens, max_tokens_);
+  last_refilled_ += new_tokens * refill_interval_;
+  DCHECK_GE(tokens_, 0);
+}
+
+}  // namespace syncer
diff --git a/components/sync/engine/cycle/commit_quota.h b/components/sync/engine/cycle/commit_quota.h
new file mode 100644
index 0000000..4136745
--- /dev/null
+++ b/components/sync/engine/cycle/commit_quota.h
@@ -0,0 +1,47 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SYNC_ENGINE_CYCLE_COMMIT_QUOTA_H_
+#define COMPONENTS_SYNC_ENGINE_CYCLE_COMMIT_QUOTA_H_
+
+#include "base/time/time.h"
+
+namespace syncer {
+
+// Tracks quota for commits with `initial_tokens` being also the maximum token
+// count. A token is refilled every `refill_interval` if below the maximum token
+// count. Tokens are consumed one by one by `ConsumeToken()` until they reach
+// the zero. When having zero tokens, calls to `ConsumeToken()` only reset the
+// refill "timer" (pushing away the next refill to happen after
+// `refill_interval` from now).
+class CommitQuota {
+ public:
+  CommitQuota(int initial_tokens, base::TimeDelta refill_interval);
+
+  CommitQuota(const CommitQuota&) = delete;
+  CommitQuota& operator=(const CommitQuota&) = delete;
+
+  ~CommitQuota();
+
+  // Returns whether the current token count is greater than zero.
+  bool HasTokensAvailable();
+
+  // Consumes a token. If the current token count is zero, it only resets the
+  // refill "timer".
+  void ConsumeToken();
+
+ private:
+  // Refills any tokens and updates `last_refilled_` time if possible.
+  void RefillTokens();
+
+  const int max_tokens_;
+  const base::TimeDelta refill_interval_;
+
+  int tokens_;
+  base::TimeTicks last_refilled_;
+};
+
+}  // namespace syncer
+
+#endif  // COMPONENTS_SYNC_ENGINE_CYCLE_COMMIT_QUOTA_H_
diff --git a/components/sync/engine/cycle/commit_quota_unittest.cc b/components/sync/engine/cycle/commit_quota_unittest.cc
new file mode 100644
index 0000000..3af9cad5
--- /dev/null
+++ b/components/sync/engine/cycle/commit_quota_unittest.cc
@@ -0,0 +1,97 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/sync/engine/cycle/commit_quota.h"
+
+#include "base/test/task_environment.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace syncer {
+namespace {
+
+class CommitQuotaTest : public ::testing::Test {
+ public:
+  CommitQuotaTest() = default;
+
+  void ConsumeTokensAndExpectDepleted(CommitQuota* quota, int n) {
+    while (n > 0) {
+      EXPECT_TRUE(quota->HasTokensAvailable());
+      quota->ConsumeToken();
+      --n;
+    }
+    EXPECT_FALSE(quota->HasTokensAvailable());
+  }
+
+ protected:
+  base::test::SingleThreadTaskEnvironment task_environment_{
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+};
+
+TEST_F(CommitQuotaTest, NoTokensAvailableWhenDepleted) {
+  CommitQuota quota(/*initial_tokens=*/2, /*refill_interval=*/base::Seconds(1));
+  ConsumeTokensAndExpectDepleted(&quota, 2);
+}
+
+TEST_F(CommitQuotaTest, TokensRefill) {
+  CommitQuota quota(/*initial_tokens=*/2, /*refill_interval=*/base::Seconds(1));
+  ConsumeTokensAndExpectDepleted(&quota, 2);
+
+  task_environment_.FastForwardBy(base::Milliseconds(1500));
+  ConsumeTokensAndExpectDepleted(&quota, 1);
+
+  task_environment_.FastForwardBy(base::Milliseconds(501));
+  ConsumeTokensAndExpectDepleted(&quota, 1);
+}
+
+TEST_F(CommitQuotaTest, TokensCannotGetBelowZero) {
+  CommitQuota quota(/*initial_tokens=*/2, /*refill_interval=*/base::Seconds(1));
+  ConsumeTokensAndExpectDepleted(&quota, 2);
+
+  // Try to consume another token. This has no effect.
+  quota.ConsumeToken();
+
+  // After one second, there's another token available.
+  task_environment_.FastForwardBy(base::Milliseconds(1001));
+  ConsumeTokensAndExpectDepleted(&quota, 1);
+}
+
+TEST_F(CommitQuotaTest, RefillPostponedWhenConsumingAtZero) {
+  CommitQuota quota(/*initial_tokens=*/2, /*refill_interval=*/base::Seconds(1));
+  ConsumeTokensAndExpectDepleted(&quota, 2);
+
+  // After half a second, there are still no tokens.
+  task_environment_.FastForwardBy(base::Milliseconds(501));
+  EXPECT_FALSE(quota.HasTokensAvailable());
+
+  // When consuming with zero tokens, the next refill gets postponed.
+  quota.ConsumeToken();
+  task_environment_.FastForwardBy(base::Milliseconds(501));
+  EXPECT_FALSE(quota.HasTokensAvailable());
+  task_environment_.FastForwardBy(base::Milliseconds(501));
+  ConsumeTokensAndExpectDepleted(&quota, 1);
+}
+
+TEST_F(CommitQuotaTest, TokensRefillUpToInitialTokens) {
+  CommitQuota quota(/*initial_tokens=*/2, /*refill_interval=*/base::Seconds(1));
+  ConsumeTokensAndExpectDepleted(&quota, 2);
+
+  task_environment_.FastForwardBy(base::Milliseconds(3001));
+  // Waiting longer does not help -- we still end up with initial tokens.
+  ConsumeTokensAndExpectDepleted(&quota, 2);
+}
+
+TEST_F(CommitQuotaTest, TokensStayAtInitialTokens) {
+  CommitQuota quota(/*initial_tokens=*/2, /*refill_interval=*/base::Seconds(1));
+  // The quota is full, waiting has no effect.
+  task_environment_.FastForwardBy(base::Days(1));
+  ConsumeTokensAndExpectDepleted(&quota, 2);
+
+  task_environment_.FastForwardBy(base::Milliseconds(1001));
+  // It also has no effect later, the quota does not fill up faster now.
+  ConsumeTokensAndExpectDepleted(&quota, 1);
+}
+
+}  // namespace
+}  // namespace syncer
diff --git a/components/sync/engine/cycle/data_type_tracker.cc b/components/sync/engine/cycle/data_type_tracker.cc
index f0e381b..7a66d61 100644
--- a/components/sync/engine/cycle/data_type_tracker.cc
+++ b/components/sync/engine/cycle/data_type_tracker.cc
@@ -5,12 +5,15 @@
 #include "components/sync/engine/cycle/data_type_tracker.h"
 
 #include <algorithm>
+#include <memory>
 #include <string>
 #include <utility>
 
 #include "base/check.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/notreached.h"
 #include "components/sync/engine/polling_constants.h"
+#include "components/sync/engine/sync_engine_switches.h"
 #include "components/sync/protocol/data_type_progress_marker.pb.h"
 
 namespace syncer {
@@ -26,9 +29,14 @@
 
 constexpr base::TimeDelta kDefaultLocalChangeNudgeDelayForSessions =
     base::Seconds(11);
+constexpr base::TimeDelta kDepletedQuotaNudgeDelayForExtensionTypes =
+    base::Seconds(100);
 
 const size_t kDefaultMaxPayloadsPerType = 10;
 
+constexpr base::TimeDelta kRefillIntervalForExtensionTypes = base::Seconds(100);
+constexpr int kInitialQuotaForExtensionTypes = 100;
+
 base::TimeDelta GetDefaultLocalChangeNudgeDelay(ModelType model_type) {
   switch (model_type) {
     case AUTOFILL:
@@ -87,6 +95,54 @@
   }
 }
 
+bool CanGetCommitsFromExtensions(ModelType model_type) {
+  switch (model_type) {
+    case BOOKMARKS:
+    case EXTENSION_SETTINGS:
+    case APP_SETTINGS:
+      // Only for the types above, extensions can trigger a commit via a js API.
+      return true;
+    case AUTOFILL:
+    case USER_EVENTS:
+    case SESSIONS:
+    case PREFERENCES:
+    case SHARING_MESSAGE:
+    case PASSWORDS:
+    case AUTOFILL_PROFILE:
+    case AUTOFILL_WALLET_DATA:
+    case AUTOFILL_WALLET_METADATA:
+    case AUTOFILL_WALLET_OFFER:
+    case THEMES:
+    case TYPED_URLS:
+    case EXTENSIONS:
+    case SEARCH_ENGINES:
+    case APPS:
+    case HISTORY_DELETE_DIRECTIVES:
+    case DICTIONARY:
+    case DEVICE_INFO:
+    case PRIORITY_PREFERENCES:
+    case SUPERVISED_USER_SETTINGS:
+    case APP_LIST:
+    case ARC_PACKAGE:
+    case PRINTERS:
+    case READING_LIST:
+    case USER_CONSENTS:
+    case SEND_TAB_TO_SELF:
+    case SECURITY_EVENTS:
+    case WIFI_CONFIGURATIONS:
+    case WEB_APPS:
+    case OS_PREFERENCES:
+    case OS_PRIORITY_PREFERENCES:
+    case WORKSPACE_DESK:
+    case NIGORI:
+    case PROXY_TABS:
+      return false;
+    case UNSPECIFIED:
+      NOTREACHED();
+      return false;
+  }
+}
+
 }  // namespace
 
 WaitInterval::WaitInterval() : mode(BlockingMode::kUnknown) {}
@@ -97,7 +153,8 @@
 WaitInterval::~WaitInterval() = default;
 
 DataTypeTracker::DataTypeTracker(ModelType type)
-    : local_nudge_count_(0),
+    : type_(type),
+      local_nudge_count_(0),
       local_refresh_request_count_(0),
       payload_buffer_size_(kDefaultMaxPayloadsPerType),
       initial_sync_required_(false),
@@ -105,6 +162,12 @@
       local_change_nudge_delay_(GetDefaultLocalChangeNudgeDelay(type)) {
   // Sanity check the hardcode value for kMinLocalChangeNudgeDelay.
   DCHECK_GE(local_change_nudge_delay_, kMinLocalChangeNudgeDelay);
+
+  if (CanGetCommitsFromExtensions(type) &&
+      base::FeatureList::IsEnabled(switches::kSyncExtensionTypesThrottling)) {
+    quota_ = std::make_unique<CommitQuota>(kInitialQuotaForExtensionTypes,
+                                           kRefillIntervalForExtensionTypes);
+  }
 }
 
 DataTypeTracker::~DataTypeTracker() = default;
@@ -182,6 +245,12 @@
   sync_required_to_resolve_conflict_ = true;
 }
 
+void DataTypeTracker::RecordSuccessfulCommitMessage() {
+  if (quota_) {
+    quota_->ConsumeToken();
+  }
+}
+
 void DataTypeTracker::RecordSuccessfulSyncCycle() {
   // If we were blocked, then we would have been excluded from this cycle's
   // GetUpdates and Commit actions.  Our state remains unchanged.
@@ -370,6 +439,11 @@
 }
 
 base::TimeDelta DataTypeTracker::GetLocalChangeNudgeDelay() const {
+  if (quota_ && !quota_->HasTokensAvailable()) {
+    base::UmaHistogramEnumeration("Sync.ModelTypeCommitWithDepletedQuota",
+                                  ModelTypeHistogramValue(type_));
+    return kDepletedQuotaNudgeDelayForExtensionTypes;
+  }
   return local_change_nudge_delay_;
 }
 
diff --git a/components/sync/engine/cycle/data_type_tracker.h b/components/sync/engine/cycle/data_type_tracker.h
index 4fbe309..1e03d67 100644
--- a/components/sync/engine/cycle/data_type_tracker.h
+++ b/components/sync/engine/cycle/data_type_tracker.h
@@ -13,6 +13,7 @@
 #include "base/time/time.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/base/sync_invalidation.h"
+#include "components/sync/engine/cycle/commit_quota.h"
 
 namespace sync_pb {
 class DataTypeProgressMarker;
@@ -73,6 +74,11 @@
   // resolve conflict locally.
   void RecordCommitConflict();
 
+  // Records that a commit message has been sent (note that each commit message
+  // may include multiple entities of this data type and each sync cycle may
+  // include an arbitrary number of commit messages).
+  void RecordSuccessfulCommitMessage();
+
   // Records that a sync cycle has been performed successfully.
   // Generally, this means that all local changes have been committed and all
   // remote changes have been downloaded, so we can clear any flags related to
@@ -163,6 +169,8 @@
  private:
   friend class SyncSchedulerImplTest;
 
+  const ModelType type_;
+
   // Number of local change nudges received for this type since the last
   // successful sync cycle.
   int local_nudge_count_;
@@ -201,6 +209,10 @@
   // The amount of time to delay a sync cycle by when a local change for this
   // type occurs.
   base::TimeDelta local_change_nudge_delay_;
+
+  // Quota for commits (used only for data types that can be committed by
+  // extensions).
+  std::unique_ptr<CommitQuota> quota_;
 };
 
 }  // namespace syncer
diff --git a/components/sync/engine/cycle/nudge_tracker.cc b/components/sync/engine/cycle/nudge_tracker.cc
index 6147f2c..04c479d 100644
--- a/components/sync/engine/cycle/nudge_tracker.cc
+++ b/components/sync/engine/cycle/nudge_tracker.cc
@@ -76,6 +76,14 @@
   return current_retry_time_ <= sync_cycle_start_time_;
 }
 
+void NudgeTracker::RecordSuccessfulCommitMessage(ModelTypeSet types) {
+  for (ModelType type : types) {
+    TypeTrackerMap::const_iterator tracker_it = type_trackers_.find(type);
+    DCHECK(tracker_it != type_trackers_.end()) << ModelTypeToString(type);
+    tracker_it->second->RecordSuccessfulCommitMessage();
+  }
+}
+
 void NudgeTracker::RecordSuccessfulSyncCycle(ModelTypeSet types) {
   // If a retry was required, we've just serviced it.  Unset the flag.
   if (IsRetryRequired()) {
diff --git a/components/sync/engine/cycle/nudge_tracker.h b/components/sync/engine/cycle/nudge_tracker.h
index 02635ef..2af5204 100644
--- a/components/sync/engine/cycle/nudge_tracker.h
+++ b/components/sync/engine/cycle/nudge_tracker.h
@@ -52,6 +52,10 @@
   // information on how this flag is maintained.
   bool IsRetryRequired() const;
 
+  // Tells this class that a commit message has been sent (note that each sync
+  // cycle may include an arbitrary number of commit messages).
+  void RecordSuccessfulCommitMessage(ModelTypeSet types);
+
   // Tells this class that all required update fetching or committing has
   // completed successfully, as the result of a "normal" sync cycle.
   void RecordSuccessfulSyncCycle(ModelTypeSet types);
diff --git a/components/sync/engine/sync_engine_switches.cc b/components/sync/engine/sync_engine_switches.cc
index ab75192a..f44732f3 100644
--- a/components/sync/engine/sync_engine_switches.cc
+++ b/components/sync/engine/sync_engine_switches.cc
@@ -20,4 +20,11 @@
 const base::FeatureParam<int> kMinGuResponsesToIgnoreKey{
     &kIgnoreSyncEncryptionKeysLongMissing, "MinGuResponsesToIgnoreKey", 50};
 
+// Causes the sync engine to count a quota for commits of data types that can
+// be committed by extension JS API. If the quota is depleted, an extra long
+// nudge delay is applied to that data type. As a result, more changes are
+// likely to get combined into one commit message.
+const base::Feature kSyncExtensionTypesThrottling{
+    "SyncExtensionTypesThrottling", base::FEATURE_DISABLED_BY_DEFAULT};
+
 }  // namespace switches
diff --git a/components/sync/engine/sync_engine_switches.h b/components/sync/engine/sync_engine_switches.h
index 76f86d3..59bafe3ca 100644
--- a/components/sync/engine/sync_engine_switches.h
+++ b/components/sync/engine/sync_engine_switches.h
@@ -15,6 +15,8 @@
 extern const base::Feature kIgnoreSyncEncryptionKeysLongMissing;
 extern const base::FeatureParam<int> kMinGuResponsesToIgnoreKey;
 
+extern const base::Feature kSyncExtensionTypesThrottling;
+
 }  // namespace switches
 
 #endif  // COMPONENTS_SYNC_ENGINE_SYNC_ENGINE_SWITCHES_H_
diff --git a/components/sync/engine/syncer.cc b/components/sync/engine/syncer.cc
index 61b570d7..94b3faf 100644
--- a/components/sync/engine/syncer.cc
+++ b/components/sync/engine/syncer.cc
@@ -169,6 +169,8 @@
     if (error.value() != SyncerError::SYNCER_OK) {
       return error;
     }
+    nudge_tracker->RecordSuccessfulCommitMessage(
+        commit->GetContributingDataTypes());
   }
 
   return SyncerError(SyncerError::SYNCER_OK);
diff --git a/components/translate/core/browser/translate_prefs_unittest.cc b/components/translate/core/browser/translate_prefs_unittest.cc
index 165d487d..12df712 100644
--- a/components/translate/core/browser/translate_prefs_unittest.cc
+++ b/components/translate/core/browser/translate_prefs_unittest.cc
@@ -1120,13 +1120,7 @@
   EXPECT_THAT(translate_prefs_->GetAlwaysTranslateLanguages(), IsEmpty());
 }
 
-// Failing on Android - crbug.com/1286360
-#if BUILDFLAG(IS_ANDROID)
-#define MAYBE_CanTranslateLanguage DISABLED_CanTranslateLanguage
-#else
-#define MAYBE_CanTranslateLanguage CanTranslateLanguage
-#endif
-TEST_F(TranslatePrefsTest, MAYBE_CanTranslateLanguage) {
+TEST_F(TranslatePrefsTest, CanTranslateLanguage) {
   prefs_.SetString(language::prefs::kAcceptLanguages, "en");
   TranslateDownloadManager::GetInstance()->set_application_locale("en");
 
@@ -1144,9 +1138,14 @@
   EXPECT_FALSE(translate_prefs_->CanTranslateLanguage(
       &translate_accept_languages, "en"));
 
-  if (!TranslatePrefs::IsDetailedLanguageSettingsEnabled()) {
-    // Blocked languages that are not in accept languages are not blocked.
-    translate_prefs_->BlockLanguage("de");
+  // When the detailed language settings are enabled blocked languages not in
+  // the accept languages list are blocked. When the detailed language settings
+  // are disabled blocked languages not in the accept language list are allowed.
+  translate_prefs_->BlockLanguage("de");
+  if (TranslatePrefs::IsDetailedLanguageSettingsEnabled()) {
+    EXPECT_FALSE(translate_prefs_->CanTranslateLanguage(
+        &translate_accept_languages, "de"));
+  } else {
     EXPECT_TRUE(translate_prefs_->CanTranslateLanguage(
         &translate_accept_languages, "de"));
   }
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index fcb0b1d32..26c37be 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1036,6 +1036,8 @@
     "interest_group/auction_runner.h",
     "interest_group/auction_url_loader_factory_proxy.cc",
     "interest_group/auction_url_loader_factory_proxy.h",
+    "interest_group/auction_worklet_manager.cc",
+    "interest_group/auction_worklet_manager.h",
     "interest_group/debuggable_auction_worklet.cc",
     "interest_group/debuggable_auction_worklet.h",
     "interest_group/debuggable_auction_worklet_tracker.cc",
diff --git a/content/browser/accessibility/accessibility_action_browsertest.cc b/content/browser/accessibility/accessibility_action_browsertest.cc
index 31ede63..fbff14b 100644
--- a/content/browser/accessibility/accessibility_action_browsertest.cc
+++ b/content/browser/accessibility/accessibility_action_browsertest.cc
@@ -474,7 +474,7 @@
       target->CreateTextPositionAt(0);
   BrowserAccessibility::AXPosition end_of_line_1 =
       start_position->CreateNextLineEndPosition(
-          ui::AXBoundaryBehavior::CrossBoundary);
+          ui::AXBoundaryBehavior::kCrossBoundary);
   EXPECT_EQ(5, end_of_line_1->text_offset());
 #endif
 }
@@ -508,7 +508,7 @@
       target->CreateTextPositionAt(0);
   BrowserAccessibility::AXPosition end_of_line_1 =
       start_position->CreateNextLineEndPosition(
-          ui::AXBoundaryBehavior::CrossBoundary);
+          ui::AXBoundaryBehavior::kCrossBoundary);
   EXPECT_EQ(5, end_of_line_1->text_offset());
 #endif
 }
diff --git a/content/browser/accessibility/accessibility_auralinux_browsertest.cc b/content/browser/accessibility/accessibility_auralinux_browsertest.cc
index 0108a42..38ccd2b0 100644
--- a/content/browser/accessibility/accessibility_auralinux_browsertest.cc
+++ b/content/browser/accessibility/accessibility_auralinux_browsertest.cc
@@ -460,7 +460,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(AccessibilityAuraLinuxBrowserTest,
-                       TestParagraphTextAtOffsetWithBoundarySentence) {
+                       DISABLED_TestParagraphTextAtOffsetWithBoundarySentence) {
   LoadInitialAccessibilityTreeFromHtml(std::string(
       R"HTML(<!DOCTYPE html>
           <html>
diff --git a/content/browser/accessibility/accessibility_win_browsertest.cc b/content/browser/accessibility/accessibility_win_browsertest.cc
index f51674f..62c3bbae 100644
--- a/content/browser/accessibility/accessibility_win_browsertest.cc
+++ b/content/browser/accessibility/accessibility_win_browsertest.cc
@@ -1784,7 +1784,7 @@
   Microsoft::WRL::ComPtr<IAccessibleText> input_text;
   SetUpScrollableInputField(&input_text);
 
-  int contents_string_length = static_cast<int>(InputContentsString().size());
+  LONG contents_string_length = static_cast<LONG>(InputContentsString().size());
   constexpr LONG visible_characters_start = 21;
   LONG n_characters;
   ASSERT_HRESULT_SUCCEEDED(input_text->get_nCharacters(&n_characters));
@@ -1979,7 +1979,7 @@
   Microsoft::WRL::ComPtr<IAccessibleText> input_text;
   SetUpScrollableInputTypeSearchField(&input_text);
 
-  int contents_string_length = static_cast<int>(InputContentsString().size());
+  LONG contents_string_length = static_cast<LONG>(InputContentsString().size());
   constexpr LONG visible_characters_start = 21;
   LONG n_characters;
   ASSERT_HRESULT_SUCCEEDED(input_text->get_nCharacters(&n_characters));
@@ -2628,7 +2628,7 @@
   AccessibilityNotificationWaiter waiter(
       shell()->web_contents(), ui::kAXModeComplete,
       ax::mojom::Event::kTextSelectionChanged);
-  int contents_string_length = static_cast<int>(InputContentsString().size());
+  LONG contents_string_length = static_cast<LONG>(InputContentsString().size());
   start_offset = 0;
   end_offset = contents_string_length;
   EXPECT_HRESULT_FAILED(input_text->setSelection(1, start_offset, end_offset));
@@ -2664,7 +2664,7 @@
   LONG n_ranges = 1;
   IA2Range* ranges =
       reinterpret_cast<IA2Range*>(CoTaskMemAlloc(sizeof(IA2Range)));
-  int contents_string_length = static_cast<int>(InputContentsString().size());
+  LONG contents_string_length = static_cast<LONG>(InputContentsString().size());
   ranges[0].anchor = ax_input.Get();
   ranges[0].anchorOffset = -1;
   ranges[0].active = ax_input.Get();
@@ -2869,7 +2869,7 @@
   // There is no selection, just a caret.
   EXPECT_EQ(E_INVALIDARG, hr);
 
-  int contents_string_length = static_cast<int>(InputContentsString().size());
+  LONG contents_string_length = static_cast<LONG>(InputContentsString().size());
   AccessibilityNotificationWaiter waiter(
       shell()->web_contents(), ui::kAXModeComplete,
       ax::mojom::Event::kTextSelectionChanged);
@@ -2906,7 +2906,7 @@
   Microsoft::WRL::ComPtr<IAccessible2_4> ax_textarea;
   ASSERT_HRESULT_SUCCEEDED(textarea_text.As(&ax_textarea));
 
-  int contents_string_length = static_cast<int>(InputContentsString().size());
+  LONG contents_string_length = static_cast<LONG>(InputContentsString().size());
   LONG n_ranges = 1;
   IA2Range* ranges =
       reinterpret_cast<IA2Range*>(CoTaskMemAlloc(sizeof(IA2Range)));
@@ -3481,7 +3481,7 @@
   EXPECT_EQ(nullptr, text.Get());
   hr = input_text->get_textAtOffset(invalid_offset, IA2_TEXT_BOUNDARY_SENTENCE,
                                     &start_offset, &end_offset, text.Receive());
-  EXPECT_EQ(S_FALSE, hr);
+  EXPECT_EQ(E_INVALIDARG, hr);
   EXPECT_EQ(0, start_offset);
   EXPECT_EQ(0, end_offset);
   EXPECT_EQ(nullptr, text.Get());
@@ -3518,7 +3518,7 @@
   hr = input_text->get_textAtOffset(IA2_TEXT_OFFSET_LENGTH,
                                     IA2_TEXT_BOUNDARY_SENTENCE, &start_offset,
                                     &end_offset, text.Receive());
-  EXPECT_EQ(S_FALSE, hr);
+  EXPECT_EQ(E_INVALIDARG, hr);
   EXPECT_EQ(0, start_offset);
   EXPECT_EQ(0, end_offset);
   EXPECT_EQ(nullptr, text.Get());
@@ -3588,7 +3588,7 @@
   hr = textarea_text->get_textAtOffset(
       invalid_offset, IA2_TEXT_BOUNDARY_SENTENCE, &start_offset, &end_offset,
       text.Receive());
-  EXPECT_EQ(S_FALSE, hr);
+  EXPECT_EQ(E_INVALIDARG, hr);
   EXPECT_EQ(0, start_offset);
   EXPECT_EQ(0, end_offset);
   EXPECT_EQ(nullptr, text.Get());
@@ -3627,7 +3627,7 @@
   hr = textarea_text->get_textAtOffset(
       IA2_TEXT_OFFSET_LENGTH, IA2_TEXT_BOUNDARY_SENTENCE, &start_offset,
       &end_offset, text.Receive());
-  EXPECT_EQ(S_FALSE, hr);
+  EXPECT_EQ(E_INVALIDARG, hr);
   EXPECT_EQ(0, start_offset);
   EXPECT_EQ(0, end_offset);
   EXPECT_EQ(nullptr, text.Get());
@@ -3653,7 +3653,7 @@
   Microsoft::WRL::ComPtr<IAccessibleText> input_text;
   SetUpInputField(&input_text);
 
-  int contents_string_length = static_cast<int>(InputContentsString().size());
+  LONG contents_string_length = static_cast<LONG>(InputContentsString().size());
   for (LONG offset = 0; offset < contents_string_length; ++offset) {
     std::wstring expected_text(1, InputContentsString()[offset]);
     LONG expected_start_offset = offset;
@@ -3681,7 +3681,7 @@
   Microsoft::WRL::ComPtr<IAccessibleText> textarea_text;
   SetUpTextareaField(&textarea_text);
 
-  int contents_string_length = InputContentsString().size();
+  LONG contents_string_length = static_cast<LONG>(InputContentsString().size());
   for (LONG offset = 0; offset < contents_string_length; ++offset) {
     std::wstring expected_text(1, TextAreaContentsString()[offset]);
     LONG expected_start_offset = offset;
@@ -3869,7 +3869,7 @@
   CheckTextAtOffset(input_text, 39, IA2_TEXT_BOUNDARY_WORD, 38, 40, L", ");
 
   // Trailing final punctuation should not be part of the last word.
-  int contents_string_length = static_cast<int>(InputContentsString().size());
+  LONG contents_string_length = static_cast<LONG>(InputContentsString().size());
   CheckTextAtOffset(input_text, 40, IA2_TEXT_BOUNDARY_WORD, 40, 44, L"like");
   CheckTextAtOffset(input_text, 41, IA2_TEXT_BOUNDARY_WORD, 40, 44, L"like");
   CheckTextAtOffset(input_text, 44, IA2_TEXT_BOUNDARY_WORD, 44,
@@ -3934,7 +3934,7 @@
   CheckTextAtOffset(textarea_text, 39, IA2_TEXT_BOUNDARY_WORD, 38, 40, L", ");
 
   // Trailing final punctuation should not be part of the last word.
-  int contents_string_length = static_cast<int>(InputContentsString().size());
+  LONG contents_string_length = static_cast<LONG>(InputContentsString().size());
   CheckTextAtOffset(textarea_text, 40, IA2_TEXT_BOUNDARY_WORD, 40, 44, L"like");
   CheckTextAtOffset(textarea_text, 41, IA2_TEXT_BOUNDARY_WORD, 40, 44, L"like");
   CheckTextAtOffset(textarea_text, 44, IA2_TEXT_BOUNDARY_WORD, 44,
@@ -3977,33 +3977,78 @@
 }
 
 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
-                       TestTextAtOffsetWithBoundarySentence) {
+                       DISABLED_TestTextAtOffsetWithBoundarySentence) {
   Microsoft::WRL::ComPtr<IAccessibleText> input_text;
   SetUpInputField(&input_text);
 
-  // Sentence navigation is not currently implemented.
-  LONG start_offset = 0;
-  LONG end_offset = 0;
-  base::win::ScopedBstr text;
-  HRESULT hr =
-      input_text->get_textAtOffset(5, IA2_TEXT_BOUNDARY_SENTENCE, &start_offset,
-                                   &end_offset, text.Receive());
-  EXPECT_EQ(S_FALSE, hr);
+  const LONG contents_string_length =
+      static_cast<LONG>(InputContentsString().size());
+  const std::wstring expected_text = base::SysUTF8ToWide(InputContentsString());
+  for (LONG offset = 0; offset < contents_string_length; ++offset) {
+    CheckTextAtOffset(input_text, offset, IA2_TEXT_BOUNDARY_SENTENCE, 0,
+                      contents_string_length, expected_text);
+  }
+
+  // Test special offsets.
+  CheckTextAtOffset(input_text, IA2_TEXT_OFFSET_CARET,
+                    IA2_TEXT_BOUNDARY_SENTENCE, 0, contents_string_length,
+                    expected_text);
+  {
+    LONG start_offset = 0;
+    LONG end_offset = 0;
+    base::win::ScopedBstr text;
+    HRESULT hr = input_text->get_textAtOffset(
+        IA2_TEXT_OFFSET_LENGTH, IA2_TEXT_BOUNDARY_SENTENCE, &start_offset,
+        &end_offset, text.Receive());
+    EXPECT_EQ(E_INVALIDARG, hr);
+    EXPECT_EQ(0, start_offset);
+    EXPECT_EQ(0, end_offset);
+    EXPECT_EQ(nullptr, text.Get());
+  }
 }
 
 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
-                       TestMultiLineTextAtOffsetWithBoundarySentence) {
+                       DISABLED_TestMultiLineTextAtOffsetWithBoundarySentence) {
   Microsoft::WRL::ComPtr<IAccessibleText> textarea_text;
   SetUpTextareaField(&textarea_text);
 
-  // Sentence navigation is not currently implemented.
-  LONG start_offset = 0;
-  LONG end_offset = 0;
-  base::win::ScopedBstr text;
-  HRESULT hr = textarea_text->get_textAtOffset(25, IA2_TEXT_BOUNDARY_SENTENCE,
-                                               &start_offset, &end_offset,
-                                               text.Receive());
-  EXPECT_EQ(S_FALSE, hr);
+  const LONG contents_string_length =
+      static_cast<LONG>(TextAreaContentsString().size());
+  const std::vector<LONG> sentence_starts{0, 23, 24, 31, 32};
+  const std::vector<LONG> sentence_ends{23, 24, 31, 32, contents_string_length};
+  size_t sentence_index = 0;
+  for (LONG offset = 0; offset < contents_string_length &&
+                        sentence_index < sentence_starts.size();
+       ++offset) {
+    if (offset == sentence_starts[sentence_index + 1])
+      ++sentence_index;
+    LONG expected_start_offset = sentence_starts[sentence_index];
+    LONG expected_end_offset = sentence_ends[sentence_index];
+    const std::wstring expected_text =
+        base::SysUTF8ToWide(TextAreaContentsString().substr(
+            sentence_starts[sentence_index],
+            (sentence_ends[sentence_index] - sentence_starts[sentence_index])));
+    CheckTextAtOffset(textarea_text, offset, IA2_TEXT_BOUNDARY_SENTENCE,
+                      expected_start_offset, expected_end_offset,
+                      expected_text);
+  }
+
+  // Test special offsets.
+  CheckTextAtOffset(textarea_text, IA2_TEXT_OFFSET_CARET,
+                    IA2_TEXT_BOUNDARY_SENTENCE, 32, contents_string_length,
+                    base::SysUTF8ToWide(TextAreaContentsString().substr(32)));
+  {
+    LONG start_offset = 0;
+    LONG end_offset = 0;
+    base::win::ScopedBstr text;
+    HRESULT hr = textarea_text->get_textAtOffset(
+        IA2_TEXT_OFFSET_LENGTH, IA2_TEXT_BOUNDARY_SENTENCE, &start_offset,
+        &end_offset, text.Receive());
+    EXPECT_EQ(E_INVALIDARG, hr);
+    EXPECT_EQ(0, start_offset);
+    EXPECT_EQ(0, end_offset);
+    EXPECT_EQ(nullptr, text.Get());
+  }
 }
 
 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
@@ -4012,7 +4057,7 @@
   SetUpInputField(&input_text);
 
   // Single line text fields should return the whole text.
-  int contents_string_length = static_cast<int>(InputContentsString().size());
+  LONG contents_string_length = static_cast<LONG>(InputContentsString().size());
   CheckTextAtOffset(input_text, 0, IA2_TEXT_BOUNDARY_LINE, 0,
                     contents_string_length,
                     base::SysUTF8ToWide(InputContentsString()));
@@ -4039,7 +4084,7 @@
                     L"WebKit \n");
 
   // Last line does not have a trailing newline.
-  int contents_string_length = static_cast<int>(InputContentsString().size());
+  LONG contents_string_length = static_cast<LONG>(InputContentsString().size());
   CheckTextAtOffset(textarea_text, 32, IA2_TEXT_BOUNDARY_LINE, 32,
                     contents_string_length, L"\"KHTML, like\".");
 
@@ -4077,8 +4122,8 @@
   // Blink represents the blank line with a newline character, so in total there
   // should be two more newlines. The second newline is not part of the HTML
   // value attribute however.
-  int contents_string_length =
-      static_cast<int>(InputContentsString().size()) + 1;
+  LONG contents_string_length =
+      static_cast<LONG>(InputContentsString().size()) + 1;
   CheckTextAtOffset(textarea_text, 32, IA2_TEXT_BOUNDARY_LINE, 32,
                     contents_string_length, L"\"KHTML, like\".\n");
   CheckTextAtOffset(textarea_text, 46, IA2_TEXT_BOUNDARY_LINE, 32,
diff --git a/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc b/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc
index 84f486ee..24b95ba 100644
--- a/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc
+++ b/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc
@@ -2759,7 +2759,7 @@
       /*expected_count*/ -1);
   ASSERT_HRESULT_SUCCEEDED(
       text_range_provider->ExpandToEnclosingUnit(TextUnit_Word));
-  EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"\xA0\n");
+  EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"\xA0");
 
   // Case 2: test on range that includes the whitespace and the following word.
   GetTextRangeProviderFromTextNode(*node, &text_range_provider);
@@ -2772,7 +2772,7 @@
                                    /*expected_count*/ 1);
   ASSERT_HRESULT_SUCCEEDED(
       text_range_provider->ExpandToEnclosingUnit(TextUnit_Word));
-  EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"\xA0\n");
+  EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"\xA0");
 
   // Case 3: test on degenerate range after whitespace.
   node = FindNode(ax::mojom::Role::kStaticText, "3.14");
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index 11aacc6..f0896a77 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -105,26 +105,6 @@
   return nullptr;
 }
 
-int GetBoundaryTextOffsetInsideBaseAnchor(
-    ax::mojom::MoveDirection direction,
-    const BrowserAccessibility::AXPosition& base,
-    const BrowserAccessibility::AXPosition& position) {
-  if (base->GetAnchor() == position->GetAnchor())
-    return position->text_offset();
-
-  // If the position is outside the anchor of the base position, then return
-  // the first or last position in the same direction.
-  switch (direction) {
-    case ax::mojom::MoveDirection::kNone:
-      NOTREACHED();
-      return position->text_offset();
-    case ax::mojom::MoveDirection::kBackward:
-      return base->CreatePositionAtStartOfAnchor()->text_offset();
-    case ax::mojom::MoveDirection::kForward:
-      return base->CreatePositionAtEndOfAnchor()->text_offset();
-  }
-}
-
 }  // namespace
 
 bool BrowserAccessibility::IsValid() const {
@@ -1157,29 +1137,6 @@
   return result;
 }
 
-absl::optional<int> BrowserAccessibility::FindTextBoundary(
-    ax::mojom::TextBoundary boundary,
-    int offset,
-    ax::mojom::MoveDirection direction,
-    ax::mojom::TextAffinity affinity) const {
-  const AXPosition position = CreateTextPositionAt(offset, affinity);
-
-  // On Windows and Linux ATK, searching for a text boundary should always stop
-  // at the boundary of the current object.
-  auto boundary_behavior = ui::AXBoundaryBehavior::StopAtAnchorBoundary;
-  // On Windows and Linux ATK, it is standard text navigation behavior to stop
-  // if we are searching in the backwards direction and the current position is
-  // already at the required text boundary.
-  DCHECK_NE(direction, ax::mojom::MoveDirection::kNone);
-  if (direction == ax::mojom::MoveDirection::kBackward)
-    boundary_behavior = ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary;
-
-  return GetBoundaryTextOffsetInsideBaseAnchor(
-      direction, position,
-      position->CreatePositionAtTextBoundary(boundary, direction,
-                                             boundary_behavior));
-}
-
 const std::vector<gfx::NativeViewAccessible>
 BrowserAccessibility::GetUIADirectChildrenInRange(
     ui::AXPlatformNodeDelegate* start,
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h
index 8ec8af9b..2974b1f4 100644
--- a/content/browser/accessibility/browser_accessibility.h
+++ b/content/browser/accessibility/browser_accessibility.h
@@ -507,12 +507,6 @@
   int GetIndexInParent() override;
   gfx::AcceleratedWidget GetTargetForNativeAccessibilityEvent() override;
 
-  absl::optional<int> FindTextBoundary(
-      ax::mojom::TextBoundary boundary,
-      int offset,
-      ax::mojom::MoveDirection direction,
-      ax::mojom::TextAffinity affinity) const override;
-
   const std::vector<gfx::NativeViewAccessible> GetUIADirectChildrenInRange(
       ui::AXPlatformNodeDelegate* start,
       ui::AXPlatformNodeDelegate* end) override;
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index 06f49e79..8e61e3d 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -2383,7 +2383,7 @@
     if (position->IsNullPosition())
       return nil;
     return CreateTextMarker(position->CreateNextCharacterPosition(
-        ui::AXBoundaryBehavior::CrossBoundary));
+        ui::AXBoundaryBehavior::kCrossBoundary));
   }
 
   if ([attribute
@@ -2393,7 +2393,7 @@
     if (position->IsNullPosition())
       return nil;
     return CreateTextMarker(position->CreatePreviousCharacterPosition(
-        ui::AXBoundaryBehavior::CrossBoundary));
+        ui::AXBoundaryBehavior::kCrossBoundary));
   }
 
   if ([attribute
@@ -2404,9 +2404,9 @@
       return nil;
 
     AXPosition startWordPosition = endPosition->CreatePreviousWordStartPosition(
-        ui::AXBoundaryBehavior::StopAtAnchorBoundary);
+        ui::AXBoundaryBehavior::kStopAtAnchorBoundary);
     AXPosition endWordPosition = endPosition->CreatePreviousWordEndPosition(
-        ui::AXBoundaryBehavior::StopAtAnchorBoundary);
+        ui::AXBoundaryBehavior::kStopAtAnchorBoundary);
     AXPosition startPosition = *startWordPosition <= *endWordPosition
                                    ? std::move(endWordPosition)
                                    : std::move(startWordPosition);
@@ -2422,9 +2422,9 @@
       return nil;
 
     AXPosition endWordPosition = startPosition->CreateNextWordEndPosition(
-        ui::AXBoundaryBehavior::StopAtAnchorBoundary);
+        ui::AXBoundaryBehavior::kStopAtAnchorBoundary);
     AXPosition startWordPosition = startPosition->CreateNextWordStartPosition(
-        ui::AXBoundaryBehavior::StopAtAnchorBoundary);
+        ui::AXBoundaryBehavior::kStopAtAnchorBoundary);
     AXPosition endPosition = *startWordPosition <= *endWordPosition
                                  ? std::move(startWordPosition)
                                  : std::move(endWordPosition);
@@ -2439,7 +2439,7 @@
     if (position->IsNullPosition())
       return nil;
     return CreateTextMarker(position->CreateNextWordEndPosition(
-        ui::AXBoundaryBehavior::CrossBoundary));
+        ui::AXBoundaryBehavior::kCrossBoundary));
   }
 
   if ([attribute
@@ -2449,7 +2449,7 @@
     if (position->IsNullPosition())
       return nil;
     return CreateTextMarker(position->CreatePreviousWordStartPosition(
-        ui::AXBoundaryBehavior::CrossBoundary));
+        ui::AXBoundaryBehavior::kCrossBoundary));
   }
 
   if ([attribute isEqualToString:
@@ -2485,9 +2485,9 @@
     // Make sure that the line start position is really at the start of the
     // current line.
     lineStartPosition = lineStartPosition->CreatePreviousLineStartPosition(
-        ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+        ui::AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
     AXPosition lineEndPosition = lineStartPosition->CreateNextLineEndPosition(
-        ui::AXBoundaryBehavior::StopAtAnchorBoundary);
+        ui::AXBoundaryBehavior::kStopAtAnchorBoundary);
     AXRange range(std::move(lineStartPosition), std::move(lineEndPosition));
     return CreateTextMarkerRange(std::move(range));
   }
@@ -2500,9 +2500,9 @@
       return nil;
 
     AXPosition startLinePosition = endPosition->CreatePreviousLineStartPosition(
-        ui::AXBoundaryBehavior::StopAtLastAnchorBoundary);
+        ui::AXBoundaryBehavior::kStopAtLastAnchorBoundary);
     AXPosition endLinePosition = endPosition->CreatePreviousLineEndPosition(
-        ui::AXBoundaryBehavior::StopAtLastAnchorBoundary);
+        ui::AXBoundaryBehavior::kStopAtLastAnchorBoundary);
     AXPosition startPosition = *startLinePosition <= *endLinePosition
                                    ? std::move(endLinePosition)
                                    : std::move(startLinePosition);
@@ -2518,9 +2518,9 @@
       return nil;
 
     AXPosition startLinePosition = startPosition->CreateNextLineStartPosition(
-        ui::AXBoundaryBehavior::StopAtLastAnchorBoundary);
+        ui::AXBoundaryBehavior::kStopAtLastAnchorBoundary);
     AXPosition endLinePosition = startPosition->CreateNextLineEndPosition(
-        ui::AXBoundaryBehavior::StopAtLastAnchorBoundary);
+        ui::AXBoundaryBehavior::kStopAtLastAnchorBoundary);
     AXPosition endPosition = *startLinePosition <= *endLinePosition
                                  ? std::move(startLinePosition)
                                  : std::move(endLinePosition);
@@ -2535,7 +2535,7 @@
     if (position->IsNullPosition())
       return nil;
     return CreateTextMarker(position->CreateNextLineEndPosition(
-        ui::AXBoundaryBehavior::CrossBoundary));
+        ui::AXBoundaryBehavior::kCrossBoundary));
   }
 
   if ([attribute
@@ -2545,7 +2545,20 @@
     if (position->IsNullPosition())
       return nil;
     return CreateTextMarker(position->CreatePreviousLineStartPosition(
-        ui::AXBoundaryBehavior::CrossBoundary));
+        ui::AXBoundaryBehavior::kCrossBoundary));
+  }
+
+  if ([attribute
+          isEqualToString:
+              NSAccessibilitySentenceTextMarkerRangeForTextMarkerParameterizedAttribute]) {
+    AXPosition position = AXTextMarkerToAXPosition(parameter);
+    if (position->IsNullPosition())
+      return nil;
+
+    AXRange range = position->ExpandToEnclosingTextBoundary(
+        ax::mojom::TextBoundary::kSentenceStartOrEnd,
+        ui::AXRangeExpandBehavior::kLeftFirst);
+    return CreateTextMarkerRange(std::move(range));
   }
 
   if ([attribute
@@ -2555,11 +2568,9 @@
     if (position->IsNullPosition())
       return nil;
 
-    AXPosition startPosition = position->CreatePreviousParagraphStartPosition(
-        ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary);
-    AXPosition endPosition = position->CreateNextParagraphEndPosition(
-        ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary);
-    AXRange range(std::move(startPosition), std::move(endPosition));
+    AXRange range = position->ExpandToEnclosingTextBoundary(
+        ax::mojom::TextBoundary::kParagraphStartOrEnd,
+        ui::AXRangeExpandBehavior::kLeftFirst);
     return CreateTextMarkerRange(std::move(range));
   }
 
@@ -2570,7 +2581,7 @@
     if (position->IsNullPosition())
       return nil;
     return CreateTextMarker(position->CreateNextParagraphEndPosition(
-        ui::AXBoundaryBehavior::CrossBoundary));
+        ui::AXBoundaryBehavior::kCrossBoundary));
   }
 
   if ([attribute
@@ -2580,7 +2591,7 @@
     if (position->IsNullPosition())
       return nil;
     return CreateTextMarker(position->CreatePreviousParagraphStartPosition(
-        ui::AXBoundaryBehavior::CrossBoundary));
+        ui::AXBoundaryBehavior::kCrossBoundary));
   }
 
   if ([attribute
@@ -2591,9 +2602,9 @@
       return nil;
 
     AXPosition startPosition = position->CreatePreviousFormatStartPosition(
-        ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+        ui::AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
     AXPosition endPosition = position->CreateNextFormatEndPosition(
-        ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+        ui::AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
     AXRange range(std::move(startPosition), std::move(endPosition));
     return CreateTextMarkerRange(std::move(range));
   }
@@ -2675,9 +2686,9 @@
     //
     // Note that hard line breaks are on a line of their own.
     AXPosition startPosition = position->CreatePreviousLineStartPosition(
-        ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+        ui::AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
     AXPosition endPosition = startPosition->CreateNextLineStartPosition(
-        ui::AXBoundaryBehavior::StopAtLastAnchorBoundary);
+        ui::AXBoundaryBehavior::kStopAtLastAnchorBoundary);
     AXRange range(std::move(startPosition), std::move(endPosition));
     return CreateTextMarkerRange(std::move(range));
   }
diff --git a/content/browser/accessibility/browser_accessibility_fuchsia.cc b/content/browser/accessibility/browser_accessibility_fuchsia.cc
index ac90112..3cebe115 100644
--- a/content/browser/accessibility/browser_accessibility_fuchsia.cc
+++ b/content/browser/accessibility/browser_accessibility_fuchsia.cc
@@ -397,7 +397,7 @@
     if (!accessibility_bridge)
       return false;
 
-    root_manager->HitTest(action_data.target_point);
+    root_manager->HitTest(action_data.target_point, action_data.request_id);
     return true;
   }
 
diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc
index f65cc54..687dfa92 100644
--- a/content/browser/accessibility/browser_accessibility_manager.cc
+++ b/content/browser/accessibility/browser_accessibility_manager.cc
@@ -1012,11 +1012,14 @@
   BrowserAccessibilityStateImpl::GetInstance()->OnAccessibilityApiUsage();
 }
 
-void BrowserAccessibilityManager::HitTest(const gfx::Point& frame_point) const {
+void BrowserAccessibilityManager::HitTest(const gfx::Point& frame_point,
+                                          int request_id) const {
   if (!delegate_)
     return;
 
-  delegate_->AccessibilityHitTest(frame_point, ax::mojom::Event::kHover, 0, {});
+  delegate_->AccessibilityHitTest(frame_point, ax::mojom::Event::kHover,
+                                  request_id,
+                                  /*opt_callback=*/{});
   BrowserAccessibilityStateImpl::GetInstance()->OnAccessibilityApiUsage();
 }
 
@@ -1691,7 +1694,7 @@
 
     // This triggers an asynchronous request to compute the true object that's
     // under the point.
-    HitTest(frame_point);
+    HitTest(frame_point, /*request_id=*/0);
 
     // Unfortunately we still have to return an answer synchronously because
     // the APIs were designed that way. The best case scenario is that the
diff --git a/content/browser/accessibility/browser_accessibility_manager.h b/content/browser/accessibility/browser_accessibility_manager.h
index 57b60da4..9be92a2 100644
--- a/content/browser/accessibility/browser_accessibility_manager.h
+++ b/content/browser/accessibility/browser_accessibility_manager.h
@@ -292,7 +292,7 @@
   // expects hit test points in page coordinates. However, WebAXObject::HitTest
   // applies the visual viewport offset, so we want to pass that function a
   // point in frame coordinates.
-  void HitTest(const gfx::Point& frame_point) const;
+  void HitTest(const gfx::Point& frame_point, int request_id) const;
   void Increment(const BrowserAccessibility& node);
   void LoadInlineTextBoxes(const BrowserAccessibility& node);
   void ScrollToMakeVisible(
diff --git a/content/browser/accessibility/browser_accessibility_manager_fuchsia_unittest.cc b/content/browser/accessibility/browser_accessibility_manager_fuchsia_unittest.cc
index 411b23ad..7274a56 100644
--- a/content/browser/accessibility/browser_accessibility_manager_fuchsia_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_fuchsia_unittest.cc
@@ -35,18 +35,22 @@
       base::OnceCallback<void(BrowserAccessibilityManager* hit_manager,
                               int hit_node_id)> opt_callback) override {
     last_hit_test_point_ = point_in_frame_pixels;
+    last_request_id_ = opt_request_id;
   }
 
   const absl::optional<ui::AXActionData>& last_action_data() {
     return last_action_data_;
   }
 
+  const absl::optional<int>& last_request_id() { return last_request_id_; }
+
   const absl::optional<gfx::Point>& last_hit_test_point() {
     return last_hit_test_point_;
   }
 
  private:
   absl::optional<ui::AXActionData> last_action_data_;
+  absl::optional<int> last_request_id_;
   absl::optional<gfx::Point> last_hit_test_point_;
 };
 
@@ -495,8 +499,14 @@
   {
     absl::optional<gfx::Point> last_target =
         mock_browser_accessibility_delegate_->last_hit_test_point();
+    ASSERT_TRUE(last_target.has_value());
     EXPECT_EQ(last_target->x(), 1);
     EXPECT_EQ(last_target->y(), 2);
+
+    absl::optional<int> last_request_id =
+        mock_browser_accessibility_delegate_->last_request_id();
+    ASSERT_TRUE(last_request_id.has_value());
+    EXPECT_EQ(*last_request_id, action_data.request_id);
   }
 
   // Fire blink event to signify the hit test result.
diff --git a/content/browser/accessibility/browser_accessibility_unittest.cc b/content/browser/accessibility/browser_accessibility_unittest.cc
index 04f8580..b3001fb 100644
--- a/content/browser/accessibility/browser_accessibility_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_unittest.cc
@@ -829,7 +829,7 @@
 
   BrowserAccessibility::AXPosition next_word_start =
       position->CreateNextWordStartPosition(
-          ui::AXBoundaryBehavior::CrossBoundary);
+          ui::AXBoundaryBehavior::kCrossBoundary);
   if (position->MaxTextOffset() == 0) {
     EXPECT_TRUE(next_word_start->IsNullPosition());
   } else {
@@ -841,7 +841,7 @@
 
   BrowserAccessibility::AXPosition next_word_end =
       position->CreateNextWordEndPosition(
-          ui::AXBoundaryBehavior::CrossBoundary);
+          ui::AXBoundaryBehavior::kCrossBoundary);
   if (position->MaxTextOffset() == 0) {
     EXPECT_TRUE(next_word_end->IsNullPosition());
   } else {
diff --git a/content/browser/accessibility/dump_accessibility_events_browsertest.cc b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
index eb2d295..fa52bf04 100644
--- a/content/browser/accessibility/dump_accessibility_events_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
@@ -493,8 +493,8 @@
   RunEventTest(FILE_PATH_LITERAL("caret-move.html"));
 }
 
-// Flaky on Windows: https://crbug.com/1186887
-#if defined(OS_WIN)
+// Flaky on Windows, disabled on Linux: https://crbug.com/1186887
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
 #define MAYBE_AccessibilityEventsCaretMoveHiddenInput \
   DISABLED_AccessibilityEventsCaretMoveHiddenInput
 #else
diff --git a/content/browser/accessibility/web_contents_accessibility_android.cc b/content/browser/accessibility/web_contents_accessibility_android.cc
index 9bddf22..ace8e70 100644
--- a/content/browser/accessibility/web_contents_accessibility_android.cc
+++ b/content/browser/accessibility/web_contents_accessibility_android.cc
@@ -557,7 +557,7 @@
   // Hover event was consumed by accessibility by now. Return true to
   // stop the event from proceeding.
   if (event.GetAction() != ui::MotionEvent::Action::HOVER_EXIT)
-    GetRootBrowserAccessibilityManager()->HitTest(point);
+    GetRootBrowserAccessibilityManager()->HitTest(point, /*request_id=*/0);
 
   if (!GetRootBrowserAccessibilityManager()->touch_passthrough_enabled())
     return true;
@@ -672,7 +672,7 @@
                                               jint y) {
   if (BrowserAccessibilityManagerAndroid* root_manager =
           GetRootBrowserAccessibilityManager())
-    root_manager->HitTest(gfx::Point(x, y));
+    root_manager->HitTest(gfx::Point(x, y), /*request_id=*/0);
 }
 
 jboolean WebContentsAccessibilityAndroid::IsEditableText(
diff --git a/content/browser/background_fetch/background_fetch_cross_origin_filter.cc b/content/browser/background_fetch/background_fetch_cross_origin_filter.cc
index 1fcc93f..bb240a22 100644
--- a/content/browser/background_fetch/background_fetch_cross_origin_filter.cc
+++ b/content/browser/background_fetch/background_fetch_cross_origin_filter.cc
@@ -61,8 +61,7 @@
   const auto& response_header_map = request.GetResponseHeaders();
 
   // True iff |source_origin| is the same origin as the original request URL.
-  is_same_origin_ =
-      source_origin.IsSameOriginWith(url::Origin::Create(final_url));
+  is_same_origin_ = source_origin.IsSameOriginWith(final_url);
 
   // Access-Control-Allow-Origin checks. The header's values must be valid for
   // it to not be completely discarded.
diff --git a/content/browser/background_fetch/storage/get_metadata_task.cc b/content/browser/background_fetch/storage/get_metadata_task.cc
index 90c2621..6e2928f 100644
--- a/content/browser/background_fetch/storage/get_metadata_task.cc
+++ b/content/browser/background_fetch/storage/get_metadata_task.cc
@@ -85,7 +85,7 @@
   // can get it from `metadata_proto_`.
   if (registration_proto.developer_id() != developer_id_ ||
       !storage_key_.origin().IsSameOriginWith(
-          url::Origin::Create(GURL(metadata_proto_->origin())))) {
+          GURL(metadata_proto_->origin()))) {
     FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR);
     return;
   }
diff --git a/content/browser/bluetooth/web_bluetooth_service_impl.cc b/content/browser/bluetooth/web_bluetooth_service_impl.cc
index aa0df7dc..b3f02cd 100644
--- a/content/browser/bluetooth/web_bluetooth_service_impl.cc
+++ b/content/browser/bluetooth/web_bluetooth_service_impl.cc
@@ -566,10 +566,17 @@
 
 WebBluetoothServiceImpl::~WebBluetoothServiceImpl() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
   // Releasing the adapter will drop references to callbacks that have not yet
   // been executed. The receiver must be closed first so that this is allowed.
   receiver()->reset();
 
+#if PAIR_BLUETOOTH_ON_DEMAND()
+  // Destroy the pairing manager before releasing the adapter to give it an
+  // opportunity to cancel pairing operations that are in progress.
+  pairing_manager_.reset();
+#endif
+
   BluetoothAdapterFactoryWrapper::Get().ReleaseAdapter(this);
 }
 
diff --git a/content/browser/bluetooth/web_bluetooth_service_impl.h b/content/browser/bluetooth/web_bluetooth_service_impl.h
index b7a1051..faf46e6a 100644
--- a/content/browser/bluetooth/web_bluetooth_service_impl.h
+++ b/content/browser/bluetooth/web_bluetooth_service_impl.h
@@ -146,6 +146,8 @@
 #if PAIR_BLUETOOTH_ON_DEMAND()
   FRIEND_TEST_ALL_PREFIXES(WebBluetoothServiceImplBondingTest,
                            ReadCharacteristicValueNotAuthorized);
+  FRIEND_TEST_ALL_PREFIXES(WebBluetoothServiceImplBondingTest,
+                           IncompletePairingOnShutdown);
 #endif  // PAIR_BLUETOOTH_ON_DEMAND()
 
   friend class FrameConnectedBluetoothDevicesTest;
diff --git a/content/browser/bluetooth/web_bluetooth_service_impl_unittest.cc b/content/browser/bluetooth/web_bluetooth_service_impl_unittest.cc
index fb402d8..26d54fe 100644
--- a/content/browser/bluetooth/web_bluetooth_service_impl_unittest.cc
+++ b/content/browser/bluetooth/web_bluetooth_service_impl_unittest.cc
@@ -9,6 +9,7 @@
 
 #include "base/memory/raw_ptr.h"
 #include "base/test/bind.h"
+#include "base/test/gmock_callback_support.h"
 #include "base/test/mock_callback.h"
 #include "base/test/scoped_feature_list.h"
 #include "content/browser/bluetooth/bluetooth_adapter_factory_wrapper.h"
@@ -891,6 +892,34 @@
   EXPECT_EQ(!on_demand_bonding_enabled(), read_value_callback_called);
 }
 
+TEST_P(WebBluetoothServiceImplBondingTest, IncompletePairingOnShutdown) {
+  RegisterTestCharacteristic();
+
+  EXPECT_CALL(test_bundle().characteristic(), ReadRemoteCharacteristic_(_))
+      .WillOnce(base::test::RunOnceCallback<0>(
+          device::BluetoothGattService::GATT_ERROR_NOT_AUTHORIZED,
+          std::vector<uint8_t>()));
+
+  base::MockCallback<
+      WebBluetoothServiceImpl::RemoteCharacteristicReadValueCallback>
+      callback;
+  if (on_demand_bonding_enabled()) {
+    // The pairing is never completed so the callback won't be run before the
+    // test ends.
+    EXPECT_CALL(callback, Run(_, _)).Times(0);
+  } else {
+    EXPECT_CALL(callback, Run(WebBluetoothResult::GATT_NOT_AUTHORIZED,
+                              testing::Eq(absl::nullopt)));
+  }
+
+  service_->RemoteCharacteristicReadValue(
+      test_bundle().characteristic().GetIdentifier(), callback.Get());
+
+  // Simulate the WebBluetoothServiceImpl being destroyed due to a navigation or
+  // tab closure while the pairing request is in progress.
+  delete service_;
+}
+
 INSTANTIATE_TEST_SUITE_P(All,
                          WebBluetoothServiceImplBondingTest,
                          testing::Values(false, true));
diff --git a/content/browser/client_hints/client_hints.cc b/content/browser/client_hints/client_hints.cc
index 36425a8..ca70fa7 100644
--- a/content/browser/client_hints/client_hints.cc
+++ b/content/browser/client_hints/client_hints.cc
@@ -450,10 +450,6 @@
       .value_or(std::string());
 }
 
-bool IsSameOrigin(const GURL& url1, const GURL& url2) {
-  return url::Origin::Create(url1).IsSameOriginWith(url::Origin::Create(url2));
-}
-
 // Returns true iff the `url` is embedded inside a frame that has the
 // Sec-CH-UA-Reduced client hint and thus, is enrolled in the
 // UserAgentReduction Origin Trial.
@@ -475,7 +471,7 @@
     // Don't use Sec-CH-UA-Reduced from third-party origins if third-party
     // cookies are blocked, so that we don't reveal any more user data than
     // is allowed by the cookie settings.
-    if (IsSameOrigin(current_url, main_frame_url) ||
+    if (url::IsSameOriginWith(current_url, main_frame_url) ||
         !delegate->AreThirdPartyCookiesBlocked(current_url)) {
       blink::EnabledClientHints current_url_hints;
       delegate->GetAllowedClientHintsFromSource(current_url,
@@ -501,7 +497,6 @@
     std::vector<WebClientHintsType>* accept_ch,
     GURL* main_frame_url,
     GURL const** third_party_url) {
-  const url::Origin request_origin = url::Origin::Create(url);
   RenderFrameHostImpl* main_frame =
       frame_tree_node->frame_tree()->GetMainFrame();
 
@@ -513,7 +508,7 @@
     }
   }
 
-  if (!request_origin.IsSameOriginWith(main_frame->GetLastCommittedOrigin())) {
+  if (!main_frame->GetLastCommittedOrigin().IsSameOriginWith(url)) {
     // If third-party cookeis are blocked, we will not persist the
     // Sec-CH-UA-Reduced client hint in a third-party context.
     if (delegate->AreThirdPartyCookiesBlocked(url)) {
diff --git a/content/browser/content_index/content_index_service_impl.cc b/content/browser/content_index/content_index_service_impl.cc
index 175cffb..14958e3 100644
--- a/content/browser/content_index/content_index_service_impl.cc
+++ b/content/browser/content_index/content_index_service_impl.cc
@@ -134,8 +134,7 @@
     }
   }
 
-  if (!launch_url.is_valid() || !origin_.IsSameOriginWith(url::Origin::Create(
-                                    launch_url.DeprecatedGetOriginAsURL()))) {
+  if (!launch_url.is_valid() || !origin_.IsSameOriginWith(launch_url)) {
     mojo::ReportBadMessage("Invalid launch URL");
     std::move(callback).Run(blink::mojom::ContentIndexError::INVALID_PARAMETER);
     return;
diff --git a/content/browser/cookie_store/cookie_store_manager.cc b/content/browser/cookie_store/cookie_store_manager.cc
index ff5899c7..7bca0886 100644
--- a/content/browser/cookie_store/cookie_store_manager.cc
+++ b/content/browser/cookie_store/cookie_store_manager.cc
@@ -385,16 +385,15 @@
     return;
   }
 
-  const url::Origin first_origin = url::Origin::Create(it->second[0]->url());
+  const GURL& first_url = it->second[0]->url();
 #if DCHECK_IS_ON()
   for (const auto& subscription : it->second) {
-    DCHECK(
-        first_origin.IsSameOriginWith(url::Origin::Create(subscription->url())))
+    DCHECK(url::IsSameOriginWith(first_url, subscription->url()))
         << "Service worker's change subscriptions don't have the same origin";
   }
 #endif  // DCHECK_IS_ON()
 
-  if (!origin.IsSameOriginWith(first_origin)) {
+  if (!origin.IsSameOriginWith(first_url)) {
     std::move(bad_message_callback).Run("Invalid service worker");
     std::move(callback).Run(
         std::vector<blink::mojom::CookieChangeSubscriptionPtr>(), false);
diff --git a/content/browser/devtools/devtools_instrumentation.cc b/content/browser/devtools/devtools_instrumentation.cc
index 1e60a0c..49c3c4c 100644
--- a/content/browser/devtools/devtools_instrumentation.cc
+++ b/content/browser/devtools/devtools_instrumentation.cc
@@ -1245,6 +1245,34 @@
   DispatchToAgents(ftn, &protocol::LogHandler::EntryAdded, entry.get());
 }
 
+void OnServiceWorkerMainScriptRequestWillBeSent(
+    const GlobalRenderFrameHostId& requesting_frame_id,
+    const base::UnguessableToken& token,
+    const network::ResourceRequest& request) {
+  // Currently, `requesting_frame_id` is invalid when payment apps and
+  // extensions register a service worker. See the callers of
+  // ServiceWorkerContextWrapper::RegisterServiceWorker().
+  if (!requesting_frame_id)
+    return;
+
+  RenderFrameHostImpl* requesting_frame =
+      RenderFrameHostImpl::FromID(requesting_frame_id);
+  if (!requesting_frame)
+    return;
+
+  FrameTreeNode* ftn = requesting_frame->frame_tree_node();
+  DCHECK(ftn);
+
+  auto timestamp = base::TimeTicks::Now();
+  network::mojom::URLRequestDevToolsInfoPtr request_info =
+      network::ExtractDevToolsInfo(request);
+  DispatchToAgents(
+      ftn, &protocol::NetworkHandler::RequestSent, token.ToString(),
+      /*loader_id=*/"", request.headers, *request_info,
+      protocol::Network::Initiator::TypeEnum::Other, ftn->current_url(),
+      /*initiator_devtools_request_id=*/"", timestamp);
+}
+
 void OnWorkerMainScriptLoadingFailed(
     const GURL& url,
     const base::UnguessableToken& worker_token,
@@ -1284,7 +1312,7 @@
   DispatchToAgents(
       ftn, &protocol::NetworkHandler::RequestSent, worker_token.ToString(),
       /*loader_id=*/"", request.headers, *request_info,
-      protocol::Network::Initiator::TypeEnum::Script, ftn->current_url(),
+      protocol::Network::Initiator::TypeEnum::Other, ftn->current_url(),
       /*initiator_devtools_request_id*/ "", timestamp);
 }
 
diff --git a/content/browser/devtools/devtools_instrumentation.h b/content/browser/devtools/devtools_instrumentation.h
index 4cf044c..29416ce 100644
--- a/content/browser/devtools/devtools_instrumentation.h
+++ b/content/browser/devtools/devtools_instrumentation.h
@@ -292,6 +292,10 @@
 void OnServiceWorkerMainScriptFetchingFailed(
     const GlobalRenderFrameHostId& requesting_frame_id,
     const std::string& error);
+void OnServiceWorkerMainScriptRequestWillBeSent(
+    const GlobalRenderFrameHostId& requesting_frame_id,
+    const base::UnguessableToken& token,
+    const network::ResourceRequest& request);
 
 // Fires `Network.onLoadingFailed` event for a dedicated worker main script.
 // Used for PlzDedicatedWorker.
diff --git a/content/browser/devtools/devtools_url_loader_interceptor.cc b/content/browser/devtools/devtools_url_loader_interceptor.cc
index dbd96452..76f0054 100644
--- a/content/browser/devtools/devtools_url_loader_interceptor.cc
+++ b/content/browser/devtools/devtools_url_loader_interceptor.cc
@@ -1391,11 +1391,9 @@
 
   network::ResourceRequest* request = &create_loader_params_->request;
   const net::RedirectInfo& info = *response_metadata_->redirect_info;
-  const auto current_origin = url::Origin::Create(request->url);
-  const auto new_origin = url::Origin::Create(info.new_url);
   if (request->request_initiator &&
-      (!new_origin.IsSameOriginWith(current_origin) &&
-       !request->request_initiator->IsSameOriginWith(current_origin))) {
+      (!url::IsSameOriginWith(info.new_url, request->url) &&
+       !request->request_initiator->IsSameOriginWith(request->url))) {
     tainted_origin_ = true;
   }
 
@@ -1415,6 +1413,7 @@
   request->referrer_policy = info.new_referrer_policy;
   request->referrer = GURL(info.new_referrer);
   if (request->trusted_params) {
+    const auto new_origin = url::Origin::Create(info.new_url);
     request->trusted_params->isolation_info =
         request->trusted_params->isolation_info.CreateForRedirect(new_origin);
   }
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc
index c25d171..b89325c 100644
--- a/content/browser/devtools/protocol/network_handler.cc
+++ b/content/browser/devtools/protocol/network_handler.cc
@@ -2153,14 +2153,24 @@
     request_object->SetTrustTokenParams(
         BuildTrustTokenParams(*request_info.trust_token_params));
   }
+
+  std::string resource_type = Network::ResourceTypeEnum::Other;
+  if (request_info.resource_type ==
+          static_cast<int>(blink::mojom::ResourceType::kWorker) ||
+      request_info.resource_type ==
+          static_cast<int>(blink::mojom::ResourceType::kSharedWorker) ||
+      request_info.resource_type ==
+          static_cast<int>(blink::mojom::ResourceType::kServiceWorker)) {
+    resource_type = Network::ResourceTypeEnum::Script;
+  }
+
   // TODO(crbug.com/1261605): Populate redirect_emitted_extra_info instead of
   // just returning false.
   frontend_->RequestWillBeSent(
       request_id, loader_id, url_without_fragment, std::move(request_object),
       timestamp.since_origin().InSecondsF(), base::Time::Now().ToDoubleT(),
       std::move(initiator), /*redirect_emitted_extra_info=*/false,
-      std::unique_ptr<Network::Response>(),
-      std::string(Network::ResourceTypeEnum::Other),
+      std::unique_ptr<Network::Response>(), resource_type,
       Maybe<std::string>() /* frame_id */, request_info.has_user_gesture);
 }
 
diff --git a/content/browser/direct_sockets/direct_sockets_service_impl.cc b/content/browser/direct_sockets/direct_sockets_service_impl.cc
index 64f926e7..3248b18 100644
--- a/content/browser/direct_sockets/direct_sockets_service_impl.cc
+++ b/content/browser/direct_sockets/direct_sockets_service_impl.cc
@@ -515,7 +515,7 @@
 
   for (std::string& origin_string : origin_strings) {
     GURL url(std::move(origin_string));
-    if (last_committed_origin.IsSameOriginWith(url::Origin::Create(url))) {
+    if (last_committed_origin.IsSameOriginWith(url)) {
       return true;
     }
   }
diff --git a/content/browser/interest_group/ad_auction_service_impl.cc b/content/browser/interest_group/ad_auction_service_impl.cc
index fd46537f..1b021ef 100644
--- a/content/browser/interest_group/ad_auction_service_impl.cc
+++ b/content/browser/interest_group/ad_auction_service_impl.cc
@@ -16,6 +16,7 @@
 #include "content/browser/fenced_frame/fenced_frame_url_mapping.h"
 #include "content/browser/interest_group/ad_auction_result_metrics.h"
 #include "content/browser/interest_group/auction_runner.h"
+#include "content/browser/interest_group/auction_worklet_manager.h"
 #include "content/browser/interest_group/interest_group_manager.h"
 #include "content/browser/renderer_host/page_impl.h"
 #include "content/browser/renderer_host/render_frame_host_impl.h"
@@ -179,8 +180,12 @@
     : DocumentService(render_frame_host, std::move(receiver)),
       main_frame_origin_(
           render_frame_host->GetMainFrame()->GetLastCommittedOrigin()),
-      main_frame_url_(
-          render_frame_host->GetMainFrame()->GetLastCommittedURL()) {}
+      main_frame_url_(render_frame_host->GetMainFrame()->GetLastCommittedURL()),
+      auction_worklet_manager_(
+          &GetInterestGroupManager().auction_process_manager(),
+          GetTopWindowOrigin(),
+          origin(),
+          this) {}
 
 AdAuctionServiceImpl::~AdAuctionServiceImpl() {
   while (!auctions_.empty()) {
@@ -317,20 +322,13 @@
     return;
   }
 
-  url::Origin top_frame_origin;
-  if (!render_frame_host()->GetParent()) {
-    top_frame_origin = frame_origin;
-  } else {
-    top_frame_origin =
-        render_frame_host()->GetMainFrame()->GetLastCommittedOrigin();
-  }
-
   auto browser_signals = auction_worklet::mojom::BrowserSignals::New(
-      std::move(top_frame_origin), config->seller);
+      GetTopWindowOrigin(), config->seller);
 
   std::unique_ptr<AuctionRunner> auction = AuctionRunner::CreateAndStart(
-      this, &GetInterestGroupManager(), std::move(config),
-      std::move(filtered_buyers), std::move(browser_signals), frame_origin,
+      &auction_worklet_manager_, this, &GetInterestGroupManager(),
+      std::move(config), std::move(filtered_buyers), std::move(browser_signals),
+      frame_origin,
       base::BindOnce(&AdAuctionServiceImpl::OnAuctionComplete,
                      base::Unretained(this), std::move(callback)));
   auctions_.insert(std::move(auction));
@@ -485,4 +483,10 @@
               ->GetInterestGroupManager();
 }
 
+url::Origin AdAuctionServiceImpl::GetTopWindowOrigin() const {
+  if (!render_frame_host()->GetParent())
+    return origin();
+  return render_frame_host()->GetMainFrame()->GetLastCommittedOrigin();
+}
+
 }  // namespace content
diff --git a/content/browser/interest_group/ad_auction_service_impl.h b/content/browser/interest_group/ad_auction_service_impl.h
index 772c57c..8958c10 100644
--- a/content/browser/interest_group/ad_auction_service_impl.h
+++ b/content/browser/interest_group/ad_auction_service_impl.h
@@ -9,7 +9,7 @@
 #include <set>
 
 #include "base/containers/unique_ptr_adapters.h"
-#include "content/browser/interest_group/auction_runner.h"
+#include "content/browser/interest_group/auction_worklet_manager.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/document_service.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
@@ -32,7 +32,7 @@
 // Implements the AdAuctionService service called by Blink code.
 class CONTENT_EXPORT AdAuctionServiceImpl final
     : public DocumentService<blink::mojom::AdAuctionService>,
-      public AuctionRunner::Delegate {
+      public AuctionWorkletManager::Delegate {
  public:
   // Factory method for creating an instance of this interface that is
   // bound to the lifetime of the frame or receiver (whichever is shorter).
@@ -83,19 +83,22 @@
 
   InterestGroupManager& GetInterestGroupManager() const;
 
-  // This must be above `auction_worklet_service_`, since auctions may own
-  // callbacks over the AuctionWorkletService pipe, and mojo pipes must be
-  // destroyed before any callbacks that are bound to them.
-  std::set<std::unique_ptr<AuctionRunner>, base::UniquePtrComparator> auctions_;
-
-  mojo::Remote<network::mojom::URLLoaderFactory> frame_url_loader_factory_;
-  mojo::Remote<network::mojom::URLLoaderFactory> trusted_url_loader_factory_;
+  url::Origin GetTopWindowOrigin() const;
 
   // To avoid race conditions associated with top frame navigations (mentioned
   // in document_service.h), we need to save the values of the main frame
   // URL and origin in the constructor.
   const url::Origin main_frame_origin_;
   const GURL main_frame_url_;
+
+  mojo::Remote<network::mojom::URLLoaderFactory> frame_url_loader_factory_;
+  mojo::Remote<network::mojom::URLLoaderFactory> trusted_url_loader_factory_;
+
+  // This must be before `auctions_`, since auctions may own references to
+  // worklets it manages.
+  AuctionWorkletManager auction_worklet_manager_;
+
+  std::set<std::unique_ptr<AuctionRunner>, base::UniquePtrComparator> auctions_;
 };
 
 }  // namespace content
diff --git a/content/browser/interest_group/ad_auction_service_impl_unittest.cc b/content/browser/interest_group/ad_auction_service_impl_unittest.cc
index 4812d1a..df3edc5 100644
--- a/content/browser/interest_group/ad_auction_service_impl_unittest.cc
+++ b/content/browser/interest_group/ad_auction_service_impl_unittest.cc
@@ -23,6 +23,7 @@
 #include "content/browser/fenced_frame/fenced_frame_url_mapping.h"
 #include "content/browser/interest_group/auction_process_manager.h"
 #include "content/browser/interest_group/interest_group_manager.h"
+#include "content/browser/interest_group/interest_group_storage.h"
 #include "content/browser/renderer_host/render_frame_host_impl.h"
 #include "content/browser/storage_partition_impl.h"
 #include "content/public/browser/back_forward_cache.h"
diff --git a/content/browser/interest_group/auction_process_manager.h b/content/browser/interest_group/auction_process_manager.h
index aea0ab80..b65f0223 100644
--- a/content/browser/interest_group/auction_process_manager.h
+++ b/content/browser/interest_group/auction_process_manager.h
@@ -138,6 +138,9 @@
   size_t GetPendingSellerRequestsForTesting() const {
     return pending_seller_request_queue_.size();
   }
+  size_t GetSellerProcessCountForTesting() const {
+    return seller_processes_.size();
+  }
 
  protected:
   // Launches the actual process. Virtual so tests can override it.
diff --git a/content/browser/interest_group/auction_process_manager_unittest.cc b/content/browser/interest_group/auction_process_manager_unittest.cc
index cb26ed3..45820bf3 100644
--- a/content/browser/interest_group/auction_process_manager_unittest.cc
+++ b/content/browser/interest_group/auction_process_manager_unittest.cc
@@ -66,8 +66,7 @@
       mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory,
       const GURL& script_source_url,
       const absl::optional<GURL>& trusted_scoring_signals_url,
-      const url::Origin& top_window_origin,
-      LoadSellerWorkletCallback callback) override {
+      const url::Origin& top_window_origin) override {
     NOTREACHED();
   }
 
diff --git a/content/browser/interest_group/auction_runner.cc b/content/browser/interest_group/auction_runner.cc
index 90fb387..2a22085 100644
--- a/content/browser/interest_group/auction_runner.cc
+++ b/content/browser/interest_group/auction_runner.cc
@@ -4,6 +4,8 @@
 
 #include "content/browser/interest_group/auction_runner.h"
 
+#include <stdint.h>
+
 #include <algorithm>
 #include <string>
 #include <vector>
@@ -18,6 +20,7 @@
 #include "base/time/time.h"
 #include "content/browser/interest_group/auction_process_manager.h"
 #include "content/browser/interest_group/auction_url_loader_factory_proxy.h"
+#include "content/browser/interest_group/auction_worklet_manager.h"
 #include "content/browser/interest_group/debuggable_auction_worklet.h"
 #include "content/browser/interest_group/interest_group_manager.h"
 #include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom.h"
@@ -127,7 +130,8 @@
 }
 
 std::unique_ptr<AuctionRunner> AuctionRunner::CreateAndStart(
-    Delegate* delegate,
+    AuctionWorkletManager* auction_worklet_manager,
+    AuctionWorkletManager::Delegate* auction_worklet_manager_delegate,
     InterestGroupManager* interest_group_manager,
     blink::mojom::AuctionAdConfigPtr auction_config,
     std::vector<url::Origin> filtered_buyers,
@@ -136,20 +140,23 @@
     RunAuctionCallback callback) {
   DCHECK(!filtered_buyers.empty());
   std::unique_ptr<AuctionRunner> instance(new AuctionRunner(
-      delegate, interest_group_manager, std::move(auction_config),
+      auction_worklet_manager, auction_worklet_manager_delegate,
+      interest_group_manager, std::move(auction_config),
       std::move(browser_signals), frame_origin, std::move(callback)));
   instance->ReadInterestGroups(std::move(filtered_buyers));
   return instance;
 }
 
 AuctionRunner::AuctionRunner(
-    Delegate* delegate,
+    AuctionWorkletManager* auction_worklet_manager,
+    AuctionWorkletManager::Delegate* auction_worklet_manager_delegate,
     InterestGroupManager* interest_group_manager,
     blink::mojom::AuctionAdConfigPtr auction_config,
     auction_worklet::mojom::BrowserSignalsPtr browser_signals,
     const url::Origin& frame_origin,
     RunAuctionCallback callback)
-    : delegate_(delegate),
+    : auction_worklet_manager_(auction_worklet_manager),
+      auction_worklet_manager_delegate_(auction_worklet_manager_delegate),
       interest_group_manager_(interest_group_manager),
       auction_config_(std::move(auction_config)),
       browser_signals_(std::move(browser_signals)),
@@ -159,11 +166,10 @@
 AuctionRunner::~AuctionRunner() = default;
 
 void AuctionRunner::FailAuction(AuctionResult result,
-                                absl::optional<std::string> error) {
+                                const std::vector<std::string>& errors) {
   DCHECK(callback_);
 
-  if (error)
-    errors_.emplace_back(std::move(error).value());
+  errors_.insert(errors_.end(), errors.begin(), errors.end());
   RecordResult(result);
 
   ClosePipes();
@@ -221,62 +227,28 @@
 
   num_bids_not_sent_to_seller_worklet_ = bid_states_.size();
   outstanding_bids_ = num_bids_not_sent_to_seller_worklet_;
-  RequestSellerWorkletProcess();
+  RequestSellerWorklet();
 }
 
-void AuctionRunner::RequestSellerWorkletProcess() {
-  seller_worklet_process_handle_ =
-      std::make_unique<AuctionProcessManager::ProcessHandle>();
-
-  // Request a seller worklet process. If one is received synchronously, start
-  // loading the seller worklet and requesting bidder processes.
-  if (interest_group_manager_->auction_process_manager().RequestWorkletService(
-          AuctionProcessManager::WorkletType::kSeller, auction_config_->seller,
-          seller_worklet_process_handle_.get(),
-          base::BindOnce(&AuctionRunner::OnSellerWorkletProcessReceived,
-                         base::Unretained(this)))) {
-    OnSellerWorkletProcessReceived();
+void AuctionRunner::RequestSellerWorklet() {
+  if (auction_worklet_manager_->RequestSellerWorklet(
+          auction_config_->decision_logic_url,
+          auction_config_->trusted_scoring_signals_url,
+          base::BindOnce(&AuctionRunner::OnSellerWorkletReceived,
+                         base::Unretained(this)),
+          base::BindOnce(&AuctionRunner::OnSellerWorkletFatalError,
+                         base::Unretained(this)),
+          seller_worklet_handle_)) {
+    OnSellerWorkletReceived();
   }
 }
 
-void AuctionRunner::OnSellerWorkletProcessReceived() {
+void AuctionRunner::OnSellerWorkletReceived() {
   // Auctions are only run when there are bidders participating. As-is, an
   // empty bidder vector here would result in synchronously calling back into
   // the creator, which isn't allowed.
   DCHECK(!bid_states_.empty());
 
-  // Start loading the seller worklet.
-  const GURL& seller_url = auction_config_->decision_logic_url;
-  mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory;
-  seller_url_loader_factory_ = std::make_unique<AuctionURLLoaderFactoryProxy>(
-      url_loader_factory.InitWithNewPipeAndPassReceiver(),
-      base::BindRepeating(&Delegate::GetFrameURLLoaderFactory,
-                          base::Unretained(delegate_)),
-      base::BindRepeating(&Delegate::GetTrustedURLLoaderFactory,
-                          base::Unretained(delegate_)),
-      browser_signals_->top_frame_origin, frame_origin_,
-      /*is_for_seller_=*/true, delegate_->GetClientSecurityState(), seller_url,
-      /*wasm_url=*/absl::nullopt,
-      /*trusted_signals_base_url=*/
-      auction_config_->trusted_scoring_signals_url);
-  mojo::PendingReceiver<auction_worklet::mojom::SellerWorklet>
-      worklet_receiver = seller_worklet_.BindNewPipeAndPassReceiver();
-  seller_worklet_debug_ = base::WrapUnique(new DebuggableAuctionWorklet(
-      delegate_->GetFrame(), seller_url, seller_worklet_.get()));
-  seller_worklet_process_handle_->GetService()->LoadSellerWorklet(
-      std::move(worklet_receiver),
-      seller_worklet_debug_->should_pause_on_start(),
-      std::move(url_loader_factory), seller_url,
-      auction_config_->trusted_scoring_signals_url,
-      browser_signals_->top_frame_origin,
-      base::BindOnce(&AuctionRunner::OnSellerWorkletLoaded,
-                     base::Unretained(this)));
-  // Fail auction if the seller worklet pipe is disconnected.
-  seller_worklet_.set_disconnect_handler(
-      base::BindOnce(&AuctionRunner::FailAuction, base::Unretained(this),
-                     AuctionResult::kSellerWorkletCrashed,
-                     base::StrCat({seller_url.spec(), " crashed."})));
-
   // Request processes for all bidder worklets.
   for (auto& bid_state : bid_states_) {
     DCHECK_EQ(bid_state.state,
@@ -297,6 +269,21 @@
   }
 }
 
+void AuctionRunner::OnSellerWorkletFatalError(
+    AuctionWorkletManager::FatalErrorType fatal_error_type,
+    const std::vector<std::string>& errors) {
+  AuctionResult result;
+  switch (fatal_error_type) {
+    case AuctionWorkletManager::FatalErrorType::kScriptLoadFailed:
+      result = AuctionResult::kSellerWorkletLoadFailed;
+      break;
+    case AuctionWorkletManager::FatalErrorType::kWorkletCrash:
+      result = AuctionResult::kSellerWorkletCrashed;
+      break;
+  }
+  FailAuction(result, errors);
+}
+
 void AuctionRunner::OnBidderWorkletProcessReceived(BidState* bid_state) {
   DCHECK_EQ(bid_state->state, BidState::State::kWaitingForProcess);
 
@@ -360,14 +347,10 @@
     state->state = BidState::State::kScoringComplete;
     --num_bids_not_sent_to_seller_worklet_;
     // If this is the only bid that yet to be sent to the seller worklet, and
-    // the seller worklet has loaded, then need to tell the SellerWorklet that
-    // no more bids coming.
-    //
-    // Note that this is called even if the seller hasn't loaded yet (which is
-    // safe to do, but not useful). Calling unconditionally is currently needed
-    // for a couple unit tests to pass.
+    // the seller worklet has loaded, then tell the seller worklet to send any
+    // pending scoring signals request to complete the auction more quickly.
     if (num_bids_not_sent_to_seller_worklet_ == 0)
-      seller_worklet_->SendPendingSignalsRequests();
+      seller_worklet_handle_->GetSellerWorklet()->SendPendingSignalsRequests();
     --outstanding_bids_;
     MaybeCompleteAuction();
     return;
@@ -375,58 +358,32 @@
 
   state->bid_result = std::move(bid);
   state->state = BidState::State::kWaitingOnSellerWorkletLoad;
-  if (seller_loaded_)
-    ScoreBid(state);
-}
-
-void AuctionRunner::OnSellerWorkletLoaded(
-    bool load_result,
-    const std::vector<std::string>& errors) {
-  errors_.insert(errors_.end(), errors.begin(), errors.end());
-
-  if (!load_result) {
-    // Failed to load the seller/auction script --- nothing useful can be
-    // done, so abort, possibly cancelling other fetches, so we don't waste
-    // time.
-    FailAuction(AuctionResult::kSellerWorkletLoadFailed);
-    return;
-  }
-
-  seller_loaded_ = true;
-  // Start scoring any bids that were waiting on the seller worklet to load.
-  for (BidState& state : bid_states_) {
-    // Bids can be complete at this point (if no bid was offered, or on
-    // error), but they can't be scoring a bid.
-    DCHECK_NE(state.state, BidState::State::kSellerScoringBid);
-
-    if (state.state == BidState::State::kWaitingOnSellerWorkletLoad)
-      ScoreBid(&state);
-  }
+  ScoreBid(state);
 }
 
 void AuctionRunner::ScoreBid(BidState* state) {
-  DCHECK(seller_loaded_);
   DCHECK_GT(num_bids_not_sent_to_seller_worklet_, 0);
   DCHECK_GT(outstanding_bids_, 0);
   DCHECK_EQ(state->state, BidState::State::kWaitingOnSellerWorkletLoad);
   state->state = BidState::State::kSellerScoringBid;
 
-  seller_worklet_->ScoreAd(
+  seller_worklet_handle_->GetSellerWorklet()->ScoreAd(
       state->bid_result->ad, state->bid_result->bid,
       auction_config_->shareable_auction_ad_config.Clone(),
       state->bidder.interest_group.owner, state->bid_result->render_url,
       state->bid_result->ad_components ? *state->bid_result->ad_components
                                        : std::vector<GURL>(),
       state->bid_result->bid_duration.InMilliseconds(),
-      base::BindOnce(&AuctionRunner::OnBidScored, base::Unretained(this),
-                     state));
+      base::BindOnce(&AuctionRunner::OnBidScored,
+                     weak_ptr_factory_.GetWeakPtr(), state));
 
   // If this was the last bid that needed to be passed to ScoreAd(), tell the
   // SellerWorklet no more bids are coming, so it can send a request for any
   // needed scoring signals now, if needed.
   --num_bids_not_sent_to_seller_worklet_;
-  if (num_bids_not_sent_to_seller_worklet_ == 0)
-    seller_worklet_->SendPendingSignalsRequests();
+  if (num_bids_not_sent_to_seller_worklet_ == 0) {
+    seller_worklet_handle_->GetSellerWorklet()->SendPendingSignalsRequests();
+  }
 }
 
 void AuctionRunner::OnBidScored(BidState* state,
@@ -509,13 +466,13 @@
   DCHECK(top_bidder_->bid_result);
   DCHECK_GT(top_bidder_->seller_score, 0);
 
-  seller_worklet_->ReportResult(
+  seller_worklet_handle_->GetSellerWorklet()->ReportResult(
       auction_config_->shareable_auction_ad_config.Clone(),
       top_bidder_->bidder.interest_group.owner,
       top_bidder_->bid_result->render_url, top_bidder_->bid_result->bid,
       top_bidder_->seller_score,
       base::BindOnce(&AuctionRunner::OnReportSellerResultComplete,
-                     base::Unretained(this)));
+                     weak_ptr_factory_.GetWeakPtr()));
 }
 
 void AuctionRunner::OnReportSellerResultComplete(
@@ -655,9 +612,7 @@
   for (BidState& bid_state : bid_states_) {
     bid_state.ClosePipes();
   }
-  seller_worklet_debug_.reset();
-  seller_worklet_.reset();
-  seller_worklet_process_handle_.reset();
+  seller_worklet_handle_.reset();
 }
 
 void AuctionRunner::RecordResult(AuctionResult result) const {
@@ -696,10 +651,12 @@
       url_loader_factory.InitWithNewPipeAndPassReceiver(),
       // BidderWorklets don't need frame URLLoaderFactories.
       AuctionURLLoaderFactoryProxy::GetUrlLoaderFactoryCallback(),
-      base::BindRepeating(&Delegate::GetTrustedURLLoaderFactory,
-                          base::Unretained(delegate_)),
+      base::BindRepeating(
+          &AuctionWorkletManager::Delegate::GetTrustedURLLoaderFactory,
+          base::Unretained(auction_worklet_manager_delegate_)),
       browser_signals_->top_frame_origin, frame_origin_,
-      /*is_for_seller=*/false, delegate_->GetClientSecurityState(), bidding_url,
+      /*is_for_seller=*/false,
+      auction_worklet_manager_delegate_->GetClientSecurityState(), bidding_url,
       bid_state.bidder.interest_group.bidding_wasm_helper_url,
       interest_group.trusted_bidding_signals_url);
 
@@ -707,7 +664,8 @@
       worklet_receiver = bid_state.bidder_worklet.BindNewPipeAndPassReceiver();
   bid_state.bidder_worklet_debug =
       base::WrapUnique(new DebuggableAuctionWorklet(
-          delegate_->GetFrame(), bidding_url, bid_state.bidder_worklet.get()));
+          auction_worklet_manager_delegate_->GetFrame(), bidding_url,
+          bid_state.bidder_worklet.get()));
 
   bid_state.process_handle->GetService()->LoadBidderWorklet(
       std::move(worklet_receiver),
diff --git a/content/browser/interest_group/auction_runner.h b/content/browser/interest_group/auction_runner.h
index 9022c670..24451f2 100644
--- a/content/browser/interest_group/auction_runner.h
+++ b/content/browser/interest_group/auction_runner.h
@@ -5,6 +5,8 @@
 #ifndef CONTENT_BROWSER_INTEREST_GROUP_AUCTION_RUNNER_H_
 #define CONTENT_BROWSER_INTEREST_GROUP_AUCTION_RUNNER_H_
 
+#include <stdint.h>
+
 #include <memory>
 #include <string>
 #include <vector>
@@ -15,6 +17,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "content/browser/interest_group/auction_process_manager.h"
+#include "content/browser/interest_group/auction_worklet_manager.h"
 #include "content/browser/interest_group/interest_group_storage.h"
 #include "content/common/content_export.h"
 #include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom-forward.h"
@@ -23,7 +26,6 @@
 #include "content/services/auction_worklet/public/mojom/seller_worklet.mojom.h"
 #include "mojo/public/cpp/bindings/connection_error_callback.h"
 #include "mojo/public/cpp/bindings/remote.h"
-#include "services/network/public/mojom/client_security_state.mojom-forward.h"
 #include "services/network/public/mojom/url_loader_factory.mojom-forward.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/public/common/interest_group/interest_group.h"
@@ -35,7 +37,6 @@
 class AuctionURLLoaderFactoryProxy;
 class DebuggableAuctionWorklet;
 class InterestGroupManager;
-class RenderFrameHostImpl;
 
 // An AuctionRunner loads and runs the bidder and seller worklets, along with
 // their reporting phases and produces the result via a callback.
@@ -65,29 +66,6 @@
       const absl::optional<GURL> seller_report_url,
       std::vector<std::string> errors)>;
 
-  // Delegate class to allow dependency injection in tests. Note that all
-  // objects this returns can crash and be restarted, so passing in raw pointers
-  // would be problematic.
-  class Delegate {
-   public:
-    // Returns the URLLoaderFactory of the frame running the auction. Used to
-    // load the seller worklet in the context of the parent frame, since unlike
-    // other worklet types, it has no first party opt-in, and it's not a
-    // cross-origin leak if the parent from knows its URL, since the parent
-    // frame provided the URL in the first place.
-    virtual network::mojom::URLLoaderFactory* GetFrameURLLoaderFactory() = 0;
-
-    // Trusted URLLoaderFactory used to load bidder worklets.
-    virtual network::mojom::URLLoaderFactory* GetTrustedURLLoaderFactory() = 0;
-
-    // Get containing frame. (Passed to debugging hooks).
-    virtual RenderFrameHostImpl* GetFrame() = 0;
-
-    // Returns the ClientSecurityState associated with the frame, for use in
-    // bidder worklet and signals fetches.
-    virtual network::mojom::ClientSecurityStatePtr GetClientSecurityState() = 0;
-  };
-
   // Result of an auction. Used for histograms. Only recorded for valid
   // auctions. These are used in histograms, so values of existing entries must
   // not change when adding/removing values, and obsolete values must not be
@@ -129,24 +107,25 @@
   explicit AuctionRunner(const AuctionRunner&) = delete;
   AuctionRunner& operator=(const AuctionRunner&) = delete;
 
-  // Fails the auction, invoking `callback_` and preventis any future calls into
+  // Fails the auction, invoking `callback_` and prevents any future calls into
   // `this` by closing mojo pipes and disposing of weak pointers. The owner must
   // be able to safely delete `this` when the callback is invoked. May only be
   // invoked if the auction has not yet completed.
   //
   // `result` is used for logging purposes only.
   //
-  // If `error` is non-null, it will be appended to `errors_`.
+  // `errors` is appended to `errors_`.
   //
   // Public so that the owner can fail the auction on teardown, to invoke any
   // pending Mojo callbacks.
   void FailAuction(AuctionResult result,
-                   absl::optional<std::string> error = absl::nullopt);
+                   const std::vector<std::string>& errors = {});
 
   // Runs an entire FLEDGE auction.
   //
   // Arguments:
-  // `delegate` and `interest_group_manager` must remain valid until the
+  // `auction_worklet_manager`, `auction_worklet_manager_delegate`, and
+  // `interest_group_manager` must remain valid until the
   //  AuctionRunner is destroyed.
   //
   // `auction_config` is the configuration provided by client JavaScript in
@@ -163,7 +142,8 @@
   // `frame_origin` is the origin running the auction (not the top frame
   // origin), used as the initiator in network requests.
   static std::unique_ptr<AuctionRunner> CreateAndStart(
-      Delegate* delegate,
+      AuctionWorkletManager* auction_worklet_manager,
+      AuctionWorkletManager::Delegate* auction_worklet_manager_delegate,
       InterestGroupManager* interest_group_manager,
       blink::mojom::AuctionAdConfigPtr auction_config,
       std::vector<url::Origin> filtered_buyers,
@@ -236,12 +216,14 @@
     double seller_score = 0;
   };
 
-  AuctionRunner(Delegate* delegate,
-                InterestGroupManager* interest_group_manager,
-                blink::mojom::AuctionAdConfigPtr auction_config,
-                auction_worklet::mojom::BrowserSignalsPtr browser_signals,
-                const url::Origin& frame_origin,
-                RunAuctionCallback callback);
+  AuctionRunner(
+      AuctionWorkletManager* auction_worklet_manager,
+      AuctionWorkletManager::Delegate* auction_worklet_manager_delegate,
+      InterestGroupManager* interest_group_manager,
+      blink::mojom::AuctionAdConfigPtr auction_config,
+      auction_worklet::mojom::BrowserSignalsPtr browser_signals,
+      const url::Origin& frame_origin,
+      RunAuctionCallback callback);
 
   // Starts retrieving all interest groups owned by `filtered_buyers` from
   // storage. OnInterestGroupRead() will be invoked with the lookup results for
@@ -253,14 +235,19 @@
   // StartBidding().
   void OnInterestGroupRead(std::vector<StorageInterestGroup> interest_groups);
 
-  // Request seller worklet process. No bidder processes are requested until a
-  // seller worklet process has been received.
-  void RequestSellerWorkletProcess();
+  // Requests a seller worklet from the AuctionWorkletManager. No bidder
+  // processes are requested until a seller worklet has been received.
+  void RequestSellerWorklet();
 
-  // Invoked once the AuctionProcessManager has provided a process for the
-  // seller worklet. Starts loading the seller worklet, and requests processes
-  // for all bidders.
-  void OnSellerWorkletProcessReceived();
+  // Invoked once the AuctionWorkletManager has provided a SellerWorkletHandle.
+  // Requests processes for all bidders.
+  void OnSellerWorkletReceived();
+
+  // Invoked by the SellerWorkletManager on fatal errors, at any point after a
+  // SellerWorklet has been provided. Results in auction immediately failing.
+  void OnSellerWorkletFatalError(
+      AuctionWorkletManager::FatalErrorType fatal_error_type,
+      const std::vector<std::string>& errors);
 
   // Invoked whenever the AuctionProcessManager has provided a process for a
   // bidder worklet. Starts loading the corresponding worklet and generating a
@@ -276,8 +263,6 @@
 
   // True if all bid results and the seller script load are complete.
   bool AllBidsScored() const { return outstanding_bids_ == 0; }
-  void OnSellerWorkletLoaded(bool load_result,
-                             const std::vector<std::string>& errors);
 
   // Calls into the seller asynchronously to score the passed in bid.
   void ScoreBid(BidState* state);
@@ -331,7 +316,9 @@
       BidState& bid_state,
       mojo::ConnectionErrorWithReasonCallback disconnect_handler);
 
-  const raw_ptr<Delegate> delegate_;
+  const raw_ptr<AuctionWorkletManager> auction_worklet_manager_;
+  const raw_ptr<AuctionWorkletManager::Delegate>
+      auction_worklet_manager_delegate_;
   const raw_ptr<InterestGroupManager> interest_group_manager_;
 
   // Configuration.
@@ -376,20 +363,8 @@
   // Number of bidders with the same score as `top_bidder`.
   size_t num_top_bidders_ = 0;
 
-  // URLLoaderFactory proxy class configured only to load the URL the seller
-  // needs.
-  std::unique_ptr<AuctionURLLoaderFactoryProxy> seller_url_loader_factory_;
-
-  // State for the scoring phase.
-  std::unique_ptr<AuctionProcessManager::ProcessHandle>
-      seller_worklet_process_handle_;
-  mojo::Remote<auction_worklet::mojom::SellerWorklet> seller_worklet_;
-  std::unique_ptr<DebuggableAuctionWorklet> seller_worklet_debug_;
-
-  // This is true if the seller script has been loaded successfully --- if the
-  // load failed, the entire process is aborted since there is nothing useful
-  // that can be done.
-  bool seller_loaded_ = false;
+  // Holds a reference to the SellerWorklet used by the auction.
+  std::unique_ptr<AuctionWorkletManager::WorkletHandle> seller_worklet_handle_;
 
   // Seller script reportResult() results.
   absl::optional<GURL> seller_report_url_;
diff --git a/content/browser/interest_group/auction_runner_unittest.cc b/content/browser/interest_group/auction_runner_unittest.cc
index 936fa8c..51b3b8a 100644
--- a/content/browser/interest_group/auction_runner_unittest.cc
+++ b/content/browser/interest_group/auction_runner_unittest.cc
@@ -22,6 +22,7 @@
 #include "base/test/task_environment.h"
 #include "base/time/time.h"
 #include "content/browser/interest_group/auction_process_manager.h"
+#include "content/browser/interest_group/auction_worklet_manager.h"
 #include "content/browser/interest_group/debuggable_auction_worklet.h"
 #include "content/browser/interest_group/debuggable_auction_worklet_tracker.h"
 #include "content/browser/interest_group/interest_group_manager.h"
@@ -442,14 +443,8 @@
 
   explicit MockSellerWorklet(
       mojo::PendingReceiver<auction_worklet::mojom::SellerWorklet>
-          pending_receiver,
-      mojo::PendingRemote<network::mojom::URLLoaderFactory>
-          pending_url_loader_factory,
-      auction_worklet::mojom::AuctionWorkletService::LoadSellerWorkletCallback
-          load_worklet_callback)
-      : load_worklet_callback_(std::move(load_worklet_callback)),
-        url_loader_factory_(std::move(pending_url_loader_factory)),
-        receiver_(this, std::move(pending_receiver)) {}
+          pending_receiver)
+      : receiver_(this, std::move(pending_receiver)) {}
 
   MockSellerWorklet(const MockSellerWorklet&) = delete;
   const MockSellerWorklet& operator=(const MockSellerWorklet&) = delete;
@@ -457,6 +452,9 @@
   ~MockSellerWorklet() override {
     EXPECT_EQ(expect_send_pending_signals_requests_called_,
               send_pending_signals_requests_called_);
+
+    // Every received ScoreAd() call should have been waited for.
+    EXPECT_TRUE(score_ad_params_.empty());
   }
 
   // auction_worklet::mojom::SellerWorklet implementation:
@@ -507,26 +505,11 @@
         << "ConnectDevToolsAgent should not be called on MockSellerWorklet";
   }
 
-  // Informs the consumer that the seller worklet has successfully loaded.
-  void CompleteLoading() {
-    DCHECK(load_worklet_callback_);
-
-    // If a worklet completes loading successfully,
-    // `send_pending_signals_requests_called_` is always called, unless the
-    // seller worklet crashes. This includes the case where no bidders
-    // successfully bid, though it's not strictly needed in that case.
-    expect_send_pending_signals_requests_called_ = true;
-
-    std::move(load_worklet_callback_)
-        .Run(true /* success */, std::vector<std::string>() /* errors */);
-  }
-
   // Waits until ScoreAd() has been invoked, if it hasn't been already. It's up
   // to the caller to invoke the returned ScoreAdParams::callback to continue
   // the auction.
   ScoreAdParams WaitForScoreAd() {
     DCHECK(!score_ad_run_loop_);
-    DCHECK(!load_worklet_callback_);
     if (score_ad_params_.empty()) {
       score_ad_run_loop_ = std::make_unique<base::RunLoop>();
       score_ad_run_loop_->Run();
@@ -540,7 +523,6 @@
 
   void WaitForReportResult() {
     DCHECK(!report_result_run_loop_);
-    DCHECK(!load_worklet_callback_);
     if (!report_result_callback_) {
       report_result_run_loop_ = std::make_unique<base::RunLoop>();
       report_result_run_loop_->Run();
@@ -559,31 +541,23 @@
              std::vector<std::string>() /* errors */);
   }
 
-  mojo::Remote<network::mojom::URLLoaderFactory>& url_loader_factory() {
-    return url_loader_factory_;
-  }
-
   void Flush() { receiver_.FlushForTesting(); }
 
   // `expect_send_pending_signals_requests_called_` needs to be set to false in
-  // the case a SellerWorklet crash is simulated before the final bid is scored.
+  // the case a SellerWorklet is destroyed before it receives a request to score
+  // the final bid.
   void set_expect_send_pending_signals_requests_called(bool value) {
     expect_send_pending_signals_requests_called_ = value;
   }
 
  private:
-  auction_worklet::mojom::AuctionWorkletService::LoadSellerWorkletCallback
-      load_worklet_callback_;
-
   std::unique_ptr<base::RunLoop> score_ad_run_loop_;
   std::list<ScoreAdParams> score_ad_params_;
 
   std::unique_ptr<base::RunLoop> report_result_run_loop_;
   ReportResultCallback report_result_callback_;
 
-  mojo::Remote<network::mojom::URLLoaderFactory> url_loader_factory_;
-
-  bool expect_send_pending_signals_requests_called_ = false;
+  bool expect_send_pending_signals_requests_called_ = true;
   bool send_pending_signals_requests_called_ = false;
 
   // Receiver is last so that destroying `this` while there's a pending callback
@@ -671,8 +645,7 @@
           pending_url_loader_factory,
       const GURL& script_source_url,
       const absl::optional<GURL>& trusted_scoring_signals_url,
-      const url::Origin& top_window_origin,
-      LoadSellerWorkletCallback load_seller_worklet_callback) override {
+      const url::Origin& top_window_origin) override {
     DCHECK(!seller_worklet_);
 
     // Make sure this request came over the right pipe.
@@ -680,10 +653,8 @@
               ComputeDisplayName(AuctionProcessManager::WorkletType::kSeller,
                                  url::Origin::Create(script_source_url)));
 
-    seller_worklet_ = std::make_unique<MockSellerWorklet>(
-        std::move(seller_worklet_receiver),
-        std::move(pending_url_loader_factory),
-        std::move(load_seller_worklet_callback));
+    seller_worklet_ =
+        std::make_unique<MockSellerWorklet>(std::move(seller_worklet_receiver));
 
     ASSERT_TRUE(waiting_on_seller_);
     waiting_on_seller_ = false;
@@ -729,11 +700,6 @@
 
   void Flush() { receiver_set_.FlushForTesting(); }
 
-  // Close all the AuctionWorkletService pipes. Needs to be called before
-  // uninvoked worklet callbacks can be destroyed, which is useful after
-  // simulating a worklet crash.
-  void ClosePipes() { receiver_set_.Clear(); }
-
  private:
   void MaybeQuitWaitForWorkletsRunLoop() {
     DCHECK(wait_for_worklets_run_loop_);
@@ -804,7 +770,7 @@
 };
 
 class AuctionRunnerTest : public testing::Test,
-                          public AuctionRunner::Delegate,
+                          public AuctionWorkletManager::Delegate,
                           public DebuggableAuctionWorkletTracker::Observer {
  protected:
   // Output of the RunAuctionCallback passed to AuctionRunner::CreateAndStart().
@@ -903,13 +869,15 @@
     interest_group_manager_ = std::make_unique<InterestGroupManager>(
         base::FilePath(), true /* in_memory */,
         /* url_loader_factory */ nullptr);
-    if (auction_process_manager_) {
-      interest_group_manager_->set_auction_process_manager_for_testing(
-          std::move(auction_process_manager_));
-    } else {
-      interest_group_manager_->set_auction_process_manager_for_testing(
-          std::make_unique<SameProcessAuctionProcessManager>());
+    if (!auction_process_manager_) {
+      auction_process_manager_ =
+          std::make_unique<SameProcessAuctionProcessManager>();
     }
+    auction_worklet_manager_ = std::make_unique<AuctionWorkletManager>(
+        auction_process_manager_.get(), browser_signals->top_frame_origin,
+        frame_origin_, this);
+    interest_group_manager_->set_auction_process_manager_for_testing(
+        std::move(auction_process_manager_));
 
     histogram_tester_ = std::make_unique<base::HistogramTester>();
 
@@ -936,8 +904,8 @@
 
     auction_run_loop_ = std::make_unique<base::RunLoop>();
     auction_runner_ = AuctionRunner::CreateAndStart(
-        this, interest_group_manager_.get(), std::move(auction_config),
-        std::vector<url::Origin>{kBidder1, kBidder2},
+        auction_worklet_manager_.get(), this, interest_group_manager_.get(),
+        std::move(auction_config), std::vector<url::Origin>{kBidder1, kBidder2},
         std::move(browser_signals), frame_origin_,
         base::BindOnce(&AuctionRunnerTest::OnAuctionComplete,
                        base::Unretained(this)));
@@ -1099,7 +1067,7 @@
     mock_auction_process_manager_->WaitForWorklets(2 /* num_bidders */);
   }
 
-  // AuctionRunner::Delegate implementation:
+  // AuctionWorkletManager::Delegate implementation:
   network::mojom::URLLoaderFactory* GetFrameURLLoaderFactory() override {
     return &url_loader_factory_;
   }
@@ -1190,6 +1158,8 @@
 
   network::TestURLLoaderFactory url_loader_factory_;
 
+  std::unique_ptr<AuctionWorkletManager> auction_worklet_manager_;
+
   // This is used (and consumed) when starting an auction, if non-null. Allows
   // either using a MockAuctionProcessManager instead of a
   // SameProcessAuctionProcessManager, or using a SameProcessAuctionProcessManager
@@ -2293,7 +2263,7 @@
   EXPECT_EQ(0u, auction_process_manager->GetPendingBidderRequestsForTesting());
   EXPECT_FALSE(auction_complete_);
 
-  // Make kMaxBidderProcesses bidder worklet requests different bidder origins.
+  // Make kMaxBidderProcesses bidder worklet requests for different origins.
   // Do this after starting the auction, so the auction will incorrectly
   // complete once a seller worklet slot is freed if the auction already
   // requested bidder worklet processes.
@@ -2340,6 +2310,51 @@
                   2 /* expected_interest_groups */, 2 /* expected_owners */);
 }
 
+// Test a seller worklet load failure while waiting on bidder worklet processes
+// to be allocated. Most of the tests for global seller worklet failures at a
+// particular phase use seller crashes instead of load errors (see SellerCrash
+// test), but this case is simplest to test with a seller load error.
+TEST_F(AuctionRunnerTest, SellerLoadErrorWhileWaitingForBidders) {
+  // Create AuctionProcessManager in advance of starting the auction so can
+  // create worklets before the auction starts.
+  auction_process_manager_ =
+      std::make_unique<SameProcessAuctionProcessManager>();
+
+  // Make kMaxBidderProcesses bidder worklet requests for different origins.
+  std::list<std::unique_ptr<AuctionProcessManager::ProcessHandle>>
+      other_bidders;
+  for (size_t i = 0; i < AuctionProcessManager::kMaxBidderProcesses; ++i) {
+    other_bidders.push_back(
+        std::make_unique<AuctionProcessManager::ProcessHandle>());
+    url::Origin origin = url::Origin::Create(
+        GURL(base::StringPrintf("https://blocking.bidder.%zu.test", i)));
+    EXPECT_TRUE(auction_process_manager_->RequestWorkletService(
+        AuctionProcessManager::WorkletType::kBidder, origin,
+        &*other_bidders.back(), base::BindOnce([]() {
+          ADD_FAILURE() << "This should not be called";
+        })));
+  }
+
+  auction_worklet::AddJavascriptResponse(&url_loader_factory_, kSellerUrl,
+                                         MakeAuctionScript());
+
+  url_loader_factory_.AddResponse(kSellerUrl.spec(), "", net::HTTP_NOT_FOUND);
+
+  RunStandardAuction();
+
+  EXPECT_FALSE(result_.ad_url);
+  EXPECT_EQ(5, result_.bidder1_bid_count);
+  EXPECT_EQ(3u, result_.bidder1_prev_wins.size());
+  EXPECT_EQ(5, result_.bidder2_bid_count);
+  ASSERT_EQ(3u, result_.bidder2_prev_wins.size());
+  EXPECT_THAT(result_.errors,
+              testing::ElementsAre(
+                  "Failed to load https://adstuff.publisher1.com/auction.js "
+                  "HTTP status = 404 Not Found."));
+  CheckHistograms(AuctionRunner::AuctionResult::kSellerWorkletLoadFailed,
+                  2 /* expected_interest_groups */, 2 /* expected_owners */);
+}
+
 TEST_F(AuctionRunnerTest, AllBiddersCrashBeforeBidding) {
   StartStandardAuctionWithMockService();
   auto seller_worklet = mock_auction_process_manager_->TakeSellerWorklet();
@@ -2351,8 +2366,6 @@
       mock_auction_process_manager_->TakeBidderWorklet(kBidder2Url);
   ASSERT_TRUE(bidder2_worklet);
 
-  seller_worklet->CompleteLoading();
-
   EXPECT_FALSE(auction_complete_);
 
   EXPECT_THAT(observer_log_,
@@ -2422,8 +2435,6 @@
         mock_auction_process_manager_->TakeBidderWorklet(kBidder2Url);
     ASSERT_TRUE(bidder2_worklet);
 
-    seller_worklet->CompleteLoading();
-
     ASSERT_FALSE(auction_complete_);
     if (other_bidder_finishes_first) {
       bidder2_worklet->InvokeGenerateBidCallback(7 /* bid */,
@@ -2515,7 +2526,6 @@
       mock_auction_process_manager_->TakeBidderWorklet(kBidder2Url);
   ASSERT_TRUE(bidder2_worklet);
 
-  seller_worklet->CompleteLoading();
   bidder1_worklet->InvokeGenerateBidCallback(7 /* bid */,
                                              GURL("https://ad1.com/"));
   // The bidder pipe should be closed after it bids.
@@ -2565,17 +2575,19 @@
                   2 /* expected_interest_groups */, 2 /* expected_owners */);
 }
 
-// If the seller crashes at any point in the auction, the auction fails.
+// If the seller crashes at several points in the auction, the auction fails.
+// Seller load failures look the same to auctions, so this test also covers
+// load failures in the same places. Note that a seller worklet load error while
+// waiting for bidder worklet processes is covered in another test, and looks
+// exactly like a crash at the same point to the AuctionRunner.
 TEST_F(AuctionRunnerTest, SellerCrash) {
   enum class CrashPhase {
     kLoad,
-    kLoadAfterBidsReceived,
     kScoreBid,
     kReportResult,
   };
   for (CrashPhase crash_phase :
-       {CrashPhase::kLoad, CrashPhase::kLoadAfterBidsReceived,
-        CrashPhase::kScoreBid, CrashPhase::kReportResult}) {
+       {CrashPhase::kLoad, CrashPhase::kScoreBid, CrashPhase::kReportResult}) {
     SCOPED_TRACE(static_cast<int>(crash_phase));
 
     StartStandardAuctionWithMockService();
@@ -2592,34 +2604,19 @@
     // While loop to allow breaking when the crash stage is reached.
     while (true) {
       if (crash_phase == CrashPhase::kLoad) {
-        // Need to close the AuctionWorkletService pipes so callbacks can be
-        // destroyed without DCHECKing.
-        mock_auction_process_manager_->ClosePipes();
+        seller_worklet->set_expect_send_pending_signals_requests_called(false);
         seller_worklet.reset();
         break;
       }
 
+      // Generate both bids, wait for seller to receive them..
       bidder1_worklet->InvokeGenerateBidCallback(5 /* bid */,
                                                  GURL("https://ad1.com/"));
       bidder2_worklet->InvokeGenerateBidCallback(7 /* bid */,
                                                  GURL("https://ad2.com/"));
-      // Wait for bids to be received.
-      task_environment_.RunUntilIdle();
-
-      if (crash_phase == CrashPhase::kLoadAfterBidsReceived) {
-        // Need to close the AuctionWorkletService pipes so callbacks can be
-        // destroyed without DCHECKing.
-        mock_auction_process_manager_->ClosePipes();
-        seller_worklet.reset();
-        break;
-      }
-
-      // Seller worklet finishes loading, and receives both bids.
-      seller_worklet->CompleteLoading();
-
-      // Wait for both bids.
       auto score_ad_params = seller_worklet->WaitForScoreAd();
       auto score_ad_params2 = seller_worklet->WaitForScoreAd();
+
       // Wait for SendPendingSignalsRequests() invocation.
       task_environment_.RunUntilIdle();
 
@@ -2705,7 +2702,6 @@
         mock_auction_process_manager_->TakeBidderWorklet(kBidder1Url);
     ASSERT_TRUE(bidder_worklet);
 
-    seller_worklet->CompleteLoading();
     bidder_worklet->InvokeGenerateBidCallback(
         /*bid=*/1, kRenderUrl, test_case.bid_ad_component_urls,
         base::TimeDelta());
@@ -2793,7 +2789,6 @@
         mock_auction_process_manager_->TakeBidderWorklet(kBidder1Url);
     ASSERT_TRUE(bidder_worklet);
 
-    seller_worklet->CompleteLoading();
     bidder_worklet->InvokeGenerateBidCallback(
         /*bid=*/1, kRenderUrl, ad_component_urls, base::TimeDelta());
 
@@ -2971,7 +2966,6 @@
         mock_auction_process_manager_->TakeBidderWorklet(kBidder2Url);
     ASSERT_TRUE(bidder2_worklet);
 
-    seller_worklet->CompleteLoading();
     bidder1_worklet->InvokeGenerateBidCallback(
         test_case.bid, test_case.render_url, test_case.ad_component_urls,
         test_case.duration);
@@ -3014,7 +3008,6 @@
       mock_auction_process_manager_->TakeBidderWorklet(kBidder2Url);
   ASSERT_TRUE(bidder2_worklet);
 
-  seller_worklet->CompleteLoading();
   // Only Bidder1 bids, to keep things simple.
   bidder1_worklet->InvokeGenerateBidCallback(5 /* bid */,
                                              GURL("https://ad1.com/"));
@@ -3062,7 +3055,6 @@
       mock_auction_process_manager_->TakeBidderWorklet(kBidder2Url);
   ASSERT_TRUE(bidder2_worklet);
 
-  seller_worklet->CompleteLoading();
   // Only Bidder1 bids, to keep things simple.
   bidder1_worklet->InvokeGenerateBidCallback(5 /* bid */,
                                              GURL("https://ad1.com/"));
@@ -3099,12 +3091,21 @@
                   2 /* expected_interest_groups */, 2 /* expected_owners */);
 }
 
-// Make sure that requesting unexpected URLs is blocked.
+// Make sure that requesting unexpected URLs from a bidder worklet is blocked.
+// While this test starts an auction, it only does this so it can directly make
+// requests using the URLLoaderFactories the auction creates.
+//
+// TODO(https://crbug.com/1276639): Once bidder worklets are created using
+// AuctionWorkletManager, make this an AuctionWorkletManager test.
 TEST_F(AuctionRunnerTest, UrlRequestProtection) {
   StartStandardAuctionWithMockService();
 
   auto seller_worklet = mock_auction_process_manager_->TakeSellerWorklet();
   ASSERT_TRUE(seller_worklet);
+  // This auction doesn't generate any bids, the auction is just used to create
+  // URLLoaderFactories, which are used independently of the AuctionRunner.
+  seller_worklet->set_expect_send_pending_signals_requests_called(false);
+
   auto bidder1_worklet =
       mock_auction_process_manager_->TakeBidderWorklet(kBidder1Url);
   ASSERT_TRUE(bidder1_worklet);
@@ -3112,35 +3113,20 @@
       mock_auction_process_manager_->TakeBidderWorklet(kBidder2Url);
   ASSERT_TRUE(bidder2_worklet);
 
-  // It should be possible to request the seller URL from the seller's
-  // URLLoaderFactory.
+  // A bidder's URLLoaderFactory should reject the seller URL, closing the Mojo
+  // pipe.
   network::ResourceRequest request;
-  request.url = kSellerUrl;
   request.headers.SetHeader(net::HttpRequestHeaders::kAccept,
                             "application/javascript");
   mojo::PendingRemote<network::mojom::URLLoader> receiver;
   mojo::PendingReceiver<network::mojom::URLLoaderClient> client;
-  seller_worklet->url_loader_factory()->CreateLoaderAndStart(
-      receiver.InitWithNewPipeAndPassReceiver(), 0 /* request_id_ */,
-      0 /* options */, request, client.InitWithNewPipeAndPassRemote(),
-      net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
-  seller_worklet->url_loader_factory().FlushForTesting();
-  EXPECT_TRUE(seller_worklet->url_loader_factory().is_connected());
-  ASSERT_EQ(1u, url_loader_factory_.pending_requests()->size());
-  EXPECT_EQ(kSellerUrl,
-            (*url_loader_factory_.pending_requests())[0].request.url);
-  receiver.reset();
-  client.reset();
-
-  // A bidder's URLLoaderFactory should reject the seller URL, closing the Mojo
-  // pipe.
   bidder1_worklet->url_loader_factory()->CreateLoaderAndStart(
       receiver.InitWithNewPipeAndPassReceiver(), 0 /* request_id_ */,
       0 /* options */, request, client.InitWithNewPipeAndPassRemote(),
       net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
   bidder1_worklet->url_loader_factory().FlushForTesting();
   EXPECT_FALSE(bidder1_worklet->url_loader_factory().is_connected());
-  EXPECT_EQ(1u, url_loader_factory_.pending_requests()->size());
+  EXPECT_EQ(0u, url_loader_factory_.pending_requests()->size());
   EXPECT_EQ("Unexpected request", TakeBadMessage());
   receiver.reset();
   client.reset();
@@ -3153,22 +3139,9 @@
       net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
   bidder2_worklet->url_loader_factory().FlushForTesting();
   EXPECT_TRUE(bidder2_worklet->url_loader_factory().is_connected());
-  ASSERT_EQ(2u, url_loader_factory_.pending_requests()->size());
+  ASSERT_EQ(1u, url_loader_factory_.pending_requests()->size());
   EXPECT_EQ(kBidder2Url,
-            (*url_loader_factory_.pending_requests())[1].request.url);
-  receiver.reset();
-  client.reset();
-
-  // The seller's URLLoaderFactory should reject a bidder worklet's URL, closing
-  // the Mojo pipe.
-  seller_worklet->url_loader_factory()->CreateLoaderAndStart(
-      receiver.InitWithNewPipeAndPassReceiver(), 0 /* request_id_ */,
-      0 /* options */, request, client.InitWithNewPipeAndPassRemote(),
-      net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
-  seller_worklet->url_loader_factory().FlushForTesting();
-  EXPECT_FALSE(seller_worklet->url_loader_factory().is_connected());
-  EXPECT_EQ(2u, url_loader_factory_.pending_requests()->size());
-  EXPECT_EQ("Unexpected request", TakeBadMessage());
+            (*url_loader_factory_.pending_requests())[0].request.url);
   receiver.reset();
   client.reset();
 
@@ -3180,12 +3153,8 @@
       net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
   bidder2_worklet->url_loader_factory().FlushForTesting();
   EXPECT_FALSE(bidder2_worklet->url_loader_factory().is_connected());
-  ASSERT_EQ(2u, url_loader_factory_.pending_requests()->size());
+  ASSERT_EQ(1u, url_loader_factory_.pending_requests()->size());
   EXPECT_EQ("Unexpected request", TakeBadMessage());
-
-  // Need to close the AuctionWorkletService pipes so callbacks can be destroyed
-  // without DCHECKing.
-  mock_auction_process_manager_->ClosePipes();
 }
 
 // Check that BidderWorklets that don't make a bid are destroyed immediately.
@@ -3201,8 +3170,6 @@
       mock_auction_process_manager_->TakeBidderWorklet(kBidder2Url);
   ASSERT_TRUE(bidder2_worklet);
 
-  seller_worklet->CompleteLoading();
-
   bidder1_worklet->InvokeGenerateBidCallback(/*bid=*/absl::nullopt);
   // Need to flush the service pipe to make sure the AuctionRunner has received
   // the bid.
@@ -3263,8 +3230,6 @@
         mock_auction_process_manager_->TakeBidderWorklet(kBidder2Url);
     ASSERT_TRUE(bidder2_worklet);
 
-    seller_worklet->CompleteLoading();
-
     // Bidder1 returns a bid, which is then scored.
     bidder1_worklet->InvokeGenerateBidCallback(5 /* bid */,
                                                GURL("https://ad1.com/"));
@@ -3377,8 +3342,6 @@
           mock_auction_process_manager_->TakeBidderWorklet(kBidder2Url);
       ASSERT_TRUE(bidder2_worklet);
 
-      seller_worklet->CompleteLoading();
-
       MockSellerWorklet::ScoreAdParams score_ad_params1;
       MockSellerWorklet::ScoreAdParams score_ad_params2;
 
diff --git a/content/browser/interest_group/auction_worklet_manager.cc b/content/browser/interest_group/auction_worklet_manager.cc
new file mode 100644
index 0000000..6377e34
--- /dev/null
+++ b/content/browser/interest_group/auction_worklet_manager.cc
@@ -0,0 +1,313 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/interest_group/auction_worklet_manager.h"
+
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <tuple>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/check.h"
+#include "base/compiler_specific.h"
+#include "base/memory/raw_ptr.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/observer_list.h"
+#include "base/strings/strcat.h"
+#include "content/browser/interest_group/auction_process_manager.h"
+#include "content/browser/interest_group/auction_url_loader_factory_proxy.h"
+#include "content/browser/interest_group/debuggable_auction_worklet.h"
+#include "content/common/content_export.h"
+#include "content/services/auction_worklet/public/mojom/seller_worklet.mojom.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "services/network/public/mojom/client_security_state.mojom.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace content {
+
+class AuctionWorkletManager::WorkletOwner
+    : public base::RefCounted<AuctionWorkletManager::WorkletOwner> {
+ public:
+  // On construction, attempts to immediately create a worklet. If that
+  // succeeds, it's up to the AuctionWorkletManager itself to inform the caller
+  // a worklet was synchronously created. Otherwise, the WorkletOwner will
+  // immediately start waiting for a process to be available, and once one is,
+  // create a worklet, informing all associated WorkletHandles.
+  WorkletOwner(AuctionWorkletManager* worklet_manager,
+               WorkletInfo worklet_info);
+
+  // Registers/unregisters a WorkletHandle for the worklet `this` owns.
+  void RegisterHandle(WorkletHandle* handle) { handles_.AddObserver(handle); }
+  void UnregisterHandle(WorkletHandle* handle) {
+    handles_.RemoveObserver(handle);
+  }
+
+  auction_worklet::mojom::SellerWorklet* seller_worklet() {
+    DCHECK(seller_worklet_);
+    return seller_worklet_.get();
+  }
+
+  const WorkletInfo& worklet_info() const { return worklet_info_; }
+
+  // Whether or not a worklet has been created. Once a worklet has been created,
+  // always returns true, even after disconnect or error.
+  bool worklet_created() const { return seller_worklet_.is_bound(); }
+
+ private:
+  friend class base::RefCounted<WorkletOwner>;
+
+  ~WorkletOwner();
+
+  // Called if the worklet becomes unusable. This happens on destruction (once
+  // all refs have been released) or when the Mojo pipe is closed. Removes
+  // `this` from `worklet_manager_`, so that future requests using the same
+  // `worklet_info` will trigger creation of a new worklet, rather than trying
+  // to use the unusable one.
+  void WorkletNoLongerUsable();
+
+  // Called once the AuctionProcessManager provides a process to load a worklet
+  // in. Immediately loads the worklet and informs WorkletHandles.
+  void OnProcessAssigned();
+
+  // Mojo disconnect with reason handler. If there's a description, it's a load
+  // error. Otherwise, it's a crash. Passes error information on to all
+  // associated WorkletHandles.
+  void OnWorkletDisconnected(uint32_t /* custom_reason */,
+                             const std::string& description);
+
+  // Set to null once `this` is removed from AuctionWorkletManager's
+  // WorkletOwner list, which happens on destruction or on Mojo pipe closure.
+  // The latter allows a handle to still exist and refer to a WorkletOwner with
+  // a broken Worklet pipe, while new requests for the same worklet will result
+  // in creating a fresh Mojo worklet.
+  AuctionWorkletManager* worklet_manager_;
+
+  const WorkletInfo worklet_info_;
+
+  AuctionProcessManager::ProcessHandle process_handle_;
+
+  // List of live WorkletHandles to notify in case a Worklet is created or on
+  // Mojo pipe closure.
+  base::ObserverList<WorkletHandle, /*check_empty=*/true> handles_;
+
+  std::unique_ptr<AuctionURLLoaderFactoryProxy> url_loader_factory_proxy_;
+  mojo::Remote<auction_worklet::mojom::SellerWorklet> seller_worklet_;
+  // This must be destroyed before the worklet it's passed, since it hangs on to
+  // a raw pointer to it.
+  std::unique_ptr<DebuggableAuctionWorklet> worklet_debug_;
+};
+
+AuctionWorkletManager::WorkletOwner::WorkletOwner(
+    AuctionWorkletManager* worklet_manager,
+    WorkletInfo worklet_info)
+    : worklet_manager_(worklet_manager),
+      worklet_info_(std::move(worklet_info)) {
+  // Only seller worklets are currently supported.
+  DCHECK_EQ(worklet_info_.type, WorkletType::kSeller);
+
+  if (worklet_manager_->auction_process_manager()->RequestWorkletService(
+          worklet_info_.type, url::Origin::Create(worklet_info_.script_url),
+          &process_handle_,
+          base::BindOnce(
+              &AuctionWorkletManager::WorkletOwner::OnProcessAssigned,
+              base::Unretained(this)))) {
+    OnProcessAssigned();
+  }
+}
+
+AuctionWorkletManager::WorkletOwner::~WorkletOwner() {
+  WorkletNoLongerUsable();
+}
+
+void AuctionWorkletManager::WorkletOwner::WorkletNoLongerUsable() {
+  if (worklet_manager_) {
+    worklet_manager_->OnWorkletNoLongerUsable(this);
+    worklet_manager_ = nullptr;
+  }
+}
+
+void AuctionWorkletManager::WorkletOwner::OnProcessAssigned() {
+  Delegate* delegate = worklet_manager_->delegate();
+  mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory;
+  url_loader_factory_proxy_ = std::make_unique<AuctionURLLoaderFactoryProxy>(
+      url_loader_factory.InitWithNewPipeAndPassReceiver(),
+      base::BindRepeating(&Delegate::GetFrameURLLoaderFactory,
+                          base::Unretained(delegate)),
+      base::BindRepeating(&Delegate::GetTrustedURLLoaderFactory,
+                          base::Unretained(delegate)),
+      worklet_manager_->top_window_origin(), worklet_manager_->frame_origin(),
+      /*is_for_seller_=*/true, delegate->GetClientSecurityState(),
+      worklet_info_.script_url, /*wasm_url=*/absl::nullopt,
+      /*trusted_signals_base_url=*/worklet_info_.signals_url);
+  mojo::PendingReceiver<auction_worklet::mojom::SellerWorklet>
+      worklet_receiver = seller_worklet_.BindNewPipeAndPassReceiver();
+  worklet_debug_ = base::WrapUnique(new DebuggableAuctionWorklet(
+      delegate->GetFrame(), worklet_info_.script_url, seller_worklet_.get()));
+  process_handle_.GetService()->LoadSellerWorklet(
+      std::move(worklet_receiver), worklet_debug_->should_pause_on_start(),
+      std::move(url_loader_factory), worklet_info_.script_url,
+      worklet_info_.signals_url, worklet_manager_->top_window_origin());
+  seller_worklet_.set_disconnect_with_reason_handler(base::BindOnce(
+      &WorkletOwner::OnWorkletDisconnected, base::Unretained(this)));
+
+  for (auto& handle : handles_) {
+    handle.OnWorkletAvailable();
+  }
+}
+
+void AuctionWorkletManager::WorkletOwner::OnWorkletDisconnected(
+    uint32_t /* custom_reason */,
+    const std::string& description) {
+  // This may only be invoked once per worklet, and `worklet_manager_` is only
+  // cleared by this method and on destruction, so it should not be null.
+  DCHECK(worklet_manager_);
+
+  WorkletNoLongerUsable();
+
+  FatalErrorType error_type;
+  std::vector<std::string> errors;
+  // If there's a description, it's a load failure. Otherwise, it's a crash.
+  if (!description.empty()) {
+    error_type = FatalErrorType::kScriptLoadFailed;
+    errors.push_back(description);
+  } else {
+    error_type = FatalErrorType::kWorkletCrash;
+    errors.emplace_back(
+        base::StrCat({worklet_info_.script_url.spec(), " crashed."}));
+  }
+
+  for (auto& handle : handles_) {
+    handle.OnFatalError(error_type, errors);
+  }
+}
+
+AuctionWorkletManager::WorkletHandle::~WorkletHandle() {
+  worklet_owner_->UnregisterHandle(this);
+}
+
+auction_worklet::mojom::SellerWorklet*
+AuctionWorkletManager::WorkletHandle::GetSellerWorklet() {
+  DCHECK_EQ(WorkletType::kSeller, worklet_owner_->worklet_info().type);
+  DCHECK(worklet_owner_->seller_worklet());
+  return worklet_owner_->seller_worklet();
+}
+
+AuctionWorkletManager::WorkletHandle::WorkletHandle(
+    scoped_refptr<WorkletOwner> worklet_owner,
+    base::OnceClosure worklet_available_callback,
+    FatalErrorCallback fatal_error_callback)
+    : worklet_owner_(std::move(worklet_owner)),
+      worklet_available_callback_(std::move(worklet_available_callback)),
+      fatal_error_callback_(std::move(fatal_error_callback)) {
+  DCHECK(worklet_available_callback_);
+  DCHECK(fatal_error_callback_);
+
+  // Delete `worklet_available_callback_` if worklet is already available, since
+  // it won't be needed.
+  if (worklet_owner_->worklet_created())
+    worklet_available_callback_.Reset();
+
+  worklet_owner_->RegisterHandle(this);
+}
+
+void AuctionWorkletManager::WorkletHandle::OnWorkletAvailable() {
+  DCHECK(worklet_available_callback_);
+  std::move(worklet_available_callback_).Run();
+}
+
+void AuctionWorkletManager::WorkletHandle::OnFatalError(
+    FatalErrorType type,
+    const std::vector<std::string>& errors) {
+  DCHECK(fatal_error_callback_);
+  std::move(fatal_error_callback_).Run(type, errors);
+}
+
+bool AuctionWorkletManager::WorkletHandle::worklet_created() const {
+  return worklet_owner_->worklet_created();
+}
+
+AuctionWorkletManager::AuctionWorkletManager(
+    AuctionProcessManager* auction_process_manager,
+    url::Origin top_window_origin,
+    url::Origin frame_origin,
+    Delegate* delegate)
+    : auction_process_manager_(auction_process_manager),
+      top_window_origin_(std::move(top_window_origin)),
+      frame_origin_(std::move(frame_origin)),
+      delegate_(delegate) {}
+
+AuctionWorkletManager::~AuctionWorkletManager() = default;
+
+bool AuctionWorkletManager::WorkletInfo::WorkletInfo::operator<(
+    const WorkletInfo& other) const {
+  return std::tie(type, script_url, signals_url) <
+         std::tie(other.type, other.script_url, other.signals_url);
+}
+
+bool AuctionWorkletManager::RequestSellerWorklet(
+    const GURL& decision_logic_url,
+    const absl::optional<GURL>& trusted_scoring_signals_url,
+    base::OnceClosure worklet_available_callback,
+    FatalErrorCallback fatal_error_callback,
+    std::unique_ptr<WorkletHandle>& out_worklet_handle) {
+  DCHECK(!out_worklet_handle);
+
+  WorkletInfo worklet_info(WorkletType::kSeller,
+                           /*script_url=*/decision_logic_url,
+                           /*signals_url=*/trusted_scoring_signals_url);
+  return RequestWorkletInternal(
+      std::move(worklet_info), std::move(worklet_available_callback),
+      std::move(fatal_error_callback), out_worklet_handle);
+}
+
+AuctionWorkletManager::WorkletInfo::WorkletInfo(
+    WorkletType type,
+    const GURL& script_url,
+    const absl::optional<GURL>& signals_url)
+    : type(type), script_url(script_url), signals_url(signals_url) {}
+
+AuctionWorkletManager::WorkletInfo::WorkletInfo(const WorkletInfo&) = default;
+AuctionWorkletManager::WorkletInfo::WorkletInfo(WorkletInfo&&) = default;
+AuctionWorkletManager::WorkletInfo::~WorkletInfo() = default;
+
+bool AuctionWorkletManager::RequestWorkletInternal(
+    WorkletInfo worklet_info,
+    base::OnceClosure worklet_available_callback,
+    FatalErrorCallback fatal_error_callback,
+    std::unique_ptr<WorkletHandle>& out_worklet_handle) {
+  auto worklet_it = worklets_.find(worklet_info);
+  scoped_refptr<WorkletOwner> worklet;
+  if (worklet_it != worklets_.end()) {
+    worklet = worklet_it->second;
+  } else {
+    // Can't just insert in the map and put a reference in `worklet_it`, since
+    // need to keep a live reference.
+    worklet = base::MakeRefCounted<WorkletOwner>(this, worklet_info);
+    worklets_.emplace(std::pair(std::move(worklet_info), worklet.get()));
+  }
+  out_worklet_handle.reset(new WorkletHandle(
+      std::move(worklet), std::move(worklet_available_callback),
+      std::move(fatal_error_callback)));
+  return out_worklet_handle->worklet_created();
+}
+
+void AuctionWorkletManager::OnWorkletNoLongerUsable(WorkletOwner* worklet) {
+  DCHECK(worklets_.count(worklet->worklet_info()));
+  DCHECK_EQ(worklet, worklets_[worklet->worklet_info()]);
+
+  worklets_.erase(worklet->worklet_info());
+}
+
+}  // namespace content
diff --git a/content/browser/interest_group/auction_worklet_manager.h b/content/browser/interest_group/auction_worklet_manager.h
new file mode 100644
index 0000000..a0eb1c1
--- /dev/null
+++ b/content/browser/interest_group/auction_worklet_manager.h
@@ -0,0 +1,230 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_INTEREST_GROUP_AUCTION_WORKLET_MANAGER_H_
+#define CONTENT_BROWSER_INTEREST_GROUP_AUCTION_WORKLET_MANAGER_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/memory/raw_ptr.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/observer_list_types.h"
+#include "content/browser/interest_group/auction_process_manager.h"
+#include "content/common/content_export.h"
+#include "content/services/auction_worklet/public/mojom/seller_worklet.mojom.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "services/network/public/mojom/client_security_state.mojom-forward.h"
+#include "services/network/public/mojom/url_loader_factory.mojom-forward.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace content {
+
+class RenderFrameHostImpl;
+
+// Per-frame manager of auction worklets. Manages creation and sharing of
+// worklets. Worklets may be reused if they share URLs for scripts and trusted
+// signals (and thus share an owner), share top frame origins, and are in the
+// same frame. The frame requirement is needed by DevTools and URLLoaderFactory
+// hooks, the others by the current worklet implementations.
+//
+// If a worklet fails to load or crashes, information about the error is
+// broadcast to all consumers of the worklet. This will only happen after
+// a worklet was successfully created. After a load failure or crash, the
+// worklet will not be able to invoke any pending callbacks passed over the Mojo
+// interface.
+//
+// AuctionWorkletManager does not implement any prioritization, apart from
+// invoking callbacks that are sharing a worklet in FIFO order. The
+// AuctionProcessManager handles prioritization for process creation. Once a
+// process is created for a worklet, the worklet is created immediately.
+//
+// TODO(https://crbug.com/1276639): Currently only applies to seller worklets.
+// Make this handle bidder worklets, too.
+class CONTENT_EXPORT AuctionWorkletManager {
+ public:
+  using WorkletType = AuctionProcessManager::WorkletType;
+
+  // Types of fatal error that can prevent a worklet from all further execution.
+  enum class FatalErrorType {
+    kScriptLoadFailed,
+    kWorkletCrash,
+  };
+
+  using FatalErrorCallback =
+      base::OnceCallback<void(FatalErrorType fatal_error_type,
+                              const std::vector<std::string>& errors)>;
+
+  // Delegate class to allow dependency injection in tests. Note that passed in
+  // URLLoaderFactories can crash and be restarted, so passing in raw pointers
+  // would be problematic.
+  class Delegate {
+   public:
+    // Returns the URLLoaderFactory of the associated frame. Used to load the
+    // seller worklet scripts in the context of the parent frame, since unlike
+    // other worklet types, it has no first party opt-in, and it's not a
+    // cross-origin leak if the parent from knows its URL, since the parent
+    // frame provided the URL in the first place.
+    virtual network::mojom::URLLoaderFactory* GetFrameURLLoaderFactory() = 0;
+
+    // Trusted URLLoaderFactory used to load bidder worklets, and seller scoring
+    // signals.
+    virtual network::mojom::URLLoaderFactory* GetTrustedURLLoaderFactory() = 0;
+
+    // Get containing frame. (Passed to debugging hooks).
+    virtual RenderFrameHostImpl* GetFrame() = 0;
+
+    // Returns the ClientSecurityState associated with the frame, for use in
+    // bidder worklet and signals fetches.
+    virtual network::mojom::ClientSecurityStatePtr GetClientSecurityState() = 0;
+  };
+
+  // Internal class that owns and creates worklets. It also tracks pending
+  // requests that the worklet will be provided upon creation. Refcounted and
+  // owned by one or more worklet handles, rather than the
+  // AuctionWorkletManager.
+  class WorkletOwner;
+
+  // Class that tracks a request for a Worklet, and helps manage the lifetime of
+  // the returned Worklet once the request receives one. Destroying the handle
+  // will abort a pending request and potentially release any worklets or
+  // processes it is keeping alive, so consumers should destroy these as soon as
+  // they are no longer needed.
+  class CONTENT_EXPORT WorkletHandle : public base::CheckedObserver {
+   public:
+    WorkletHandle(const WorkletHandle&) = delete;
+    WorkletHandle& operator=(const WorkletHandle&) = delete;
+    ~WorkletHandle() override;
+
+    // Retrieves the SellerWorklet Mojo interface for the requested worklet.
+    // Once the worklet is created, will never return null. Even in the case of
+    // process crash or load error, it will return an interface with a broken
+    // pipe.
+    //
+    // Note that calls in the returned Mojo worklet cannot currently be
+    // cancelled, so calls should always use weak pointers. Since there's no way
+    // for pages to cancel auctions, anyways, and these are currently scoped
+    // per-frame, supporting cancellation seems not useful (And the weak
+    // pointers are probably not strictly necessary, since everything is torn
+    // down before Mojo has a chance to invoke callbacks, but using weak
+    // pointers still seems the safest thing to do).
+    auction_worklet::mojom::SellerWorklet* GetSellerWorklet();
+
+   private:
+    friend class AuctionWorkletManager;
+    friend class WorkletOwner;
+
+    // These are only created by AuctionWorkletManager.
+    explicit WorkletHandle(scoped_refptr<WorkletOwner> worklet_owner,
+                           base::OnceClosure worklet_available_callback,
+                           FatalErrorCallback fatal_error_callback);
+
+    // Both these methods are invoked by WorkletOwner, and call the
+    // corresponding callback.
+    void OnWorkletAvailable();
+    void OnFatalError(FatalErrorType type,
+                      const std::vector<std::string>& errors);
+
+    // Returns true if `worklet_owner_` has created a worklet yet.
+    bool worklet_created() const;
+
+    scoped_refptr<WorkletOwner> worklet_owner_;
+
+    // Non-null only when waiting on a Worklet object to be provided.
+    base::OnceClosure worklet_available_callback_;
+
+    FatalErrorCallback fatal_error_callback_;
+  };
+
+  // `delegate` and `auction_process_manager` must outlive the created
+  // AuctionWorkletManager.
+  AuctionWorkletManager(AuctionProcessManager* auction_process_manager,
+                        url::Origin top_window_origin,
+                        url::Origin frame_origin,
+                        Delegate* delegate);
+  AuctionWorkletManager(const AuctionWorkletManager&) = delete;
+  AuctionWorkletManager& operator=(const AuctionWorkletManager&) = delete;
+  ~AuctionWorkletManager();
+
+  // Requests a SellerWorklet with the specified properties. The top frame
+  // origin and debugging information is obtained from the RenderFrameHost the
+  // AuctionWorkletManager is scoped to on construction, so they're not taken as
+  // parameters.
+  //
+  // The AuctionWorkletManager will handle requesting a process, hooking up
+  // DevTools, and merging requests with the same parameters so they can share a
+  // single worklet.
+  //
+  // If a worklet is synchronously assigned to `out_worklet_handle`, returns
+  // true and the Worklet pointer can immediately be retrieved from the handle.
+  // `worklet_available_callback` will not be invoked. Otherwise, returns false
+  // and will invoke `worklet_available_callback` when the service pointer can
+  // be retrieved from `handle`.
+  //
+  // `fatal_error_callback` is invoked in the case of a fatal error. It may be
+  // invoked any time after the worklet is available (after returning true or
+  // after `worklet_available_callback` has been invoked), before the
+  // WorkletHandle is destroyed. It is called to indicate the seller worklet
+  // failed to load, or the seller worklet crashed, both of which only happen
+  // after a worklet has been provided to the caller.
+  bool RequestSellerWorklet(
+      const GURL& decision_logic_url,
+      const absl::optional<GURL>& trusted_scoring_signals_url,
+      base::OnceClosure worklet_available_callback,
+      FatalErrorCallback fatal_error_callback,
+      std::unique_ptr<WorkletHandle>& out_worklet_handle) WARN_UNUSED_RESULT;
+
+ private:
+  // Enough information to uniquely ID a worklet. If these fields match for two
+  // worklets (and they're loaded in the same frame, as this class is
+  // frame-scoped), the worklets can use the same Mojo Worklet object.
+  struct WorkletInfo {
+    WorkletInfo(WorkletType type,
+                const GURL& script_url,
+                const absl::optional<GURL>& signals_url);
+    WorkletInfo(const WorkletInfo&);
+    WorkletInfo(WorkletInfo&&);
+    ~WorkletInfo();
+
+    WorkletType type;
+    GURL script_url;
+    absl::optional<GURL> signals_url;
+
+    bool operator<(const WorkletInfo& other) const;
+  };
+
+  bool RequestWorkletInternal(
+      WorkletInfo worklet_info,
+      base::OnceClosure worklet_available_callback,
+      FatalErrorCallback fatal_error_callback,
+      std::unique_ptr<WorkletHandle>& out_worklet_handle);
+
+  void OnWorkletNoLongerUsable(WorkletOwner* worklet);
+
+  // Accessors used by inner classes. Not strictly needed, but makes it clear
+  // which fields they can access.
+  AuctionProcessManager* auction_process_manager() {
+    return auction_process_manager_;
+  }
+  const url::Origin& top_window_origin() const { return top_window_origin_; }
+  const url::Origin& frame_origin() const { return frame_origin_; }
+  Delegate* delegate() { return delegate_; }
+
+  const raw_ptr<AuctionProcessManager> auction_process_manager_;
+  const url::Origin top_window_origin_;
+  const url::Origin frame_origin_;
+  raw_ptr<Delegate> const delegate_;
+
+  std::map<WorkletInfo, WorkletOwner*> worklets_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_INTEREST_GROUP_AUCTION_WORKLET_MANAGER_H_
diff --git a/content/browser/interest_group/auction_worklet_manager_unittest.cc b/content/browser/interest_group/auction_worklet_manager_unittest.cc
new file mode 100644
index 0000000..390706f
--- /dev/null
+++ b/content/browser/interest_group/auction_worklet_manager_unittest.cc
@@ -0,0 +1,793 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/interest_group/auction_worklet_manager.h"
+
+#include <list>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/check.h"
+#include "base/cxx17_backports.h"
+#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/bind.h"
+#include "base/test/task_environment.h"
+#include "content/browser/interest_group/auction_process_manager.h"
+#include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom.h"
+#include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom.h"
+#include "content/services/auction_worklet/public/mojom/seller_worklet.mojom.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "mojo/public/cpp/system/functions.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "services/network/public/mojom/client_security_state.mojom.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace content {
+
+namespace {
+
+base::OnceClosure NeverInvokedWorkletAvailableCallback() {
+  return base::BindOnce([]() { ADD_FAILURE() << "This should not be called"; });
+}
+
+AuctionWorkletManager::FatalErrorCallback NeverInvokedFatalErrorCallback() {
+  return base::BindOnce(
+      [](AuctionWorkletManager::FatalErrorType fatal_error_type,
+         const std::vector<std::string>& errors) {
+        ADD_FAILURE() << "This should not be called";
+      });
+}
+
+// Single-use helper for waiting for a load error and inspecting its data.
+class FatalLoadErrorHelper {
+ public:
+  FatalLoadErrorHelper() = default;
+  ~FatalLoadErrorHelper() = default;
+
+  AuctionWorkletManager::FatalErrorCallback Callback() {
+    return base::BindOnce(&FatalLoadErrorHelper::OnFatalError,
+                          base::Unretained(this));
+  }
+
+  void WaitForResult() { run_loop_.Run(); }
+
+  AuctionWorkletManager::FatalErrorType fatal_error_type() const {
+    return fatal_error_type_;
+  }
+
+  const std::vector<std::string>& errors() const { return errors_; }
+
+ private:
+  void OnFatalError(AuctionWorkletManager::FatalErrorType fatal_error_type,
+                    const std::vector<std::string>& errors) {
+    EXPECT_FALSE(run_loop_.AnyQuitCalled());
+
+    fatal_error_type_ = fatal_error_type;
+    errors_ = std::move(errors);
+    run_loop_.Quit();
+  }
+
+  AuctionWorkletManager::FatalErrorType fatal_error_type_;
+  std::vector<std::string> errors_;
+
+  // For use by FatalErrorCallback only.
+  base::RunLoop run_loop_;
+};
+
+}  // namespace
+
+// SellerWorklet that holds onto passed in callbacks, to let the test fixture
+// invoke them.
+class MockSellerWorklet : public auction_worklet::mojom::SellerWorklet {
+ public:
+  explicit MockSellerWorklet(
+      mojo::PendingReceiver<auction_worklet::mojom::SellerWorklet>
+          pending_receiver,
+      mojo::PendingRemote<network::mojom::URLLoaderFactory>
+          pending_url_loader_factory,
+      const GURL& script_source_url,
+      const absl::optional<GURL>& trusted_scoring_signals_url,
+      const url::Origin& top_window_origin)
+      : url_loader_factory_(std::move(pending_url_loader_factory)),
+        script_source_url_(script_source_url),
+        trusted_scoring_signals_url_(trusted_scoring_signals_url),
+        top_window_origin_(top_window_origin),
+        receiver_(this, std::move(pending_receiver)) {}
+
+  MockSellerWorklet(const MockSellerWorklet&) = delete;
+  const MockSellerWorklet& operator=(const MockSellerWorklet&) = delete;
+
+  ~MockSellerWorklet() override {
+    // Process any pending SendPendingSignalsRequests() calls.
+    base::RunLoop().RunUntilIdle();
+    EXPECT_EQ(expected_num_send_pending_signals_requests_calls_,
+              num_send_pending_signals_requests_calls_);
+  }
+
+  // auction_worklet::mojom::SellerWorklet implementation:
+
+  void ScoreAd(const std::string& ad_metadata_json,
+               double bid,
+               blink::mojom::ShareableAuctionAdConfigPtr shareable_config,
+               const url::Origin& browser_signal_interest_group_owner,
+               const GURL& browser_signal_render_url,
+               const std::vector<GURL>& browser_signal_ad_components,
+               uint32_t browser_signal_bidding_duration_msecs,
+               ScoreAdCallback score_ad_callback) override {
+    NOTREACHED();
+  }
+
+  void SendPendingSignalsRequests() override {
+    ++num_send_pending_signals_requests_calls_;
+    if (num_send_pending_signals_requests_calls_ ==
+        expected_num_send_pending_signals_requests_calls_) {
+      send_pending_signals_requests_called_loop_->Quit();
+    }
+  }
+
+  void ReportResult(blink::mojom::ShareableAuctionAdConfigPtr shareable_config,
+                    const url::Origin& browser_signal_interest_group_owner,
+                    const GURL& browser_signal_render_url,
+                    double browser_signal_bid,
+                    double browser_signal_desirability,
+                    ReportResultCallback report_result_callback) override {
+    NOTREACHED();
+  }
+
+  void ConnectDevToolsAgent(
+      mojo::PendingReceiver<blink::mojom::DevToolsAgent> agent) override {
+    ADD_FAILURE()
+        << "ConnectDevToolsAgent should not be called on MockSellerWorklet";
+  }
+
+  void ClosePipe(const char* error) {
+    DCHECK(error);
+    receiver_.ResetWithReason(/*custom_reason_code=*/0, error);
+  }
+
+  void WaitForSendPendingSignalsRequests(
+      int expected_num_send_pending_signals_requests_calls) {
+    DCHECK_LT(expected_num_send_pending_signals_requests_calls_,
+              expected_num_send_pending_signals_requests_calls);
+
+    expected_num_send_pending_signals_requests_calls_ =
+        expected_num_send_pending_signals_requests_calls;
+    if (num_send_pending_signals_requests_calls_ <
+        expected_num_send_pending_signals_requests_calls_) {
+      send_pending_signals_requests_called_loop_ =
+          std::make_unique<base::RunLoop>();
+      send_pending_signals_requests_called_loop_->Run();
+    }
+
+    EXPECT_EQ(expected_num_send_pending_signals_requests_calls_,
+              num_send_pending_signals_requests_calls_);
+  }
+
+  mojo::Remote<network::mojom::URLLoaderFactory>& url_loader_factory() {
+    return url_loader_factory_;
+  }
+
+  const GURL& script_source_url() const { return script_source_url_; }
+  const absl::optional<GURL>& trusted_scoring_signals_url() const {
+    return trusted_scoring_signals_url_;
+  }
+  const url::Origin& top_window_origin() const { return top_window_origin_; }
+
+  int num_send_pending_signals_requests_calls() const {
+    return num_send_pending_signals_requests_calls_;
+  }
+
+ private:
+  mojo::Remote<network::mojom::URLLoaderFactory> url_loader_factory_;
+
+  const GURL script_source_url_;
+  const absl::optional<GURL> trusted_scoring_signals_url_;
+  const url::Origin top_window_origin_;
+
+  // Number of times SendPendingSignalsRequests() has been invoked. Used to
+  // check that SellerWorklet calls make it to the SellerWorklet as expected,
+  // and that worklets are being shared correctly.
+  int num_send_pending_signals_requests_calls_ = 0;
+  // Number of SendPendingSignalsRequests() to wait for. Once this is hit,
+  // `send_pending_signals_requests_called_loop_` is invoked. Must match
+  // num_send_pending_signals_requests_calls_ on destruction (which catches
+  // unexpected extra calls).
+  int expected_num_send_pending_signals_requests_calls_ = 0;
+  std::unique_ptr<base::RunLoop> send_pending_signals_requests_called_loop_;
+
+  // Receiver is last so that destroying `this` while there's a pending callback
+  // over the pipe will not DCHECK.
+  mojo::Receiver<auction_worklet::mojom::SellerWorklet> receiver_;
+};
+
+// AuctionProcessManager and AuctionWorkletService - combining the two with a
+// mojo::ReceiverSet makes it easier to track which call came over which
+// receiver than using separate classes.
+class MockAuctionProcessManager
+    : public AuctionProcessManager,
+      public auction_worklet::mojom::AuctionWorkletService {
+ public:
+  MockAuctionProcessManager() = default;
+  ~MockAuctionProcessManager() override = default;
+
+  // AuctionProcessManager implementation:
+  void LaunchProcess(
+      mojo::PendingReceiver<auction_worklet::mojom::AuctionWorkletService>
+          auction_worklet_service_receiver,
+      const std::string& display_name) override {
+    mojo::ReceiverId receiver_id =
+        receiver_set_.Add(this, std::move(auction_worklet_service_receiver));
+
+    // Have to flush the receiver set, so that any closed receivers are removed,
+    // before searching for duplicate process names.
+    receiver_set_.FlushForTesting();
+
+    // Each receiver should get a unique display name. This check serves to help
+    // ensure that processes are correctly reused.
+    EXPECT_EQ(0u, receiver_display_name_map_.count(receiver_id));
+    for (auto receiver : receiver_display_name_map_) {
+      // Ignore closed receivers. ReportWin() will result in re-loading a
+      // worklet, after closing the original worklet, which may require
+      // re-creating the AuctionWorkletService.
+      if (receiver_set_.HasReceiver(receiver.first))
+        EXPECT_NE(receiver.second, display_name);
+    }
+
+    receiver_display_name_map_[receiver_id] = display_name;
+  }
+
+  // auction_worklet::mojom::AuctionWorkletService implementation:
+  void LoadBidderWorklet(
+      mojo::PendingReceiver<auction_worklet::mojom::BidderWorklet>
+          bidder_worklet_receiver,
+      bool pause_for_debugger_on_start,
+      mojo::PendingRemote<network::mojom::URLLoaderFactory>
+          pending_url_loader_factory,
+      const GURL& script_source_url,
+      const absl::optional<GURL>& wasm_helper_url,
+      const absl::optional<GURL>& trusted_bidding_signals_url,
+      const url::Origin& top_window_origin) override {
+    // Bidder worklets are not yet supported by the AuctionWorkletManager.
+    NOTREACHED();
+  }
+
+  void LoadSellerWorklet(
+      mojo::PendingReceiver<auction_worklet::mojom::SellerWorklet>
+          seller_worklet_receiver,
+      bool should_pause_on_start,
+      mojo::PendingRemote<network::mojom::URLLoaderFactory>
+          pending_url_loader_factory,
+      const GURL& script_source_url,
+      const absl::optional<GURL>& trusted_scoring_signals_url,
+      const url::Origin& top_window_origin) override {
+    DCHECK(!seller_worklet_);
+
+    // Make sure this request came over the right pipe.
+    EXPECT_EQ(receiver_display_name_map_[receiver_set_.current_receiver()],
+              ComputeDisplayName(AuctionProcessManager::WorkletType::kSeller,
+                                 url::Origin::Create(script_source_url)));
+
+    seller_worklet_ = std::make_unique<MockSellerWorklet>(
+        std::move(seller_worklet_receiver),
+        std::move(pending_url_loader_factory), script_source_url,
+        trusted_scoring_signals_url, top_window_origin);
+
+    if (seller_worklet_run_loop_)
+      seller_worklet_run_loop_->Quit();
+  }
+
+  std::unique_ptr<MockSellerWorklet> WaitForSellerWorklet() {
+    if (!seller_worklet_) {
+      seller_worklet_run_loop_ = std::make_unique<base::RunLoop>();
+      seller_worklet_run_loop_->Run();
+    }
+
+    DCHECK(seller_worklet_);
+    return std::move(seller_worklet_);
+  }
+
+  bool HasSellerWorkletRequest() const {
+    base::RunLoop().RunUntilIdle();
+    return seller_worklet_.get() != nullptr;
+  }
+
+ private:
+  // The most recently created unclaimed seller worklet.
+  std::unique_ptr<MockSellerWorklet> seller_worklet_;
+  std::unique_ptr<base::RunLoop> seller_worklet_run_loop_;
+
+  // Map from ReceiverSet IDs to display name when the process was launched.
+  // Used to verify that worklets are created in the right process.
+  std::map<mojo::ReceiverId, std::string> receiver_display_name_map_;
+
+  // ReceiverSet is last so that destroying `this` while there's a pending
+  // callback over the pipe will not DCHECK.
+  mojo::ReceiverSet<auction_worklet::mojom::AuctionWorkletService>
+      receiver_set_;
+};
+
+class AuctionWorkletManagerTest : public testing::Test,
+                                  public AuctionWorkletManager::Delegate {
+ public:
+  AuctionWorkletManagerTest()
+      : auction_worklet_manager_(&auction_process_manager_,
+                                 kTopWindowOrigin,
+                                 kFrameOrigin,
+                                 this) {
+    mojo::SetDefaultProcessErrorHandler(base::BindRepeating(
+        &AuctionWorkletManagerTest::OnBadMessage, base::Unretained(this)));
+  }
+
+  ~AuctionWorkletManagerTest() override {
+    // Any bad message should have been inspected and cleared before the end of
+    // the test.
+    EXPECT_EQ(std::string(), bad_message_);
+    mojo::SetDefaultProcessErrorHandler(base::NullCallback());
+  }
+
+  // AuctionWorkletManager::Delegate implementation:
+  network::mojom::URLLoaderFactory* GetFrameURLLoaderFactory() override {
+    return &url_loader_factory_;
+  }
+  network::mojom::URLLoaderFactory* GetTrustedURLLoaderFactory() override {
+    return &url_loader_factory_;
+  }
+  RenderFrameHostImpl* GetFrame() override { return nullptr; }
+  network::mojom::ClientSecurityStatePtr GetClientSecurityState() override {
+    return network::mojom::ClientSecurityState::New();
+  }
+
+ protected:
+  void OnBadMessage(const std::string& reason) {
+    // No test expects multiple bad messages at a time
+    EXPECT_EQ(std::string(), bad_message_);
+    // Empty bad messages aren't expected. This check allows an empty
+    // `bad_message_` field to mean no bad message, avoiding using an optional,
+    // which has less helpful output on EXPECT failures.
+    EXPECT_FALSE(reason.empty());
+
+    bad_message_ = reason;
+  }
+
+  // Gets and clear most recent bad Mojo message.
+  std::string TakeBadMessage() { return std::move(bad_message_); }
+
+  const url::Origin kTopWindowOrigin =
+      url::Origin::Create(GURL("https://top.window.origin.test/"));
+  // Frame origin is passed in buth otherwise ignored by these tests - it's only
+  // used by the DevTools hooks, which only have integration tests.
+  const url::Origin kFrameOrigin =
+      url::Origin::Create(GURL("https://frame.origin.test/"));
+
+  // Defaults used by most tests.
+  const GURL kDecisionLogicUrl = GURL("https://seller.test/script");
+  const GURL kTrustedSignalsUrl = GURL("https://seller.test/trusted_signals");
+
+  base::test::TaskEnvironment task_environment_;
+
+  std::string bad_message_;
+
+  network::TestURLLoaderFactory url_loader_factory_;
+  MockAuctionProcessManager auction_process_manager_;
+  AuctionWorkletManager auction_worklet_manager_;
+};
+
+TEST_F(AuctionWorkletManagerTest, SingleSellerWorklet) {
+  std::unique_ptr<AuctionWorkletManager::WorkletHandle> handle;
+  ASSERT_TRUE(auction_worklet_manager_.RequestSellerWorklet(
+      kDecisionLogicUrl, kTrustedSignalsUrl,
+      NeverInvokedWorkletAvailableCallback(), NeverInvokedFatalErrorCallback(),
+      handle));
+  EXPECT_TRUE(handle->GetSellerWorklet());
+
+  std::unique_ptr<MockSellerWorklet> seller_worklet =
+      auction_process_manager_.WaitForSellerWorklet();
+  EXPECT_EQ(kDecisionLogicUrl, seller_worklet->script_source_url());
+  EXPECT_EQ(kTrustedSignalsUrl, seller_worklet->trusted_scoring_signals_url());
+  EXPECT_EQ(kTopWindowOrigin, seller_worklet->top_window_origin());
+
+  EXPECT_EQ(0, seller_worklet->num_send_pending_signals_requests_calls());
+  handle->GetSellerWorklet()->SendPendingSignalsRequests();
+  seller_worklet->WaitForSendPendingSignalsRequests(1);
+}
+
+// Test the case where a seller worklet request completes asynchronously. This
+// only happens when the SellerWorklet process limit has been reached. This test
+// also serves to make sure that different seller origins result in different
+// processes.
+TEST_F(AuctionWorkletManagerTest, SellerWorkletAsync) {
+  // Create `kMaxSellerProcesses` for origins other than https://seller.test.
+  //
+  // For proper destruction ordering, `handles` should be after
+  // `seller_worklets`. Otherwise, worklet destruction will result in invoking
+  // the `handles` fatal error callback, as if they had crashed.
+  std::list<std::unique_ptr<MockSellerWorklet>> seller_worklets;
+  std::list<std::unique_ptr<AuctionWorkletManager::WorkletHandle>> handles;
+  for (size_t i = 0; i < AuctionProcessManager::kMaxSellerProcesses; ++i) {
+    EXPECT_EQ(i, auction_process_manager_.GetSellerProcessCountForTesting());
+
+    GURL decision_logic_url =
+        GURL(base::StringPrintf("https://seller%zu.test", i));
+    std::unique_ptr<AuctionWorkletManager::WorkletHandle> handle;
+    ASSERT_TRUE(auction_worklet_manager_.RequestSellerWorklet(
+        decision_logic_url, /*trusted_scoring_signals_url=*/absl::nullopt,
+        NeverInvokedWorkletAvailableCallback(),
+        NeverInvokedFatalErrorCallback(), handle));
+    EXPECT_TRUE(handle->GetSellerWorklet());
+    EXPECT_EQ(i + 1,
+              auction_process_manager_.GetSellerProcessCountForTesting());
+
+    std::unique_ptr<MockSellerWorklet> seller_worklet =
+        auction_process_manager_.WaitForSellerWorklet();
+    EXPECT_EQ(decision_logic_url, seller_worklet->script_source_url());
+    EXPECT_EQ(absl::nullopt, seller_worklet->trusted_scoring_signals_url());
+    EXPECT_EQ(kTopWindowOrigin, seller_worklet->top_window_origin());
+
+    EXPECT_EQ(0, seller_worklet->num_send_pending_signals_requests_calls());
+    handle->GetSellerWorklet()->SendPendingSignalsRequests();
+    seller_worklet->WaitForSendPendingSignalsRequests(1);
+
+    handles.emplace_back(std::move(handle));
+    seller_worklets.emplace_back(std::move(seller_worklet));
+  }
+
+  // Should be at the seller process limit.
+  EXPECT_EQ(AuctionProcessManager::kMaxSellerProcesses,
+            auction_process_manager_.GetSellerProcessCountForTesting());
+
+  // The next request for a distinct seller worklet should not complete
+  // synchronously, since there's no available process quota.
+  base::RunLoop worklet_available_loop;
+  std::unique_ptr<AuctionWorkletManager::WorkletHandle> handle;
+  ASSERT_FALSE(auction_worklet_manager_.RequestSellerWorklet(
+      kDecisionLogicUrl, kTrustedSignalsUrl,
+      worklet_available_loop.QuitClosure(), NeverInvokedFatalErrorCallback(),
+      handle));
+  EXPECT_EQ(AuctionProcessManager::kMaxSellerProcesses,
+            auction_process_manager_.GetSellerProcessCountForTesting());
+  EXPECT_FALSE(worklet_available_loop.AnyQuitCalled());
+
+  // Freeing a WorkletHandle should result in a new process being
+  // available, and the most recent request getting a new worklet.
+
+  handles.pop_front();
+  worklet_available_loop.Run();
+  EXPECT_TRUE(handle->GetSellerWorklet());
+
+  std::unique_ptr<MockSellerWorklet> seller_worklet =
+      auction_process_manager_.WaitForSellerWorklet();
+  EXPECT_EQ(kDecisionLogicUrl, seller_worklet->script_source_url());
+  EXPECT_EQ(kTrustedSignalsUrl, seller_worklet->trusted_scoring_signals_url());
+  EXPECT_EQ(kTopWindowOrigin, seller_worklet->top_window_origin());
+
+  EXPECT_EQ(0, seller_worklet->num_send_pending_signals_requests_calls());
+  handle->GetSellerWorklet()->SendPendingSignalsRequests();
+  seller_worklet->WaitForSendPendingSignalsRequests(1);
+
+  // Should still be at the process limit.
+  EXPECT_EQ(AuctionProcessManager::kMaxSellerProcesses,
+            auction_process_manager_.GetSellerProcessCountForTesting());
+}
+
+// Test that requests with the same parameters reuse seller worklets.
+TEST_F(AuctionWorkletManagerTest, ReuseSellerWorklet) {
+  // Load a seller worklet.
+  std::unique_ptr<AuctionWorkletManager::WorkletHandle> handle1;
+  ASSERT_TRUE(auction_worklet_manager_.RequestSellerWorklet(
+      kDecisionLogicUrl, kTrustedSignalsUrl,
+      NeverInvokedWorkletAvailableCallback(), NeverInvokedFatalErrorCallback(),
+      handle1));
+  EXPECT_TRUE(handle1->GetSellerWorklet());
+  std::unique_ptr<MockSellerWorklet> seller_worklet1 =
+      auction_process_manager_.WaitForSellerWorklet();
+  EXPECT_EQ(kDecisionLogicUrl, seller_worklet1->script_source_url());
+  EXPECT_EQ(kTrustedSignalsUrl, seller_worklet1->trusted_scoring_signals_url());
+  EXPECT_EQ(kTopWindowOrigin, seller_worklet1->top_window_origin());
+  handle1->GetSellerWorklet()->SendPendingSignalsRequests();
+  seller_worklet1->WaitForSendPendingSignalsRequests(1);
+  // Should only be one process.
+  EXPECT_EQ(1u, auction_process_manager_.GetSellerProcessCountForTesting());
+
+  // Load a seller worklet with the same parameters. The worklet should be
+  // reused.
+  std::unique_ptr<AuctionWorkletManager::WorkletHandle> handle2;
+  ASSERT_TRUE(auction_worklet_manager_.RequestSellerWorklet(
+      kDecisionLogicUrl, kTrustedSignalsUrl,
+      NeverInvokedWorkletAvailableCallback(), NeverInvokedFatalErrorCallback(),
+      handle2));
+  EXPECT_EQ(handle1->GetSellerWorklet(), handle2->GetSellerWorklet());
+  EXPECT_FALSE(auction_process_manager_.HasSellerWorkletRequest());
+  handle2->GetSellerWorklet()->SendPendingSignalsRequests();
+  seller_worklet1->WaitForSendPendingSignalsRequests(2);
+  // Should still only be one process.
+  EXPECT_EQ(1u, auction_process_manager_.GetSellerProcessCountForTesting());
+
+  // Close original handle. Worklet should still be alive, and so should its
+  // process.
+  handle1.reset();
+  EXPECT_EQ(1u, auction_process_manager_.GetSellerProcessCountForTesting());
+
+  // Load a seller worklet with the same parameters. The worklet should still be
+  // reused again.
+  std::unique_ptr<AuctionWorkletManager::WorkletHandle> handle3;
+  ASSERT_TRUE(auction_worklet_manager_.RequestSellerWorklet(
+      kDecisionLogicUrl, kTrustedSignalsUrl,
+      NeverInvokedWorkletAvailableCallback(), NeverInvokedFatalErrorCallback(),
+      handle3));
+  EXPECT_EQ(handle2->GetSellerWorklet(), handle3->GetSellerWorklet());
+  EXPECT_FALSE(auction_process_manager_.HasSellerWorkletRequest());
+  handle3->GetSellerWorklet()->SendPendingSignalsRequests();
+  seller_worklet1->WaitForSendPendingSignalsRequests(3);
+  // Should still only be one process.
+  EXPECT_EQ(1u, auction_process_manager_.GetSellerProcessCountForTesting());
+
+  // Close both remaining handles.
+  handle2.reset();
+  handle3.reset();
+
+  // Process should be destroyed.
+  EXPECT_EQ(0u, auction_process_manager_.GetSellerProcessCountForTesting());
+
+  // Request another seller worklet. A new SellerWorklet in a new process should
+  // be created.
+  std::unique_ptr<AuctionWorkletManager::WorkletHandle> handle4;
+  ASSERT_TRUE(auction_worklet_manager_.RequestSellerWorklet(
+      kDecisionLogicUrl, kTrustedSignalsUrl,
+      NeverInvokedWorkletAvailableCallback(), NeverInvokedFatalErrorCallback(),
+      handle4));
+  EXPECT_TRUE(handle4->GetSellerWorklet());
+  std::unique_ptr<MockSellerWorklet> seller_worklet2 =
+      auction_process_manager_.WaitForSellerWorklet();
+  EXPECT_EQ(kDecisionLogicUrl, seller_worklet2->script_source_url());
+  EXPECT_EQ(kTrustedSignalsUrl, seller_worklet2->trusted_scoring_signals_url());
+  EXPECT_EQ(kTopWindowOrigin, seller_worklet2->top_window_origin());
+  EXPECT_EQ(0, seller_worklet2->num_send_pending_signals_requests_calls());
+  handle4->GetSellerWorklet()->SendPendingSignalsRequests();
+  seller_worklet2->WaitForSendPendingSignalsRequests(1);
+  EXPECT_EQ(1u, auction_process_manager_.GetSellerProcessCountForTesting());
+}
+
+// Make sure that worklets are not reused when parameters don't match.
+TEST_F(AuctionWorkletManagerTest, DifferentSellerWorklets) {
+  // Load a seller worklet.
+  std::unique_ptr<AuctionWorkletManager::WorkletHandle> handle1;
+  ASSERT_TRUE(auction_worklet_manager_.RequestSellerWorklet(
+      kDecisionLogicUrl, kTrustedSignalsUrl,
+      NeverInvokedWorkletAvailableCallback(), NeverInvokedFatalErrorCallback(),
+      handle1));
+  EXPECT_TRUE(handle1->GetSellerWorklet());
+  std::unique_ptr<MockSellerWorklet> seller_worklet1 =
+      auction_process_manager_.WaitForSellerWorklet();
+  EXPECT_EQ(kDecisionLogicUrl, seller_worklet1->script_source_url());
+  EXPECT_EQ(kTrustedSignalsUrl, seller_worklet1->trusted_scoring_signals_url());
+  EXPECT_EQ(kTopWindowOrigin, seller_worklet1->top_window_origin());
+  // Should only be one process.
+  EXPECT_EQ(1u, auction_process_manager_.GetSellerProcessCountForTesting());
+
+  // Load a seller worklet with a different decision logic URL. A new worklet
+  // should be created, using the same process.
+  const GURL kDifferentDecisionLogicUrl =
+      GURL("https://seller.test/different_script");
+  std::unique_ptr<AuctionWorkletManager::WorkletHandle> handle2;
+  ASSERT_TRUE(auction_worklet_manager_.RequestSellerWorklet(
+      kDifferentDecisionLogicUrl, kTrustedSignalsUrl,
+      NeverInvokedWorkletAvailableCallback(), NeverInvokedFatalErrorCallback(),
+      handle2));
+  EXPECT_TRUE(handle1->GetSellerWorklet());
+  EXPECT_NE(handle1->GetSellerWorklet(), handle2->GetSellerWorklet());
+  std::unique_ptr<MockSellerWorklet> seller_worklet2 =
+      auction_process_manager_.WaitForSellerWorklet();
+  EXPECT_EQ(kDifferentDecisionLogicUrl, seller_worklet2->script_source_url());
+  EXPECT_EQ(kTrustedSignalsUrl, seller_worklet2->trusted_scoring_signals_url());
+  EXPECT_EQ(kTopWindowOrigin, seller_worklet2->top_window_origin());
+  // Should still only be one process.
+  EXPECT_EQ(1u, auction_process_manager_.GetSellerProcessCountForTesting());
+
+  // Load a seller worklet with a different (null) trusted signals URL. A new
+  // worklet should be created, using the same process.
+  std::unique_ptr<AuctionWorkletManager::WorkletHandle> handle3;
+  ASSERT_TRUE(auction_worklet_manager_.RequestSellerWorklet(
+      kDecisionLogicUrl, /*trusted_scoring_signals_url=*/absl::nullopt,
+      NeverInvokedWorkletAvailableCallback(), NeverInvokedFatalErrorCallback(),
+      handle3));
+  EXPECT_TRUE(handle3->GetSellerWorklet());
+  EXPECT_NE(handle1->GetSellerWorklet(), handle3->GetSellerWorklet());
+  EXPECT_NE(handle2->GetSellerWorklet(), handle3->GetSellerWorklet());
+  std::unique_ptr<MockSellerWorklet> seller_worklet3 =
+      auction_process_manager_.WaitForSellerWorklet();
+  EXPECT_EQ(kDecisionLogicUrl, seller_worklet3->script_source_url());
+  EXPECT_EQ(absl::nullopt, seller_worklet3->trusted_scoring_signals_url());
+  EXPECT_EQ(kTopWindowOrigin, seller_worklet3->top_window_origin());
+  // Should still only be one process.
+  EXPECT_EQ(1u, auction_process_manager_.GetSellerProcessCountForTesting());
+}
+
+TEST_F(AuctionWorkletManagerTest, SellerWorkletLoadError) {
+  const char kErrorText[] = "Goat teleportation error";
+
+  // Load a seller worklet.
+  FatalLoadErrorHelper load_error_helper;
+  std::unique_ptr<AuctionWorkletManager::WorkletHandle> handle;
+  ASSERT_TRUE(auction_worklet_manager_.RequestSellerWorklet(
+      kDecisionLogicUrl, kTrustedSignalsUrl,
+      NeverInvokedWorkletAvailableCallback(), load_error_helper.Callback(),
+      handle));
+  EXPECT_TRUE(handle->GetSellerWorklet());
+
+  // Return a load error.
+  std::unique_ptr<MockSellerWorklet> seller_worklet =
+      auction_process_manager_.WaitForSellerWorklet();
+  seller_worklet->ClosePipe(kErrorText);
+
+  // Wait for the load error, check the parameters.
+  load_error_helper.WaitForResult();
+  EXPECT_THAT(load_error_helper.errors(), testing::ElementsAre(kErrorText));
+  EXPECT_EQ(AuctionWorkletManager::FatalErrorType::kScriptLoadFailed,
+            load_error_helper.fatal_error_type());
+
+  // Should be safe to call into the worklet, even after the error. This allows
+  // errors to be handled asynchronously.
+  handle->GetSellerWorklet()->SendPendingSignalsRequests();
+  task_environment_.RunUntilIdle();
+
+  // Another request for the same worklet should trigger creation of a new
+  // worklet, even though the old handle for the worklet hasn't been deleted
+  // yet.
+  std::unique_ptr<AuctionWorkletManager::WorkletHandle> handle2;
+  ASSERT_TRUE(auction_worklet_manager_.RequestSellerWorklet(
+      kDecisionLogicUrl, kTrustedSignalsUrl,
+      NeverInvokedWorkletAvailableCallback(), load_error_helper.Callback(),
+      handle2));
+  EXPECT_TRUE(handle2->GetSellerWorklet());
+  EXPECT_NE(handle->GetSellerWorklet(), handle2->GetSellerWorklet());
+  std::unique_ptr<MockSellerWorklet> seller_worklet2 =
+      auction_process_manager_.WaitForSellerWorklet();
+}
+
+TEST_F(AuctionWorkletManagerTest, SellerWorkletCrash) {
+  // Load a seller worklet.
+  FatalLoadErrorHelper load_error_helper;
+  std::unique_ptr<AuctionWorkletManager::WorkletHandle> handle;
+  ASSERT_TRUE(auction_worklet_manager_.RequestSellerWorklet(
+      kDecisionLogicUrl, kTrustedSignalsUrl,
+      NeverInvokedWorkletAvailableCallback(), load_error_helper.Callback(),
+      handle));
+  EXPECT_TRUE(handle->GetSellerWorklet());
+
+  // Close the worklet pipe, simulating a worklet crash.
+  std::unique_ptr<MockSellerWorklet> seller_worklet =
+      auction_process_manager_.WaitForSellerWorklet();
+  seller_worklet.reset();
+
+  // Wait for the error, check the parameters.
+  load_error_helper.WaitForResult();
+  EXPECT_THAT(load_error_helper.errors(),
+              testing::ElementsAre("https://seller.test/script crashed."));
+  EXPECT_EQ(AuctionWorkletManager::FatalErrorType::kWorkletCrash,
+            load_error_helper.fatal_error_type());
+
+  // Should be safe to call into the worklet, even after the error. This allows
+  // errors to be handled asynchronously.
+  handle->GetSellerWorklet()->SendPendingSignalsRequests();
+  task_environment_.RunUntilIdle();
+  handle->GetSellerWorklet()->SendPendingSignalsRequests();
+
+  // Another request for the same worklet should trigger creation of a new
+  // worklet, even though the old handle for the worklet hasn't been deleted
+  // yet.
+  std::unique_ptr<AuctionWorkletManager::WorkletHandle> handle2;
+  ASSERT_TRUE(auction_worklet_manager_.RequestSellerWorklet(
+      kDecisionLogicUrl, kTrustedSignalsUrl,
+      NeverInvokedWorkletAvailableCallback(), load_error_helper.Callback(),
+      handle2));
+  EXPECT_TRUE(handle2->GetSellerWorklet());
+  EXPECT_NE(handle->GetSellerWorklet(), handle2->GetSellerWorklet());
+  std::unique_ptr<MockSellerWorklet> seller_worklet2 =
+      auction_process_manager_.WaitForSellerWorklet();
+}
+
+// Test reentrant deletion of a WorkletHandle on error.
+TEST_F(AuctionWorkletManagerTest, SellerWorkletDeleteOnError) {
+  const char kErrorText[] = "Goat teleporation error";
+
+  // Load a seller worklet.
+  base::RunLoop run_loop;
+  std::unique_ptr<AuctionWorkletManager::WorkletHandle> handle;
+  ASSERT_TRUE(auction_worklet_manager_.RequestSellerWorklet(
+      kDecisionLogicUrl, kTrustedSignalsUrl,
+      NeverInvokedWorkletAvailableCallback(),
+      base::BindLambdaForTesting(
+          [&](AuctionWorkletManager::FatalErrorType fatal_error_type,
+              const std::vector<std::string>& errors) {
+            handle.reset();
+            run_loop.Quit();
+          }),
+      handle));
+  EXPECT_TRUE(handle->GetSellerWorklet());
+
+  // Return a load error.
+  std::unique_ptr<MockSellerWorklet> seller_worklet =
+      auction_process_manager_.WaitForSellerWorklet();
+  seller_worklet->ClosePipe(kErrorText);
+
+  run_loop.Run();
+  // The process should have been deleted, and there should be no crashes.
+  EXPECT_EQ(0u, auction_process_manager_.GetSellerProcessCountForTesting());
+}
+
+// Minimal test that seller worklets' AuctionURLLoaderFactoryProxies are
+// correctly configured.
+TEST_F(AuctionWorkletManagerTest, SellerWorkletUrlRequestProtection) {
+  std::unique_ptr<AuctionWorkletManager::WorkletHandle> handle;
+  ASSERT_TRUE(auction_worklet_manager_.RequestSellerWorklet(
+      kDecisionLogicUrl, kTrustedSignalsUrl,
+      NeverInvokedWorkletAvailableCallback(), NeverInvokedFatalErrorCallback(),
+      handle));
+  EXPECT_TRUE(handle->GetSellerWorklet());
+
+  std::unique_ptr<MockSellerWorklet> seller_worklet =
+      auction_process_manager_.WaitForSellerWorklet();
+
+  const struct {
+    GURL url;
+    const char* mime_type;
+  } kAllowedUrls[] = {
+      {kDecisionLogicUrl, "application/javascript"},
+      {GURL("https://seller.test/"
+            "trusted_signals?hostname=top.window.origin.test&render_urls=not_"
+            "validated"),
+       "application/json"},
+  };
+
+  for (size_t i = 0; i < base::size(kAllowedUrls); ++i) {
+    network::ResourceRequest request;
+    request.url = kAllowedUrls[i].url;
+    request.headers.SetHeader(net::HttpRequestHeaders::kAccept,
+                              kAllowedUrls[i].mime_type);
+    mojo::PendingRemote<network::mojom::URLLoader> receiver;
+    mojo::PendingReceiver<network::mojom::URLLoaderClient> client;
+    seller_worklet->url_loader_factory()->CreateLoaderAndStart(
+        receiver.InitWithNewPipeAndPassReceiver(), 0 /*request_id=*/,
+        /*options=*/0, request, client.InitWithNewPipeAndPassRemote(),
+        net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
+    seller_worklet->url_loader_factory().FlushForTesting();
+    EXPECT_TRUE(seller_worklet->url_loader_factory().is_connected());
+    ASSERT_EQ(i + 1, url_loader_factory_.pending_requests()->size());
+    EXPECT_EQ(kAllowedUrls[i].url,
+              (*url_loader_factory_.pending_requests())[i].request.url);
+  }
+
+  // Other URLs should be rejected.
+  network::ResourceRequest request;
+  request.url = GURL("https://seller.test/");
+  request.headers.SetHeader(net::HttpRequestHeaders::kAccept,
+                            kAllowedUrls[0].mime_type);
+  mojo::PendingRemote<network::mojom::URLLoader> receiver;
+  mojo::PendingReceiver<network::mojom::URLLoaderClient> client;
+  seller_worklet->url_loader_factory()->CreateLoaderAndStart(
+      receiver.InitWithNewPipeAndPassReceiver(), /*request_id=*/0,
+      /*options=*/0, request, client.InitWithNewPipeAndPassRemote(),
+      net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
+  seller_worklet->url_loader_factory().FlushForTesting();
+  EXPECT_FALSE(seller_worklet->url_loader_factory().is_connected());
+  EXPECT_EQ(2u, url_loader_factory_.pending_requests()->size());
+  EXPECT_EQ("Unexpected request", TakeBadMessage());
+}
+
+}  // namespace content
\ No newline at end of file
diff --git a/content/browser/interest_group/debuggable_auction_worklet.h b/content/browser/interest_group/debuggable_auction_worklet.h
index 0f3374a0..6bca4b5 100644
--- a/content/browser/interest_group/debuggable_auction_worklet.h
+++ b/content/browser/interest_group/debuggable_auction_worklet.h
@@ -43,6 +43,7 @@
 
  private:
   friend class AuctionRunner;
+  friend class AuctionWorkletManager;
   friend class std::default_delete<DebuggableAuctionWorklet>;
 
   // Registers `this` with DebuggableAuctionWorkletTracker, and passes through
diff --git a/content/browser/interest_group/interest_group_browsertest.cc b/content/browser/interest_group/interest_group_browsertest.cc
index 646ca63..4c48c32 100644
--- a/content/browser/interest_group/interest_group_browsertest.cc
+++ b/content/browser/interest_group/interest_group_browsertest.cc
@@ -41,6 +41,7 @@
 #include "content/public/test/test_frame_navigation_observer.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "content/public/test/url_loader_monitor.h"
+#include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom.h"
 #include "content/shell/browser/shell.h"
 #include "content/test/test_content_browser_client.h"
 #include "content/test/test_fenced_frame_url_mapping_result_observer.h"
diff --git a/content/browser/loader/file_url_loader_factory.cc b/content/browser/loader/file_url_loader_factory.cc
index 492aa47..126488c7 100644
--- a/content/browser/loader/file_url_loader_factory.cc
+++ b/content/browser/loader/file_url_loader_factory.cc
@@ -814,8 +814,7 @@
       base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kDisableWebSecurity) ||
       (request.request_initiator &&
-       (request.request_initiator->IsSameOriginWith(
-            url::Origin::Create(request.url)) ||
+       (request.request_initiator->IsSameOriginWith(request.url) ||
         (shared_cors_origin_access_list_ &&
          shared_cors_origin_access_list_->GetOriginAccessList()
                  .CheckAccessState(*request.request_initiator, request.url) ==
diff --git a/content/browser/loader/prefetch_url_loader_service.cc b/content/browser/loader/prefetch_url_loader_service.cc
index f2e9ef2..9e3835cf 100644
--- a/content/browser/loader/prefetch_url_loader_service.cc
+++ b/content/browser/loader/prefetch_url_loader_service.cc
@@ -240,10 +240,9 @@
   // The request is expected to be cross-origin. Same-origin prefetches do not
   // need a special NetworkIsolationKey, and therefore must not be marked for
   // restricted use.
-  url::Origin destination_origin = url::Origin::Create(resource_request.url);
   DCHECK(resource_request.request_initiator.has_value());  // Checked above.
   if (resource_request.request_initiator->IsSameOriginWith(
-          destination_origin)) {
+          resource_request.url)) {
     loader_factory_receivers_.ReportBadMessage(
         "Prefetch/IsValidCrossOrigin: same-origin");
     return false;
diff --git a/content/browser/payments/payment_manager.cc b/content/browser/payments/payment_manager.cc
index ddd2cef..7de03320 100644
--- a/content/browser/payments/payment_manager.cc
+++ b/content/browser/payments/payment_manager.cc
@@ -75,7 +75,7 @@
         "Scope URL is not from the same origin of the context URL.");
     return;
   }
-  if (!origin_.IsSameOriginWith(url::Origin::Create(context_url))) {
+  if (!origin_.IsSameOriginWith(context_url)) {
     receiver_.ResetWithReason(
         static_cast<uint32_t>(ReasonCode::kCrossOriginDataAccess),
         "Cross origin data access.");
diff --git a/content/browser/prerender/prerender_host_registry.cc b/content/browser/prerender/prerender_host_registry.cc
index ab26eaaa..550f7e1 100644
--- a/content/browser/prerender/prerender_host_registry.cc
+++ b/content/browser/prerender/prerender_host_registry.cc
@@ -112,7 +112,7 @@
     // skip the same-origin check.
     if (!attributes.IsBrowserInitiated() &&
         !attributes.initiator_origin.value().IsSameOriginWith(
-            url::Origin::Create(attributes.prerendering_url))) {
+            attributes.prerendering_url)) {
       RecordPrerenderHostFinalStatus(
           PrerenderHost::FinalStatus::kCrossOriginNavigation,
           attributes.trigger_type, attributes.embedder_histogram_suffix);
diff --git a/content/browser/prerender/prerender_subframe_navigation_throttle.cc b/content/browser/prerender/prerender_subframe_navigation_throttle.cc
index 8a2f726..7853fdf 100644
--- a/content/browser/prerender/prerender_subframe_navigation_throttle.cc
+++ b/content/browser/prerender/prerender_subframe_navigation_throttle.cc
@@ -188,8 +188,7 @@
   // through the NavigationThrottle, so it's not a problem here
   RenderFrameHostImpl* rfhi = frame_tree_node->frame_tree()->GetMainFrame();
   const url::Origin& main_origin = rfhi->GetLastCommittedOrigin();
-  if (!main_origin.IsSameOriginWith(
-          url::Origin::Create(navigation_handle()->GetURL()))) {
+  if (!main_origin.IsSameOriginWith(navigation_handle()->GetURL())) {
     DeferCrossOriginSubframeNavigation(*frame_tree_node);
     return NavigationThrottle::DEFER;
   }
diff --git a/content/browser/renderer_host/ancestor_throttle.cc b/content/browser/renderer_host/ancestor_throttle.cc
index 5e243bb..5118916 100644
--- a/content/browser/renderer_host/ancestor_throttle.cc
+++ b/content/browser/renderer_host/ancestor_throttle.cc
@@ -279,10 +279,9 @@
     RenderFrameHostImpl* parent = request->frame_tree_node()
                                       ->current_frame_host()
                                       ->GetParentOrOuterDocument();
-    url::Origin current_origin =
-        url::Origin::Create(navigation_handle()->GetURL());
     while (parent) {
-      if (!parent->GetLastCommittedOrigin().IsSameOriginWith(current_origin)) {
+      if (!parent->GetLastCommittedOrigin().IsSameOriginWith(
+              navigation_handle()->GetURL())) {
         GetContentClient()->browser()->LogWebFeatureForCurrentPage(
             parent, blink::mojom::WebFeature::
                         kEmbeddedCrossOriginFrameWithoutFrameAncestorsOrXFO);
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index 1e9ff7d0..d341c50 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -5030,8 +5030,7 @@
   RenderFrameHostImpl* parent = frame_tree_node_->parent();
   DCHECK(parent);
   const GURL& parent_url = parent->GetLastCommittedURL();
-  if (url::Origin::Create(parent_url)
-          .IsSameOriginWith(url::Origin::Create(common_params_->url)) &&
+  if (url::IsSameOriginWith(parent_url, common_params_->url) &&
       parent_url.username() == common_params_->url.username() &&
       parent_url.password() == common_params_->url.password()) {
     return CredentialedSubresourceCheckResult::ALLOW_REQUEST;
diff --git a/content/browser/renderer_host/render_frame_host_csp_context.cc b/content/browser/renderer_host/render_frame_host_csp_context.cc
index 4b74dd3..f58d7b7d 100644
--- a/content/browser/renderer_host/render_frame_host_csp_context.cc
+++ b/content/browser/renderer_host/render_frame_host_csp_context.cc
@@ -46,12 +46,12 @@
   // There is no need to sanitize data when it is same-origin with the current
   // url of the renderer.
   if (render_frame_host_) {
-    if (url::Origin::Create(*blocked_url)
-            .IsSameOriginWith(render_frame_host_->GetLastCommittedOrigin())) {
+    if (render_frame_host_->GetLastCommittedOrigin().IsSameOriginWith(
+            *blocked_url)) {
       sanitize_blocked_url = false;
     }
-    if (url::Origin::Create(source_location_url)
-            .IsSameOriginWith(render_frame_host_->GetLastCommittedOrigin())) {
+    if (render_frame_host_->GetLastCommittedOrigin().IsSameOriginWith(
+            source_location_url)) {
       sanitize_source_location = false;
     }
   }
diff --git a/content/browser/service_worker/service_worker_container_host.cc b/content/browser/service_worker/service_worker_container_host.cc
index 42470968..09412433 100644
--- a/content/browser/service_worker/service_worker_container_host.cc
+++ b/content/browser/service_worker/service_worker_container_host.cc
@@ -910,8 +910,6 @@
       fetch_request_window_id_ = base::UnguessableToken::Create();
   }
 
-  auto previous_origin = url::Origin::Create(previous_url);
-  auto new_origin = url::Origin::Create(url);
   // Update client id on cross origin redirects. This corresponds to the HTML
   // standard's "process a navigation fetch" algorithm's step for discarding
   // |reservedEnvironment|.
@@ -920,8 +918,7 @@
   // same as |reservedEnvironment|'s creation URL's origin, then:
   //    1. Run the environment discarding steps for |reservedEnvironment|.
   //    2. Set |reservedEnvironment| to null."
-  if (previous_url.is_valid() &&
-      !new_origin.IsSameOriginWith(previous_origin)) {
+  if (previous_url.is_valid() && !url::IsSameOriginWith(previous_url, url)) {
     // Remove old controller since we know the controller is definitely
     // changed. We need to remove |this| from |controller_|'s controllee before
     // updating UUID since ServiceWorkerVersion has a map from uuid to provider
diff --git a/content/browser/service_worker/service_worker_new_script_fetcher.cc b/content/browser/service_worker/service_worker_new_script_fetcher.cc
index 379e67f..84dfcb85 100644
--- a/content/browser/service_worker/service_worker_new_script_fetcher.cc
+++ b/content/browser/service_worker/service_worker_new_script_fetcher.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/service_worker/service_worker_new_script_fetcher.h"
 
+#include "content/browser/devtools/devtools_instrumentation.h"
 #include "content/browser/service_worker/service_worker_context_core.h"
 #include "content/browser/service_worker/service_worker_loader_helpers.h"
 #include "content/browser/service_worker/service_worker_new_script_loader.h"
@@ -103,6 +104,11 @@
   // service worker.
   uint32_t options = network::mojom::kURLLoadOptionSendSSLInfoWithResponse;
 
+  // Notify to DevTools that the request for fetching the service worker script
+  // is about to start. It fires `Network.onRequestWillBeSent` event.
+  devtools_instrumentation::OnServiceWorkerMainScriptRequestWillBeSent(
+      requesting_frame_id_, version_->reporting_source(), request);
+
   mojo::MakeSelfOwnedReceiver(
       ServiceWorkerNewScriptLoader::CreateAndStart(
           request_id_, options, request,
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index 008c0207..133bf5f 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -1442,8 +1442,7 @@
     return;
   }
 
-  if (!url.is_valid() ||
-      !url::Origin::Create(url).IsSameOriginWith(key_.origin())) {
+  if (!url.is_valid() || !key_.origin().IsSameOriginWith(url)) {
     mojo::ReportBadMessage(
         "Received PaymentRequestEvent#openWindow() request for a cross-origin "
         "URL.");
diff --git a/content/browser/shared_storage/shared_storage_document_service_impl.cc b/content/browser/shared_storage/shared_storage_document_service_impl.cc
index 2c1147e..88204ac0 100644
--- a/content/browser/shared_storage/shared_storage_document_service_impl.cc
+++ b/content/browser/shared_storage/shared_storage_document_service_impl.cc
@@ -32,7 +32,7 @@
     const GURL& script_source_url,
     AddModuleOnWorkletCallback callback) {
   if (!render_frame_host().GetLastCommittedOrigin().IsSameOriginWith(
-          url::Origin::Create(script_source_url))) {
+          script_source_url)) {
     // This could indicate a compromised renderer, so let's terminate it.
     mojo::ReportBadMessage("Attempted to load a cross-origin module script.");
 
diff --git a/content/browser/shared_storage/shared_storage_url_loader_factory_proxy.cc b/content/browser/shared_storage/shared_storage_url_loader_factory_proxy.cc
index ca0ea14..a70dae3 100644
--- a/content/browser/shared_storage/shared_storage_url_loader_factory_proxy.cc
+++ b/content/browser/shared_storage/shared_storage_url_loader_factory_proxy.cc
@@ -51,7 +51,7 @@
     const network::ResourceRequest& url_request,
     mojo::PendingRemote<network::mojom::URLLoaderClient> client,
     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
-  DCHECK(frame_origin_.IsSameOriginWith(url::Origin::Create(script_url_)));
+  DCHECK(frame_origin_.IsSameOriginWith(script_url_));
 
   if (url_request.url != script_url_) {
     receiver_.ReportBadMessage("Unexpected request");
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 72800e23..6bbbd826 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -312,7 +312,7 @@
     return false;
 
   if (security_level < blink::ProtocolHandlerSecurityLevel::kUntrustedOrigins &&
-      !url_origin.IsSameOriginWith(origin))
+      !origin.IsSameOriginWith(url))
     return false;
 
   return true;
@@ -6761,9 +6761,7 @@
     if (!render_frame_host->GetLastCommittedOrigin().opaque()) {
       bool is_different_origin_subframe =
           render_frame_host->GetLastCommittedOrigin() !=
-          url::Origin::Create(render_frame_host->GetOutermostMainFrame()
-                                  ->GetLastCommittedURL()
-                                  .DeprecatedGetOriginAsURL());
+          render_frame_host->GetOutermostMainFrame()->GetLastCommittedOrigin();
       suppress_this_message |= is_different_origin_subframe;
       if (is_different_origin_subframe) {
         GetMainFrame()->AddMessageToConsole(
diff --git a/content/public/browser/shared_worker_instance.cc b/content/public/browser/shared_worker_instance.cc
index 9a2a61d7..6a308a4c 100644
--- a/content/public/browser/shared_worker_instance.cc
+++ b/content/public/browser/shared_worker_instance.cc
@@ -29,7 +29,7 @@
   DCHECK(url.SchemeIs(url::kDataScheme) ||
          GetContentClient()->browser()->DoesSchemeAllowCrossOriginSharedWorker(
              storage_key.origin().scheme()) ||
-         url::Origin::Create(url).IsSameOriginWith(storage_key.origin()));
+         storage_key.origin().IsSameOriginWith(url));
 }
 
 SharedWorkerInstance::SharedWorkerInstance(const SharedWorkerInstance& other) =
diff --git a/content/public/renderer/chrome_object_extensions_utils.h b/content/public/renderer/chrome_object_extensions_utils.h
index 3667a561..3db44b62 100644
--- a/content/public/renderer/chrome_object_extensions_utils.h
+++ b/content/public/renderer/chrome_object_extensions_utils.h
@@ -16,6 +16,7 @@
 
 namespace content {
 
+// Get or create a "chrome" object in the global object.
 CONTENT_EXPORT v8::Local<v8::Object> GetOrCreateChromeObject(
     v8::Isolate* isolate,
     v8::Local<v8::Context> context);
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index c456239..487cba7 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -4834,7 +4834,7 @@
   // adapted to the renderer process side.
   if (!params->origin.opaque() && params->url.IsStandard() &&
       GetBlinkPreferences().web_security_enabled) {
-    if (!params->origin.IsSameOriginWith(url::Origin::Create(params->url))) {
+    if (!params->origin.IsSameOriginWith(params->url)) {
       // Exclude file: URLs when settings allow them access any origin.
       if (!file_scheme_with_universal_access) {
         SCOPED_CRASH_KEY_STRING256("MakeDCPLParams", "mismatched_url",
diff --git a/content/renderer/web_ui_extension.cc b/content/renderer/web_ui_extension.cc
index fb89c09f..61db4a5 100644
--- a/content/renderer/web_ui_extension.cc
+++ b/content/renderer/web_ui_extension.cc
@@ -57,14 +57,35 @@
   return true;
 }
 
+// Get or create a `child_name` object in the `parent` object.
+v8::Local<v8::Object> GetOrCreateChildObject(v8::Local<v8::Object> parent,
+                                             const std::string& child_name,
+                                             v8::Isolate* isolate,
+                                             v8::Local<v8::Context> context) {
+  v8::Local<v8::Object> child;
+  v8::Local<v8::Value> child_value;
+  if (!parent->Get(context, gin::StringToV8(isolate, child_name))
+           .ToLocal(&child_value) ||
+      !child_value->IsObject()) {
+    child = v8::Object::New(isolate);
+    parent->Set(context, gin::StringToSymbol(isolate, child_name), child)
+        .Check();
+  } else {
+    child = v8::Local<v8::Object>::Cast(child_value);
+  }
+  return child;
+}
+
 }  // namespace
 
-// Exposes two methods:
+// Exposes three methods:
 //  - chrome.send: Used to send messages to the browser. Requires the message
 //      name as the first argument and can have an optional second argument that
 //      should be an array.
 //  - chrome.getVariableValue: Returns value for the input variable name if such
 //      a value was set by the browser. Else will return an empty string.
+//  - chrome.timeTicks.nowInMicroseconds: Returns base::TimeTicks::Now() in
+//      microseconds. Used for performance measuring.
 void WebUIExtension::Install(blink::WebLocalFrame* frame) {
   v8::Isolate* isolate = blink::MainThreadIsolate();
   v8::HandleScope handle_scope(isolate);
@@ -89,6 +110,16 @@
                 ->GetFunction(context)
                 .ToLocalChecked())
       .Check();
+
+  v8::Local<v8::Object> timeTicks =
+      GetOrCreateChildObject(chrome, "timeTicks", isolate, context);
+  timeTicks
+      ->Set(context, gin::StringToSymbol(isolate, "nowInMicroseconds"),
+            gin::CreateFunctionTemplate(
+                isolate, base::BindRepeating(&base::TimeTicks::Now))
+                ->GetFunction(context)
+                .ToLocalChecked())
+      .Check();
 }
 
 // static
diff --git a/content/renderer/web_ui_extension.h b/content/renderer/web_ui_extension.h
index c318d472..9393a21 100644
--- a/content/renderer/web_ui_extension.h
+++ b/content/renderer/web_ui_extension.h
@@ -7,6 +7,12 @@
 
 #include <string>
 
+#include "gin/converter.h"
+
+namespace base {
+class TimeTicks;
+}
+
 namespace blink {
 class WebLocalFrame;
 }
diff --git a/content/services/auction_worklet/auction_worklet_service_impl.cc b/content/services/auction_worklet/auction_worklet_service_impl.cc
index b098588..59f20b1 100644
--- a/content/services/auction_worklet/auction_worklet_service_impl.cc
+++ b/content/services/auction_worklet/auction_worklet_service_impl.cc
@@ -56,15 +56,26 @@
         pending_url_loader_factory,
     const GURL& decision_logic_url,
     const absl::optional<GURL>& trusted_scoring_signals_url,
-    const url::Origin& top_window_origin,
-    LoadSellerWorkletCallback load_seller_worklet_callback) {
-  seller_worklets_.Add(
-      std::make_unique<SellerWorklet>(
-          auction_v8_helper_, pause_for_debugger_on_start,
-          std::move(pending_url_loader_factory), decision_logic_url,
-          trusted_scoring_signals_url, top_window_origin,
-          std::move(load_seller_worklet_callback)),
-      std::move(seller_worklet_receiver));
+    const url::Origin& top_window_origin) {
+  auto seller_worklet = std::make_unique<SellerWorklet>(
+      auction_v8_helper_, pause_for_debugger_on_start,
+      std::move(pending_url_loader_factory), decision_logic_url,
+      trusted_scoring_signals_url, top_window_origin);
+  auto* seller_worklet_ptr = seller_worklet.get();
+
+  mojo::ReceiverId receiver_id = seller_worklets_.Add(
+      std::move(seller_worklet), std::move(seller_worklet_receiver));
+
+  seller_worklet_ptr->set_close_pipe_callback(
+      base::BindOnce(&AuctionWorkletServiceImpl::DisconnectSellerWorklet,
+                     base::Unretained(this), receiver_id));
+}
+
+void AuctionWorkletServiceImpl::DisconnectSellerWorklet(
+    mojo::ReceiverId receiver_id,
+    const std::string& reason) {
+  seller_worklets_.RemoveWithReason(receiver_id, /*custom_reason_code=*/0,
+                                    reason);
 }
 
 void AuctionWorkletServiceImpl::DisconnectBidderWorklet(
diff --git a/content/services/auction_worklet/auction_worklet_service_impl.h b/content/services/auction_worklet/auction_worklet_service_impl.h
index a277463d..9682e7d1 100644
--- a/content/services/auction_worklet/auction_worklet_service_impl.h
+++ b/content/services/auction_worklet/auction_worklet_service_impl.h
@@ -58,10 +58,11 @@
           pending_url_loader_factory,
       const GURL& decision_logic_url,
       const absl::optional<GURL>& trusted_scoring_signals_url,
-      const url::Origin& top_window_origin,
-      LoadSellerWorkletCallback load_seller_worklet_callback) override;
+      const url::Origin& top_window_origin) override;
 
  private:
+  void DisconnectSellerWorklet(mojo::ReceiverId receiver_id,
+                               const std::string& reason);
   void DisconnectBidderWorklet(mojo::ReceiverId receiver_id,
                                const std::string& reason);
 
diff --git a/content/services/auction_worklet/bidder_worklet_unittest.cc b/content/services/auction_worklet/bidder_worklet_unittest.cc
index 4901246..b8fd29f2 100644
--- a/content/services/auction_worklet/bidder_worklet_unittest.cc
+++ b/content/services/auction_worklet/bidder_worklet_unittest.cc
@@ -98,7 +98,14 @@
     v8_helper_ = AuctionV8Helper::Create(AuctionV8Helper::CreateTaskRunner());
   }
 
-  ~BidderWorkletTest() override { task_environment_.RunUntilIdle(); }
+  ~BidderWorkletTest() override {
+    // Release the V8 helper and process all pending tasks. This is to make sure
+    // there aren't any pending tasks between the V8 thread and the main thread
+    // that will result in UAFs. These lines are not necessary for any test to
+    // pass.
+    v8_helper_.reset();
+    task_environment_.RunUntilIdle();
+  }
 
   // Default values. No test actually depends on these being anything but valid,
   // but test that set these can use this to reset values to default after each
diff --git a/content/services/auction_worklet/public/mojom/auction_worklet_service.mojom b/content/services/auction_worklet/public/mojom/auction_worklet_service.mojom
index 59ab1de8..3f28043d 100644
--- a/content/services/auction_worklet/public/mojom/auction_worklet_service.mojom
+++ b/content/services/auction_worklet/public/mojom/auction_worklet_service.mojom
@@ -81,6 +81,10 @@
   // hooks (which make script fetches act as if they were made from the parent
   // frame) restrict sharing to auctions within a single RenderFrame.
   //
+  // On load error, the worklet will close its pipe with a reason string. The
+  // reason string, and worklet errors messages more generally, are considered
+  // privileged and should not be passed to renderer processes.
+  //
   // Arguments:
   // `seller_worklet` The pipe to communicate with the SellerWorklet. Closing
   //  the pipe will abort any in-progress loads destroy the worklet. The
@@ -102,21 +106,11 @@
   //  auction, if there is one.
   //
   // `top_window_origin` The origin of the top-level window running the auction.
-  //
-  // Returns:
-  // `success` is true if the worklet was successfully loaded.
-  //
-  // `errors` The various error messages to be used for debugging. These are too
-  //  sensitive for the renderer to see. There may be errors even when the
-  //  worklet is successfully loaded, and there may be no errors when the load
-  //  fails.
   LoadSellerWorklet(
       pending_receiver<SellerWorklet> seller_worklet,
       bool pause_for_debugger_on_start,
       pending_remote<network.mojom.URLLoaderFactory> url_loader_factory,
       url.mojom.Url script_source_url,
       url.mojom.Url? trusted_scoring_signals_url,
-      url.mojom.Origin top_window_origin) => (
-          bool success,
-          array<string> errors);
+      url.mojom.Origin top_window_origin);
 };
diff --git a/content/services/auction_worklet/public/mojom/seller_worklet.mojom b/content/services/auction_worklet/public/mojom/seller_worklet.mojom
index af56a96..55750c6 100644
--- a/content/services/auction_worklet/public/mojom/seller_worklet.mojom
+++ b/content/services/auction_worklet/public/mojom/seller_worklet.mojom
@@ -14,13 +14,13 @@
 // Manages the auction workflow for one loaded FLEDGE seller worklet.
 // See https://github.com/WICG/turtledove/blob/main/FLEDGE.md
 //
-// The SellerWorklet is functionally stateless, so methods are
+// The SellerWorklet is functionally stateless apart from the requirement,
+// ScoreAd() complete once before any ReportResult() call, so methods are
 // idempotent and can be called multiple times, in any order, for
 // multiple auctions using the same worklet. There is no need to wait
 // for one callback to be invoked before calling another method.
 interface SellerWorklet {
-  // Calls the Javascript scoreAd() function to evaluate a bid. May only be
-  // called once the worklet has successfully completed loading. No data is
+  // Calls the Javascript scoreAd() function to evaluate a bid. No data is
   // leaked between consecutive invocations of this method, or between
   // invocations of this method and ReportResult().
   //
@@ -80,9 +80,11 @@
 
   // Calls the Javascript reportResult() function to get the information needed
   // to report the result of the auction to the seller. May only be called once
-  // the worklet has successfully completed loading. No data is leaked between
-  // consecutive invocations of this method, or between invocations of this
-  // method and ScoreAd().
+  // ScoreAd() has successfully scored an ad, which will ensure the worklet has
+  // completed loading. It does not make sense to invoke this with a score not
+  // generated by a previous ScoreAd() call, so this should not limit consumers.
+  // No data is leaked between consecutive invocations of this method, or
+  // between invocations of this method and ScoreAd().
   //
   // Arguments:
   // `shareable_auction_config` Subset of the blink.mojom.AuctionAdConfig that
diff --git a/content/services/auction_worklet/seller_worklet.cc b/content/services/auction_worklet/seller_worklet.cc
index 0f1a31a..412bd800 100644
--- a/content/services/auction_worklet/seller_worklet.cc
+++ b/content/services/auction_worklet/seller_worklet.cc
@@ -127,9 +127,7 @@
         pending_url_loader_factory,
     const GURL& decision_logic_url,
     const absl::optional<GURL>& trusted_scoring_signals_url,
-    const url::Origin& top_window_origin,
-    mojom::AuctionWorkletService::LoadSellerWorkletCallback
-        load_worklet_callback)
+    const url::Origin& top_window_origin)
     : v8_runner_(v8_helper->v8_runner()),
       v8_helper_(std::move(v8_helper)),
       debug_id_(
@@ -146,10 +144,8 @@
                     *trusted_scoring_signals_url,
                     v8_helper_.get())
               : nullptr),
-      v8_state_(nullptr, base::OnTaskRunnerDeleter(v8_runner_)),
-      load_worklet_callback_(std::move(load_worklet_callback)) {
+      v8_state_(nullptr, base::OnTaskRunnerDeleter(v8_runner_)) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(user_sequence_checker_);
-  DCHECK(load_worklet_callback_);
 
   v8_state_ = std::unique_ptr<V8State, base::OnTaskRunnerDeleter>(
       new V8State(v8_helper_, debug_id_, decision_logic_url, top_window_origin,
@@ -163,10 +159,6 @@
 
 SellerWorklet::~SellerWorklet() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(user_sequence_checker_);
-  if (load_worklet_callback_) {
-    std::move(load_worklet_callback_)
-        .Run(false /* success */, std::vector<std::string>() /* errors */);
-  }
   debug_id_->AbortDebuggerPauses();
 }
 
@@ -201,6 +193,8 @@
       browser_signal_bidding_duration_msecs;
   score_ad_task->callback = std::move(callback);
 
+  // If `trusted_signals_request_manager_` exists, there's a trusted scoring
+  // signals URL which needs to be fetched before the auction can be run.
   if (trusted_signals_request_manager_) {
     score_ad_task->trusted_scoring_signals_request =
         trusted_signals_request_manager_->RequestScoringSignals(
@@ -211,8 +205,7 @@
     return;
   }
 
-  OnTrustedScoringSignalsDownloaded(score_ad_task, /*result=*/nullptr,
-                                    /*error_msg=*/absl::nullopt);
+  ScoreAdIfReady(score_ad_task);
 }
 
 void SellerWorklet::SendPendingSignalsRequests() {
@@ -228,6 +221,7 @@
     double browser_signal_desirability,
     ReportResultCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(user_sequence_checker_);
+  CHECK(IsCodeReady());
 
   v8_runner_->PostTask(
       FROM_HERE,
@@ -529,21 +523,30 @@
 void SellerWorklet::OnDownloadComplete(WorkletLoader::Result worklet_script,
                                        absl::optional<std::string> error_msg) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(user_sequence_checker_);
-  DCHECK(load_worklet_callback_);
   worklet_loader_.reset();
 
+  // On failure, delete `this`, as it can't do anything without a loaded script.
   bool success = worklet_script.success();
-  if (success) {
-    v8_runner_->PostTask(
-        FROM_HERE, base::BindOnce(&SellerWorklet::V8State::SetWorkletScript,
-                                  base::Unretained(v8_state_.get()),
-                                  std::move(worklet_script)));
+  if (!success) {
+    std::move(close_pipe_callback_)
+        .Run(error_msg ? error_msg.value() : std::string());
+    // `this` should be deleted at this point.
+    return;
   }
 
-  std::vector<std::string> errors;
-  if (error_msg)
-    errors.emplace_back(std::move(error_msg).value());
-  std::move(load_worklet_callback_).Run(success, errors);
+  // The error message, if any, will be appended to all invoked ScoreAd() and
+  // ReportResult() callbacks.
+  load_script_error_msg_ = std::move(error_msg);
+
+  v8_runner_->PostTask(FROM_HERE,
+                       base::BindOnce(&SellerWorklet::V8State::SetWorkletScript,
+                                      base::Unretained(v8_state_.get()),
+                                      std::move(worklet_script)));
+
+  for (auto score_ad_task = score_ad_tasks_.begin();
+       score_ad_task != score_ad_tasks_.end(); ++score_ad_task) {
+    ScoreAdIfReady(score_ad_task);
+  }
 }
 
 void SellerWorklet::OnTrustedScoringSignalsDownloaded(
@@ -553,15 +556,26 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(user_sequence_checker_);
 
   task->trusted_scoring_signals_error_msg = std::move(error_msg);
+  task->trusted_bidding_signals_result = std::move(result);
   // Clean up single-use object, now that it has done its job.
   task->trusted_scoring_signals_request.reset();
 
+  ScoreAdIfReady(task);
+}
+
+void SellerWorklet::ScoreAdIfReady(ScoreAdTaskList::iterator task) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(user_sequence_checker_);
+
+  if (task->trusted_scoring_signals_request || !IsCodeReady())
+    return;
+
   v8_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(
           &SellerWorklet::V8State::ScoreAd, base::Unretained(v8_state_.get()),
           task->ad_metadata_json, task->bid,
-          std::move(task->shareable_auction_config), std::move(result),
+          std::move(task->shareable_auction_config),
+          std::move(task->trusted_bidding_signals_result),
           std::move(task->browser_signal_interest_group_owner),
           std::move(task->browser_signal_render_url),
           std::move(task->browser_signal_ad_components),
@@ -576,6 +590,8 @@
     std::vector<std::string> errors) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(user_sequence_checker_);
 
+  if (load_script_error_msg_)
+    errors.insert(errors.begin(), load_script_error_msg_.value());
   if (task->trusted_scoring_signals_error_msg)
     errors.insert(errors.begin(), *task->trusted_scoring_signals_error_msg);
 
@@ -589,8 +605,16 @@
     absl::optional<GURL> report_url,
     std::vector<std::string> errors) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(user_sequence_checker_);
+
+  if (load_script_error_msg_)
+    errors.insert(errors.begin(), load_script_error_msg_.value());
+
   std::move(callback).Run(std::move(signals_for_winner), std::move(report_url),
                           std::move(errors));
 }
 
+bool SellerWorklet::IsCodeReady() const {
+  return (!paused_ && !worklet_loader_);
+}
+
 }  // namespace auction_worklet
diff --git a/content/services/auction_worklet/seller_worklet.h b/content/services/auction_worklet/seller_worklet.h
index d41a084..12f5369 100644
--- a/content/services/auction_worklet/seller_worklet.h
+++ b/content/services/auction_worklet/seller_worklet.h
@@ -42,23 +42,34 @@
 // seller worklet's Javascript.
 class SellerWorklet : public mojom::SellerWorklet {
  public:
-  // Starts loading the worklet script on construction. Callback will be invoked
-  // asynchronously once the data has been fetched or an error has occurred.
+  // Deletes the worklet immediately and resets the SellerWorklet's Mojo pipe
+  // with the provided description. See mojo::Receiver::ResetWithReason().
+  using ClosePipeCallback =
+      base::OnceCallback<void(const std::string& description)>;
+
+  // Starts loading the worklet script on construction.
   SellerWorklet(scoped_refptr<AuctionV8Helper> v8_helper,
                 bool pause_for_debugger_on_start,
                 mojo::PendingRemote<network::mojom::URLLoaderFactory>
                     pending_url_loader_factory,
                 const GURL& decision_logic_url,
                 const absl::optional<GURL>& trusted_scoring_signals_url,
-                const url::Origin& top_window_origin,
-                mojom::AuctionWorkletService::LoadSellerWorkletCallback
-                    load_worklet_callback);
+                const url::Origin& top_window_origin);
 
   explicit SellerWorklet(const SellerWorklet&) = delete;
   SellerWorklet& operator=(const SellerWorklet&) = delete;
 
   ~SellerWorklet() override;
 
+  // Sets the callback to be invoked on errors which require closing the pipe.
+  // Callback will also immediately delete `this`. Not an argument to
+  // constructor because the Mojo ReceiverId needs to be bound to the callback,
+  // but can only get that after creating the worklet. Must be called
+  // immediately after creating a SellerWorklet.
+  void set_close_pipe_callback(ClosePipeCallback close_pipe_callback) {
+    close_pipe_callback_ = std::move(close_pipe_callback);
+  }
+
   int context_group_id_for_testing() const;
 
   // mojom::SellerWorklet implementation:
@@ -107,6 +118,7 @@
 
     std::unique_ptr<TrustedSignalsRequestManager::Request>
         trusted_scoring_signals_request;
+    scoped_refptr<TrustedSignals::Result> trusted_bidding_signals_result;
 
     // Error message from downloading trusted scoring signals, if any. Prepended
     // to errors passed to the ScoreAdCallback.
@@ -205,6 +217,11 @@
       scoped_refptr<TrustedSignals::Result> result,
       absl::optional<std::string> error_msg);
 
+  // Checks if the script has been loaded successfully, and the
+  // TrustedSignals load has finished, if needed (successfully or not). If so,
+  // calls scoreAd().
+  void ScoreAdIfReady(ScoreAdTaskList::iterator task);
+
   void DeliverScoreAdCallbackOnUserThread(ScoreAdTaskList::iterator task,
                                           double score,
                                           std::vector<std::string> errors);
@@ -215,6 +232,9 @@
       absl::optional<GURL> report_url,
       std::vector<std::string> errors);
 
+  // Returns true if unpaused and the script has loaded.
+  bool IsCodeReady() const;
+
   scoped_refptr<base::SequencedTaskRunner> v8_runner_;
   scoped_refptr<AuctionV8Helper> v8_helper_;
   scoped_refptr<AuctionV8Helper::DebugId> debug_id_;
@@ -236,14 +256,17 @@
   // std::vector.
   ScoreAdTaskList score_ad_tasks_;
 
+  // Deleted once load has completed.
   std::unique_ptr<WorkletLoader> worklet_loader_;
 
   // Lives on `v8_runner_`. Since it's deleted there, tasks can be safely
   // posted from main thread to it with an Unretained pointer.
   std::unique_ptr<V8State, base::OnTaskRunnerDeleter> v8_state_;
 
-  mojom::AuctionWorkletService::LoadSellerWorkletCallback
-      load_worklet_callback_;
+  ClosePipeCallback close_pipe_callback_;
+
+  // Error that occurred while loading the worklet script, if any.
+  absl::optional<std::string> load_script_error_msg_;
 
   SEQUENCE_CHECKER(user_sequence_checker_);
 
diff --git a/content/services/auction_worklet/seller_worklet_unittest.cc b/content/services/auction_worklet/seller_worklet_unittest.cc
index 99a8cbf..4e62444 100644
--- a/content/services/auction_worklet/seller_worklet_unittest.cc
+++ b/content/services/auction_worklet/seller_worklet_unittest.cc
@@ -5,6 +5,7 @@
 #include "content/services/auction_worklet/seller_worklet.h"
 
 #include <algorithm>
+#include <memory>
 #include <string>
 #include <utility>
 
@@ -20,11 +21,12 @@
 #include "content/services/auction_worklet/worklet_devtools_debug_test_util.h"
 #include "content/services/auction_worklet/worklet_test_util.h"
 #include "content/services/auction_worklet/worklet_v8_debug_test_util.h"
-#include "mojo/public/cpp/bindings/self_owned_receiver.h"
+#include "mojo/public/cpp/bindings/unique_receiver_set.h"
 #include "net/http/http_status_code.h"
 #include "services/network/test/test_url_loader_factory.h"
 #include "testing/gmock/include/gmock/gmock-matchers.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/public/mojom/interest_group/interest_group_types.mojom.h"
 #include "url/gurl.h"
 
@@ -80,7 +82,8 @@
       return %s;
     }
   )";
-  return base::StringPrintf(kBasicSellerScript, extra_code.c_str(),
+  return CreateBasicSellAdScript() +
+         base::StringPrintf(kBasicSellerScript, extra_code.c_str(),
                             raw_return_value.c_str());
 }
 
@@ -91,7 +94,18 @@
     v8_helper_ = AuctionV8Helper::Create(AuctionV8Helper::CreateTaskRunner());
   }
 
-  ~SellerWorkletTest() override { task_environment_.RunUntilIdle(); }
+  ~SellerWorkletTest() override {
+    // Release the V8 helper and process all pending tasks. This is to make sure
+    // there aren't any pending tasks between the V8 thread and the main thread
+    // that will result in UAFs. These lines are not necessary for any test to
+    // pass.
+    v8_helper_.reset();
+    task_environment_.RunUntilIdle();
+
+    // In all tests where the SellerWorklet receiver is closed before the
+    // remote, the disconnect reason should be consumed and validated.
+    EXPECT_FALSE(disconnect_reason_);
+  }
 
   // Sets default values for scoreAd() and report_result() arguments. No test
   // actually depends on these being anything but valid, but this does allow
@@ -183,6 +197,18 @@
             expected_score, expected_errors, std::move(done_closure)));
   }
 
+  void RunScoreAdOnWorkletExpectingCallbackNeverInvoked(
+      mojom::SellerWorklet* seller_worklet) {
+    seller_worklet->ScoreAd(
+        ad_metadata_, bid_, shareable_config_.Clone(),
+        browser_signal_interest_group_owner_, browser_signal_render_url_,
+        browser_signal_ad_components_, browser_signal_bidding_duration_msecs_,
+        base::BindOnce(
+            [](double score, const std::vector<std::string>& errors) {
+              ADD_FAILURE() << "This should not be invoked";
+            }));
+  }
+
   // Loads and runs a scode_ad() script, expecting the supplied result.
   void RunScoreAdExpectingResultOnWorklet(
       mojom::SellerWorklet* seller_worklet,
@@ -267,12 +293,15 @@
   }
 
   // Loads and runs a report_result() script, expecting the supplied result.
+  // Runs ScoreAd() first, expecting a score of 1, since that's required before
+  // calling ReportResult.
   void RunReportResultExpectingResult(
       const absl::optional<std::string>& expected_signals_for_winner,
       const absl::optional<GURL>& expected_report_url,
       const std::vector<std::string>& expected_errors =
           std::vector<std::string>()) {
     auto seller_worklet = CreateWorklet();
+    RunScoreAdExpectingResultOnWorklet(seller_worklet.get(), 1);
     ASSERT_TRUE(seller_worklet);
 
     base::RunLoop run_loop;
@@ -282,11 +311,10 @@
     run_loop.Run();
   }
 
-  // Create a seller worklet, not waiting for completion. If
-  // out_seller_worklet_impl is non-null, will also the stash the actual
-  // implementation point there.
-  mojo::Remote<mojom::SellerWorklet> CreateWorkletImpl(
-      bool pause_for_debugger_on_start,
+  // Create a seller worklet. If out_seller_worklet_impl is non-null, will also
+  // the stash an actual implementation pointer there.
+  mojo::Remote<mojom::SellerWorklet> CreateWorklet(
+      bool pause_for_debugger_on_start = false,
       SellerWorklet** out_seller_worklet_impl = nullptr) {
     mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory;
     url_loader_factory_.Clone(
@@ -295,42 +323,55 @@
     mojo::Remote<mojom::SellerWorklet> seller_worklet;
     auto seller_worklet_impl = std::make_unique<SellerWorklet>(
         v8_helper_, pause_for_debugger_on_start, std::move(url_loader_factory),
-        decision_logic_url_, trusted_scoring_signals_url_, top_window_origin_,
-        base::BindOnce(&SellerWorkletTest::CreateWorkletCallback,
-                       base::Unretained(this)));
+        decision_logic_url_, trusted_scoring_signals_url_, top_window_origin_);
+    auto* seller_worklet_ptr = seller_worklet_impl.get();
+    mojo::ReceiverId receiver_id =
+        seller_worklets_.Add(std::move(seller_worklet_impl),
+                             seller_worklet.BindNewPipeAndPassReceiver());
+    seller_worklet_ptr->set_close_pipe_callback(
+        base::BindOnce(&SellerWorkletTest::ClosePipeCallback,
+                       base::Unretained(this), receiver_id));
+    seller_worklet.set_disconnect_with_reason_handler(base::BindRepeating(
+        &SellerWorkletTest::OnDisconnectWithReason, base::Unretained(this)));
+
     if (out_seller_worklet_impl)
-      *out_seller_worklet_impl = seller_worklet_impl.get();
-    mojo::MakeSelfOwnedReceiver(std::move(seller_worklet_impl),
-                                seller_worklet.BindNewPipeAndPassReceiver());
+      *out_seller_worklet_impl = seller_worklet_ptr;
     return seller_worklet;
   }
 
-  // Create a SellerWorklet, waiting for the URLLoader to complete. Returns
-  // a null Remote on failure.
-  mojo::Remote<mojom::SellerWorklet> CreateWorklet() {
-    CHECK(!load_script_run_loop_);
+  // Waits for OnDisconnectWithReason() to be invoked, if it hasn't been
+  // already, and returns the error string it was invoked with.
+  std::string WaitForDisconnect() {
+    DCHECK(!disconnect_run_loop_);
 
-    create_worklet_succeeded_ = false;
-    mojo::Remote<mojom::SellerWorklet> seller_worklet =
-        CreateWorkletImpl(/*pause_for_debugger_on_start=*/false);
-    load_script_run_loop_ = std::make_unique<base::RunLoop>();
-    load_script_run_loop_->Run();
-    load_script_run_loop_.reset();
-    if (!create_worklet_succeeded_)
-      return mojo::Remote<mojom::SellerWorklet>();
-    return seller_worklet;
-  }
+    if (!disconnect_reason_) {
+      disconnect_run_loop_ = std::make_unique<base::RunLoop>();
+      disconnect_run_loop_->Run();
+      disconnect_run_loop_.reset();
+    }
 
-  void CreateWorkletCallback(bool success,
-                             const std::vector<std::string>& errors) {
-    create_worklet_succeeded_ = success;
-    last_errors_ = errors;
-    if (success)
-      EXPECT_TRUE(last_errors_.empty());
-    load_script_run_loop_->Quit();
+    DCHECK(disconnect_reason_);
+    std::string disconnect_reason = std::move(disconnect_reason_).value();
+    disconnect_reason_.reset();
+    return disconnect_reason;
   }
 
  protected:
+  void ClosePipeCallback(mojo::ReceiverId receiver_id,
+                         const std::string& description) {
+    seller_worklets_.RemoveWithReason(receiver_id, /*custom_reason_code=*/0,
+                                      description);
+  }
+
+  void OnDisconnectWithReason(uint32_t custom_reason,
+                              const std::string& description) {
+    DCHECK(!disconnect_reason_);
+
+    disconnect_reason_ = description;
+    if (disconnect_run_loop_)
+      disconnect_run_loop_->Quit();
+  }
+
   base::test::TaskEnvironment task_environment_{
       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
 
@@ -350,60 +391,43 @@
   uint32_t browser_signal_bidding_duration_msecs_;
   double browser_signal_desireability_;
 
-  // Reuseable run loop for loading the script. It's always populated after
-  // creating the worklet, to cause a crash if the callback is invoked
-  // synchronously.
-  std::unique_ptr<base::RunLoop> load_script_run_loop_;
-  bool create_worklet_succeeded_ = false;
-  std::vector<std::string> last_errors_;
+  // Reuseable run loop for disconnection errors.
+  std::unique_ptr<base::RunLoop> disconnect_run_loop_;
+  absl::optional<std::string> disconnect_reason_;
 
   network::TestURLLoaderFactory url_loader_factory_;
   scoped_refptr<AuctionV8Helper> v8_helper_;
+
+  // Owns all created seller worklets - having a ReceiverSet allows them to have
+  // a ClosePipeCallback which behaves just like the one in
+  // AuctionWorkletServiceImpl, to better match production behavior.
+  mojo::UniqueReceiverSet<mojom::SellerWorklet> seller_worklets_;
 };
 
-// Test the case the SellerWorklet pipe is closed before invoking the
-// LoadSellerWorkletCallback. The LoadSellerWorkletCallback should be invoked,
-// and there should be no Mojo exception due to destroying the creation callback
-// without invoking it.
+// Test the case the SellerWorklet pipe is closed before any of its methods are
+// invoked. Nothing should happen.
 TEST_F(SellerWorkletTest, PipeClosed) {
-  mojo::Remote<mojom::SellerWorklet> seller_worklet;
-  mojo::PendingReceiver<network::mojom::URLLoaderFactory>
-      url_loader_factory_receiver;
-
-  mojo::MakeSelfOwnedReceiver(
-      std::make_unique<SellerWorklet>(
-          v8_helper_, /*pause_for_debugger_on_start=*/false,
-          url_loader_factory_receiver.InitWithNewPipeAndPassRemote(),
-          decision_logic_url_, trusted_scoring_signals_url_, top_window_origin_,
-          base::BindOnce(&SellerWorkletTest::CreateWorkletCallback,
-                         base::Unretained(this))),
-      seller_worklet.BindNewPipeAndPassReceiver());
-  load_script_run_loop_ = std::make_unique<base::RunLoop>();
-  seller_worklet.reset();
-
-  load_script_run_loop_->Run();
-  load_script_run_loop_.reset();
-  EXPECT_FALSE(create_worklet_succeeded_);
+  auto sellet_worklet = CreateWorklet();
+  sellet_worklet.reset();
+  base::RunLoop().RunUntilIdle();
 }
 
 TEST_F(SellerWorkletTest, NetworkError) {
   url_loader_factory_.AddResponse(decision_logic_url_.spec(),
                                   CreateBasicSellAdScript(),
                                   net::HTTP_NOT_FOUND);
-  EXPECT_FALSE(CreateWorklet());
-  EXPECT_EQ(
-      std::vector<std::string>{
-          "Failed to load https://url.test/ HTTP status = 404 Not Found."},
-      last_errors_);
+  auto sellet_worklet = CreateWorklet();
+  EXPECT_EQ("Failed to load https://url.test/ HTTP status = 404 Not Found.",
+            WaitForDisconnect());
 }
 
 TEST_F(SellerWorkletTest, CompileError) {
   AddJavascriptResponse(&url_loader_factory_, decision_logic_url_,
                         "Invalid Javascript");
-  EXPECT_FALSE(CreateWorklet());
-  ASSERT_EQ(1u, last_errors_.size());
-  EXPECT_THAT(last_errors_[0], StartsWith("https://url.test/:1 "));
-  EXPECT_THAT(last_errors_[0], HasSubstr("SyntaxError"));
+  auto sellet_worklet = CreateWorklet();
+  std::string disconnect_error = WaitForDisconnect();
+  EXPECT_THAT(disconnect_error, StartsWith("https://url.test/:1 "));
+  EXPECT_THAT(disconnect_error, HasSubstr("SyntaxError"));
 }
 
 // Test parsing of return values.
@@ -635,8 +659,43 @@
       TrustedSignalsRequestManager::kAutoSendDelay);
 }
 
-// Test the case of a bunch of ScoreAd() calls in parallel.
-TEST_F(SellerWorkletTest, ScoreAdParallel) {
+// Test the case of a bunch of ScoreAd() calls in parallel, all started before
+// the worklet script has loaded.
+TEST_F(SellerWorkletTest, ScoreAdParallelBeforeLoadComplete) {
+  mojo::Remote<mojom::SellerWorklet> seller_worklet =
+      CreateWorklet(/*pause_for_debugger_on_start=*/false);
+
+  const size_t kNumWorklets = 10;
+  size_t num_completed_worklets = 0;
+  base::RunLoop run_loop;
+  for (size_t i = 0; i < kNumWorklets; ++i) {
+    browser_signal_render_url_ = GURL(base::StringPrintf("https://foo/%zu", i));
+    RunScoreAdOnWorkletAsync(seller_worklet.get(), /*expected_score=*/i,
+                             /*expected_errors=*/std::vector<std::string>(),
+                             base::BindLambdaForTesting([&]() {
+                               ++num_completed_worklets;
+                               if (num_completed_worklets == kNumWorklets)
+                                 run_loop.Quit();
+                             }));
+  }
+
+  // No calls should complete, since the script hasn't loaded yet.
+  task_environment_.RunUntilIdle();
+  EXPECT_EQ(0u, num_completed_worklets);
+
+  // Load a seller script that uses the last character of `renderUrl` as the
+  // score. The worklet should report a successful load.
+  AddJavascriptResponse(
+      &url_loader_factory_, decision_logic_url_,
+      CreateScoreAdScript("parseInt(browserSignals.renderUrl.slice(-1))"));
+
+  // All scripts should complete successfully.
+  run_loop.Run();
+}
+
+// Test the case of a bunch of ScoreAd() calls in parallel, all started after
+// the worklet script has loaded.
+TEST_F(SellerWorkletTest, ScoreAdParallelAfterLoadComplete) {
   // Seller script that uses the last character of `renderUrl` as the score.
   AddJavascriptResponse(
       &url_loader_factory_, decision_logic_url_,
@@ -659,13 +718,38 @@
   run_loop.Run();
 }
 
+// Test the case of a bunch of ScoreAd() calls in parallel, all started before
+// the worklet script fails to load.
+TEST_F(SellerWorkletTest, ScoreAdParallelLoadFails) {
+  mojo::Remote<mojom::SellerWorklet> seller_worklet = CreateWorklet();
+
+  for (size_t i = 0; i < 10; ++i) {
+    browser_signal_render_url_ = GURL(base::StringPrintf("https://foo/%zu", i));
+    RunScoreAdOnWorkletExpectingCallbackNeverInvoked(seller_worklet.get());
+  }
+
+  // No calls should complete, since the script hasn't loaded yet.
+  task_environment_.RunUntilIdle();
+
+  // Script fails to load.
+  url_loader_factory_.AddResponse(decision_logic_url_.spec(),
+                                  /*content=*/std::string(),
+                                  net::HTTP_NOT_FOUND);
+
+  // The worklet should fail to load.
+  EXPECT_EQ("Failed to load https://url.test/ HTTP status = 404 Not Found.",
+            WaitForDisconnect());
+  // The worklet script callbacks should not be invoked.
+  task_environment_.RunUntilIdle();
+}
+
 // Test the case of a bunch of ScoreAd() calls in parallel, in the case trusted
 // scoring signals is non-null. In this case, call AllBidsGenerated() between
 // scoring each bid, which should result in requests being sent individually.
 TEST_F(SellerWorkletTest, ScoreAdParallelTrustedScoringSignalsNotBatched) {
   base::Time start_time = base::Time::Now();
 
-  // Seller script that gets the core from the `trustedScoringSignals` value of
+  // Seller script that gets the score from the `trustedScoringSignals` value of
   // the passed in `renderUrl`.
   AddJavascriptResponse(
       &url_loader_factory_, decision_logic_url_,
@@ -675,7 +759,7 @@
       GURL("https://url.test/trusted_scoring_signals");
   auto seller_worklet = CreateWorklet();
 
-  // Start scoring a bunch of worklets. Don't provide JSON responses to make
+  // Start scoring a bunch of worklets. Don't provide JSON responses, to make
   // sure they all reside in the worklet's task list at once.
   const size_t kNumWorklets = 10;
   size_t num_completed_worklets = 0;
@@ -721,8 +805,13 @@
 // scoring signals is non-null. In this case, don't call AllBidsGenerated()
 // between scoring each bid, which should result in all requests being sent as a
 // single request.
-TEST_F(SellerWorkletTest, ScoreAdParallelTrustedScoringSignalsBatched) {
-  // Seller script that gets the core from the `trustedScoringSignals` value of
+//
+// In this test, the ordering is:
+// 1) The worklet script load completes.
+// 2) ScoreAd() calls are made.
+// 3) The trusted bidding signals are loaded.
+TEST_F(SellerWorkletTest, ScoreAdParallelTrustedScoringSignalsBatched1) {
+  // Seller script that gets the score from the `trustedScoringSignals` value of
   // the passed in `renderUrl`.
   AddJavascriptResponse(
       &url_loader_factory_, decision_logic_url_,
@@ -732,7 +821,7 @@
       GURL("https://url.test/trusted_scoring_signals");
   auto seller_worklet = CreateWorklet();
 
-  // Start scoring a bunch of worklets. Don't provide JSON responses to make
+  // Start scoring a bunch of worklets. Don't provide JSON responses, to make
   // sure they all reside in the worklet's task list at once.
   const size_t kNumWorklets = 10;
   size_t num_completed_worklets = 0;
@@ -770,6 +859,133 @@
       base::StringPrintf(R"({"renderUrls": {%s}})", response_body.c_str());
   AddJsonResponse(&url_loader_factory_, GURL(request_url), response_body);
 
+  // All ScoreAd() calls should succeed with the expected scores.
+  run_loop.Run();
+}
+
+// Same as above, but with different ordering.
+//
+// In this test, the ordering is:
+// 1) ScoreAd() calls are made.
+// 2) The worklet script load completes.
+// 3) The trusted bidding signals are loaded.
+TEST_F(SellerWorkletTest, ScoreAdParallelTrustedScoringSignalsBatched2) {
+  trusted_scoring_signals_url_ =
+      GURL("https://url.test/trusted_scoring_signals");
+  mojo::Remote<mojom::SellerWorklet> seller_worklet = CreateWorklet();
+
+  // Start scoring a bunch of worklets. Don't provide JSON responses, to make
+  // sure they all reside in the worklet's task list at once.
+  const size_t kNumWorklets = 10;
+  size_t num_completed_worklets = 0;
+  base::RunLoop run_loop;
+  for (size_t i = 0; i < kNumWorklets; ++i) {
+    browser_signal_render_url_ = GURL(base::StringPrintf("https://foo/%zu", i));
+    RunScoreAdOnWorkletAsync(seller_worklet.get(), /*expected_score=*/2 * i,
+                             /*expected_errors=*/std::vector<std::string>(),
+                             base::BindLambdaForTesting([&]() {
+                               ++num_completed_worklets;
+                               if (num_completed_worklets == kNumWorklets)
+                                 run_loop.Quit();
+                             }));
+  }
+
+  // Spin run loop so all requests reach the scoring worklet.
+  run_loop.RunUntilIdle();
+  EXPECT_EQ(0u, num_completed_worklets);
+
+  // Return seller script that gets the score from the `trustedScoringSignals`
+  // value of the passed in `renderUrl`, and wait for it to finish loading.
+  AddJavascriptResponse(
+      &url_loader_factory_, decision_logic_url_,
+      CreateScoreAdScript(
+          "trustedScoringSignals.renderUrl[browserSignals.renderUrl]"));
+  task_environment_.RunUntilIdle();
+
+  // Provide a single response for the merged URL request.
+  std::string request_url =
+      base::StringPrintf("%s?hostname=%s&renderUrls=",
+                         trusted_scoring_signals_url_->spec().c_str(),
+                         top_window_origin_.host().c_str());
+  std::string response_body;
+  for (size_t i = 0; i < kNumWorklets; ++i) {
+    if (i > 0) {
+      request_url += ",";
+      response_body += ",";
+    }
+    request_url += base::StringPrintf("https%%3A%%2F%%2Ffoo%%2F%zu", i);
+    response_body += base::StringPrintf(R"("https://foo/%zu": %zu)", i, 2 * i);
+  }
+  response_body =
+      base::StringPrintf(R"({"renderUrls": {%s}})", response_body.c_str());
+  AddJsonResponse(&url_loader_factory_, GURL(request_url), response_body);
+
+  // All ScoreAd() calls should succeed with the expected scores.
+  run_loop.Run();
+}
+
+// Same as above, but with different ordering.
+//
+// In this test, the ordering is:
+// 1) ScoreAd() calls are made.
+// 2) The trusted bidding signals are loaded.
+// 3) The worklet script load completes.
+TEST_F(SellerWorkletTest, ScoreAdParallelTrustedScoringSignalsBatched3) {
+  trusted_scoring_signals_url_ =
+      GURL("https://url.test/trusted_scoring_signals");
+  mojo::Remote<mojom::SellerWorklet> seller_worklet = CreateWorklet();
+
+  // Start scoring a bunch of worklets. Don't provide JSON responses, to make
+  // sure they all reside in the worklet's task list at once.
+  const size_t kNumWorklets = 10;
+  size_t num_completed_worklets = 0;
+  base::RunLoop run_loop;
+  for (size_t i = 0; i < kNumWorklets; ++i) {
+    browser_signal_render_url_ = GURL(base::StringPrintf("https://foo/%zu", i));
+    RunScoreAdOnWorkletAsync(seller_worklet.get(), /*expected_score=*/2 * i,
+                             /*expected_errors=*/std::vector<std::string>(),
+                             base::BindLambdaForTesting([&]() {
+                               ++num_completed_worklets;
+                               if (num_completed_worklets == kNumWorklets)
+                                 run_loop.Quit();
+                             }));
+  }
+
+  // Spin run loop so all requests reach the scoring worklet.
+  run_loop.RunUntilIdle();
+  EXPECT_EQ(0u, num_completed_worklets);
+
+  // Provide a single response for the merged URL request.
+  std::string request_url =
+      base::StringPrintf("%s?hostname=%s&renderUrls=",
+                         trusted_scoring_signals_url_->spec().c_str(),
+                         top_window_origin_.host().c_str());
+  std::string response_body;
+  for (size_t i = 0; i < kNumWorklets; ++i) {
+    if (i > 0) {
+      request_url += ",";
+      response_body += ",";
+    }
+    request_url += base::StringPrintf("https%%3A%%2F%%2Ffoo%%2F%zu", i);
+    response_body += base::StringPrintf(R"("https://foo/%zu": %zu)", i, 2 * i);
+  }
+  response_body =
+      base::StringPrintf(R"({"renderUrls": {%s}})", response_body.c_str());
+  AddJsonResponse(&url_loader_factory_, GURL(request_url), response_body);
+
+  // Spin run loop so the response is handled. No ScoreAdCalls should complete
+  // yet.
+  run_loop.RunUntilIdle();
+  EXPECT_EQ(0u, num_completed_worklets);
+
+  // Return seller script that gets the score from the `trustedScoringSignals`
+  // value of the passed in `renderUrl`, and wait for it to finish loading.
+  AddJavascriptResponse(
+      &url_loader_factory_, decision_logic_url_,
+      CreateScoreAdScript(
+          "trustedScoringSignals.renderUrl[browserSignals.renderUrl]"));
+
+  // All ScoreAd() calls should succeed with the expected scores.
   run_loop.Run();
 }
 
@@ -797,7 +1013,7 @@
       "shrimp", std::string() /* extra_code */,
       absl::nullopt /* expected_signals_for_winner */,
       absl::nullopt /* expected_render_url */,
-      {"https://url.test/:4 Uncaught ReferenceError: "
+      {"https://url.test/:9 Uncaught ReferenceError: "
        "shrimp is not defined."});
 }
 
@@ -815,13 +1031,13 @@
       "1", R"(sendReportTo("http://foo.test/"))",
       absl::nullopt /* expected_signals_for_winner */,
       absl::nullopt /* expected_render_url */,
-      {"https://url.test/:3 Uncaught TypeError: "
+      {"https://url.test/:8 Uncaught TypeError: "
        "sendReportTo must be passed a valid HTTPS url."});
   RunReportResultCreatedScriptExpectingResult(
       "1", R"(sendReportTo("file:///foo/"))",
       absl::nullopt /* expected_signals_for_winner */,
       absl::nullopt /* expected_render_url */,
-      {"https://url.test/:3 Uncaught TypeError: "
+      {"https://url.test/:8 Uncaught TypeError: "
        "sendReportTo must be passed a valid HTTPS url."});
 
   // Multiple calls.
@@ -830,7 +1046,7 @@
       R"(sendReportTo("https://foo.test/"); sendReportTo("https://foo.test/"))",
       absl::nullopt /* expected_signals_for_winner */,
       absl::nullopt /* expected_render_url */,
-      {"https://url.test/:3 Uncaught TypeError: "
+      {"https://url.test/:8 Uncaught TypeError: "
        "sendReportTo may be called at most once."});
 
   // No message if caught, but still no URL.
@@ -846,19 +1062,19 @@
       "1", R"(sendReportTo("France"))",
       absl::nullopt /* expected_signals_for_winner */,
       absl::nullopt /* expected_render_url */,
-      {"https://url.test/:3 Uncaught TypeError: "
+      {"https://url.test/:8 Uncaught TypeError: "
        "sendReportTo must be passed a valid HTTPS url."});
   RunReportResultCreatedScriptExpectingResult(
       "1", R"(sendReportTo(null))",
       absl::nullopt /* expected_signals_for_winner */,
       absl::nullopt /* expected_render_url */,
-      {"https://url.test/:3 Uncaught TypeError: "
+      {"https://url.test/:8 Uncaught TypeError: "
        "sendReportTo requires 1 string parameter."});
   RunReportResultCreatedScriptExpectingResult(
       "1", R"(sendReportTo([5]))",
       absl::nullopt /* expected_signals_for_winner */,
       absl::nullopt /* expected_render_url */,
-      {"https://url.test/:3 Uncaught TypeError: "
+      {"https://url.test/:8 Uncaught TypeError: "
        "sendReportTo requires 1 string parameter."});
 }
 
@@ -867,7 +1083,7 @@
       "1", R"(sendReportTo("https://foo.test/" + Date().toString()))",
       absl::nullopt /* expected_signals_for_winner */,
       absl::nullopt /* expected_render_url */,
-      {"https://url.test/:3 Uncaught ReferenceError: Date is not defined."});
+      {"https://url.test/:8 Uncaught ReferenceError: Date is not defined."});
 }
 
 TEST_F(SellerWorkletTest, ReportResultTopWindowOrigin) {
@@ -1066,6 +1282,8 @@
       CreateReportToScript("1", R"(sendReportTo("https://foo.test"))"));
   auto seller_worklet = CreateWorklet();
   ASSERT_TRUE(seller_worklet);
+  // Need to call ScoreAd() calling ReportResult().
+  RunScoreAdExpectingResultOnWorklet(seller_worklet.get(), 1);
 
   base::WaitableEvent* event_handle = WedgeV8Thread(v8_helper_.get());
   seller_worklet->ReportResult(
@@ -1088,27 +1306,33 @@
 
   SellerWorklet* worklet_impl = nullptr;
   auto worklet =
-      CreateWorkletImpl(/*pause_for_debugger_on_start=*/true, &worklet_impl);
+      CreateWorklet(/*pause_for_debugger_on_start=*/true, &worklet_impl);
   // Grab the context ID to be able to resume.
   int id = worklet_impl->context_group_id_for_testing();
 
+  // Queue a ScoreAd() call, which should not happen immediately since loading
+  // is paused.
+  base::RunLoop run_loop;
+  RunScoreAdOnWorkletAsync(worklet.get(), /*expected_score=*/10,
+                           /*expected_errors=*/{}, run_loop.QuitClosure());
+
   // Give it a chance to fetch.
   task_environment_.RunUntilIdle();
+  EXPECT_FALSE(run_loop.AnyQuitCalled());
 
   AddJavascriptResponse(&url_loader_factory_, decision_logic_url_,
                         CreateScoreAdScript("10"));
 
-  // Set up the event loop for the standard callback.
-  load_script_run_loop_ = std::make_unique<base::RunLoop>();
-  // Let this run.
+  task_environment_.RunUntilIdle();
+  EXPECT_FALSE(run_loop.AnyQuitCalled());
+
+  // Let the ScoreAd() call run.
   v8_helper_->v8_runner()->PostTask(
       FROM_HERE, base::BindOnce([](scoped_refptr<AuctionV8Helper> v8_helper,
                                    int id) { v8_helper->Resume(id); },
                                 v8_helper_, id));
 
-  load_script_run_loop_->Run();
-  load_script_run_loop_.reset();
-  EXPECT_TRUE(create_worklet_succeeded_);
+  run_loop.RunUntilIdle();
 }
 
 TEST_F(SellerWorkletTest, PauseOnStartDelete) {
@@ -1117,7 +1341,11 @@
 
   SellerWorklet* worklet_impl = nullptr;
   auto worklet =
-      CreateWorkletImpl(/*pause_for_debugger_on_start=*/true, &worklet_impl);
+      CreateWorklet(/*pause_for_debugger_on_start=*/true, &worklet_impl);
+
+  // Queue a ScoreAd() call, which should start paused and will never be run.
+  base::RunLoop run_loop;
+  RunScoreAdOnWorkletExpectingCallbackNeverInvoked(worklet.get());
 
   // Give it a chance to fetch.
   task_environment_.RunUntilIdle();
@@ -1125,13 +1353,9 @@
   // Grab the context ID.
   int id = worklet_impl->context_group_id_for_testing();
 
-  // Delete the worklet. is should issue an error callback, so in turn it
-  // needs the event loop the callback in the fixture uses.
-  load_script_run_loop_ = std::make_unique<base::RunLoop>();
+  // Delete the worklet.
   worklet.reset();
-  load_script_run_loop_->Run();
-  load_script_run_loop_.reset();
-  EXPECT_FALSE(create_worklet_succeeded_);
+  task_environment_.RunUntilIdle();
 
   // Try to resume post-delete. Should not crash
   v8_helper_->v8_runner()->PostTask(
@@ -1162,13 +1386,19 @@
 
   SellerWorklet* worklet_impl1 = nullptr;
   decision_logic_url_ = kUrl1;
-  auto worklet1 = CreateWorkletImpl(
+  auto worklet1 = CreateWorklet(
       /*pause_for_debugger_on_start=*/true, &worklet_impl1);
+  base::RunLoop run_loop1;
+  RunScoreAdOnWorkletAsync(worklet1.get(), /*expected_score=*/1,
+                           /*expected_errors=*/{}, run_loop1.QuitClosure());
 
   decision_logic_url_ = kUrl2;
   SellerWorklet* worklet_impl2 = nullptr;
-  auto worklet2 = CreateWorkletImpl(
+  auto worklet2 = CreateWorklet(
       /*pause_for_debugger_on_start=*/true, &worklet_impl2);
+  base::RunLoop run_loop2;
+  RunScoreAdOnWorkletAsync(worklet2.get(), /*expected_score=*/2,
+                           /*expected_errors=*/{}, run_loop2.QuitClosure());
 
   int id1 = worklet_impl1->context_group_id_for_testing();
   int id2 = worklet_impl2->context_group_id_for_testing();
@@ -1193,18 +1423,11 @@
   EXPECT_TRUE(std::none_of(events1.begin(), events1.end(), is_script_parsed));
 
   // Unpause execution for #1.
-  load_script_run_loop_ = std::make_unique<base::RunLoop>();
+  EXPECT_FALSE(run_loop1.AnyQuitCalled());
   channel1->RunCommandAndWaitForResult(
       3, "Runtime.runIfWaitingForDebugger",
       R"({"id":3,"method":"Runtime.runIfWaitingForDebugger","params":{}})");
-  load_script_run_loop_->Run();
-  load_script_run_loop_.reset();
-  EXPECT_TRUE(create_worklet_succeeded_);
-  create_worklet_succeeded_ = false;
-
-  // Run the script to get parsing events.
-  decision_logic_url_ = kUrl1;
-  RunScoreAdExpectingResultOnWorklet(worklet1.get(), 1.0);
+  run_loop1.Run();
 
   // channel1 should have had a parsed notification for kUrl1.
   TestChannel::Event script_parsed1 =
@@ -1218,17 +1441,11 @@
   EXPECT_TRUE(std::none_of(events2.begin(), events2.end(), is_script_parsed));
 
   // Unpause execution for #2.
-  load_script_run_loop_ = std::make_unique<base::RunLoop>();
+  EXPECT_FALSE(run_loop2.AnyQuitCalled());
   channel2->RunCommandAndWaitForResult(
       3, "Runtime.runIfWaitingForDebugger",
       R"({"id":3,"method":"Runtime.runIfWaitingForDebugger","params":{}})");
-  load_script_run_loop_->Run();
-  load_script_run_loop_.reset();
-  EXPECT_TRUE(create_worklet_succeeded_);
-
-  // Run the script to get parsing events.
-  decision_logic_url_ = kUrl2;
-  RunScoreAdExpectingResultOnWorklet(worklet2.get(), 2.0);
+  run_loop2.Run();
 
   // channel2 should have had a parsed notification for kUrl2.
   TestChannel::Event script_parsed2 =
@@ -1254,7 +1471,7 @@
                         "Invalid Javascript");
   SellerWorklet* worklet_impl = nullptr;
   auto worklet =
-      CreateWorkletImpl(/*pause_for_debugger_on_start=*/true, &worklet_impl);
+      CreateWorklet(/*pause_for_debugger_on_start=*/true, &worklet_impl);
   int id = worklet_impl->context_group_id_for_testing();
   TestChannel* channel = inspector_support.ConnectDebuggerSession(id);
 
@@ -1264,14 +1481,11 @@
       2, "Debugger.enable",
       R"({"id":2,"method":"Debugger.enable","params":{}})");
 
-  // Unpause execution.
-  load_script_run_loop_ = std::make_unique<base::RunLoop>();
+  // Unpause execution and wait for the pipe to be closed with an error.
   channel->RunCommandAndWaitForResult(
       3, "Runtime.runIfWaitingForDebugger",
       R"({"id":3,"method":"Runtime.runIfWaitingForDebugger","params":{}})");
-  load_script_run_loop_->Run();
-  load_script_run_loop_.reset();
-  EXPECT_FALSE(create_worklet_succeeded_);
+  EXPECT_FALSE(WaitForDisconnect().empty());
 
   // Should have gotten a parse error notification.
   TestChannel::Event parse_error =
@@ -1293,9 +1507,17 @@
                         CreateScoreAdScript(kScriptResult));
 
   decision_logic_url_ = GURL(kUrl1);
-  auto worklet1 = CreateWorkletImpl(true /* pause_for_debugger_on_start */);
+  auto worklet1 = CreateWorklet(true /* pause_for_debugger_on_start */);
+  base::RunLoop run_loop1;
+  RunScoreAdOnWorkletAsync(worklet1.get(), 100.5, {}, run_loop1.QuitClosure());
+
   decision_logic_url_ = GURL(kUrl2);
-  auto worklet2 = CreateWorkletImpl(true /* pause_for_debugger_on_start */);
+  auto worklet2 = CreateWorklet(true /* pause_for_debugger_on_start */);
+  base::RunLoop run_loop2;
+  RunScoreAdOnWorkletAsync(
+      worklet2.get(), 0,
+      {"http://example.org/second.js scoreAd() did not return a valid number."},
+      run_loop2.QuitClosure());
 
   mojo::Remote<blink::mojom::DevToolsAgent> agent1, agent2;
   worklet1->ConnectDevToolsAgent(agent1.BindNewPipeAndPassReceiver());
@@ -1337,30 +1559,11 @@
       TestDevToolsAgentClient::Channel::kMain, 3, "Debugger.setBreakpointByUrl",
       base::StringPrintf(kBreakpointTemplate, kUrl2));
 
-  // Now start #1. This should result in successful worklet creation.
-  load_script_run_loop_ = std::make_unique<base::RunLoop>();
+  // Now start #1. We should see a scriptParsed event.
   debug1.RunCommandAndWaitForResult(
       TestDevToolsAgentClient::Channel::kMain, 4,
       "Runtime.runIfWaitingForDebugger",
       R"({"id":4,"method":"Runtime.runIfWaitingForDebugger","params":{}})");
-  load_script_run_loop_->Run();
-  EXPECT_TRUE(create_worklet_succeeded_);
-
-  // Start #2.
-  create_worklet_succeeded_ = false;
-  load_script_run_loop_ = std::make_unique<base::RunLoop>();
-  debug2.RunCommandAndWaitForResult(
-      TestDevToolsAgentClient::Channel::kMain, 4,
-      "Runtime.runIfWaitingForDebugger",
-      R"({"id":4,"method":"Runtime.runIfWaitingForDebugger","params":{}})");
-  load_script_run_loop_->Run();
-  EXPECT_TRUE(create_worklet_succeeded_);
-
-  // To actually have execution happen, call the score_ad function.
-  // For this one, we will modify the result to 100.5
-  decision_logic_url_ = GURL(kUrl1);
-  base::RunLoop run_loop;
-  RunScoreAdOnWorkletAsync(worklet1.get(), 100.5, {}, run_loop.QuitClosure());
 
   TestDevToolsAgentClient::Event script_parsed1 =
       debug1.WaitForMethodNotification("Debugger.scriptParsed");
@@ -1401,18 +1604,17 @@
 
   // Let worklet 1 finish. The callback set by RunScoreAdOnWorkletAsync() will
   // verify the result.
+  EXPECT_FALSE(run_loop1.AnyQuitCalled());
   debug1.RunCommandAndWaitForResult(
       TestDevToolsAgentClient::Channel::kIO, 6, "Debugger.resume",
       R"({"id":6,"method":"Debugger.resume","params":{}})");
-  run_loop.Run();
+  run_loop1.Run();
 
-  // Now score_ad on worklet 2.
-  decision_logic_url_ = GURL(kUrl2);
-  base::RunLoop run_loop2;
-  RunScoreAdOnWorkletAsync(
-      worklet2.get(), 0,
-      {"http://example.org/second.js scoreAd() did not return a valid number."},
-      run_loop2.QuitClosure());
+  // Start #2, see that it parses the script.
+  debug2.RunCommandAndWaitForResult(
+      TestDevToolsAgentClient::Channel::kMain, 4,
+      "Runtime.runIfWaitingForDebugger",
+      R"({"id":4,"method":"Runtime.runIfWaitingForDebugger","params":{}})");
 
   TestDevToolsAgentClient::Event script_parsed2 =
       debug2.WaitForMethodNotification("Debugger.scriptParsed");
@@ -1448,7 +1650,9 @@
   AddJavascriptResponse(&url_loader_factory_, GURL(kUrl), script_body);
 
   decision_logic_url_ = GURL(kUrl);
-  auto worklet = CreateWorkletImpl(true /* pause_for_debugger_on_start */);
+  auto worklet = CreateWorklet(true /* pause_for_debugger_on_start */);
+  base::RunLoop run_loop;
+  RunScoreAdOnWorkletAsync(worklet.get(), 1.0, {}, run_loop.QuitClosure());
 
   mojo::Remote<blink::mojom::DevToolsAgent> agent;
   worklet->ConnectDevToolsAgent(agent.BindNewPipeAndPassReceiver());
@@ -1475,18 +1679,11 @@
       MakeInstrumentationBreakpointCommand(
           4, "set", "beforeSellerWorkletReportingStart"));
 
-  // Resume execution of create.
-  load_script_run_loop_ = std::make_unique<base::RunLoop>();
+  // Resume creation, ScoreAd() call should hit a breakpoint.
   debug.RunCommandAndWaitForResult(
       TestDevToolsAgentClient::Channel::kMain, 5,
       "Runtime.runIfWaitingForDebugger",
       R"({"id":5,"method":"Runtime.runIfWaitingForDebugger","params":{}})");
-  load_script_run_loop_->Run();
-  EXPECT_TRUE(create_worklet_succeeded_);
-
-  // Try to run scoreAd. Should hit corresponding breakpoint.
-  base::RunLoop run_loop;
-  RunScoreAdOnWorkletAsync(worklet.get(), 1.0, {}, run_loop.QuitClosure());
 
   TestDevToolsAgentClient::Event breakpoint_hit1 =
       debug.WaitForMethodNotification("Debugger.paused");
@@ -1497,6 +1694,7 @@
   EXPECT_EQ("instrumentation:beforeSellerWorkletScoringStart", *breakpoint1);
 
   // Let scoring finish.
+  EXPECT_FALSE(run_loop.AnyQuitCalled());
   debug.RunCommandAndWaitForResult(
       TestDevToolsAgentClient::Channel::kIO, 6, "Debugger.resume",
       R"({"id":6,"method":"Debugger.resume","params":{}})");
@@ -1551,7 +1749,8 @@
   AddJavascriptResponse(&url_loader_factory_, GURL(kUrl), script_body);
 
   decision_logic_url_ = GURL(kUrl);
-  auto worklet = CreateWorkletImpl(/*pause_for_debugger_on_start=*/true);
+  auto worklet = CreateWorklet(/*pause_for_debugger_on_start=*/true);
+  RunScoreAdOnWorkletExpectingCallbackNeverInvoked(worklet.get());
 
   mojo::Remote<blink::mojom::DevToolsAgent> agent;
   worklet->ConnectDevToolsAgent(agent.BindNewPipeAndPassReceiver());
@@ -1572,16 +1771,12 @@
       "EventBreakpoints.setInstrumentationBreakpoint",
       MakeInstrumentationBreakpointCommand(3, "set",
                                            "beforeSellerWorkletScoringStart"));
-  // Resume execution of create.
-  load_script_run_loop_ = std::make_unique<base::RunLoop>();
+  // Resume execution of create. Should hit corresponding breakpoint.
   debug.RunCommandAndWaitForResult(
       TestDevToolsAgentClient::Channel::kMain, 4,
       "Runtime.runIfWaitingForDebugger",
       R"({"id":4,"method":"Runtime.runIfWaitingForDebugger","params":{}})");
-  load_script_run_loop_->Run();
-  EXPECT_TRUE(create_worklet_succeeded_);
 
-  // Try to run scoreAd. Should hit corresponding breakpoint.
   RunScoreAdOnWorkletAsync(worklet.get(), 1.0, {}, base::BindOnce([]() {
                              ADD_FAILURE()
                                  << "scoreAd shouldn't actually get to finish.";
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 5395ad5..bd5fd570 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -2061,6 +2061,7 @@
     "../browser/interest_group/auction_process_manager_unittest.cc",
     "../browser/interest_group/auction_runner_unittest.cc",
     "../browser/interest_group/auction_url_loader_factory_proxy_unittest.cc",
+    "../browser/interest_group/auction_worklet_manager_unittest.cc",
     "../browser/interest_group/interest_group_storage_unittest.cc",
     "../browser/loader/cors_origin_pattern_setter_unittest.cc",
     "../browser/loader/file_url_loader_factory_unittest.cc",
diff --git a/device/vr/windows/compositor_base.cc b/device/vr/windows/compositor_base.cc
index 1f5351b..331c0bb 100644
--- a/device/vr/windows/compositor_base.cc
+++ b/device/vr/windows/compositor_base.cc
@@ -398,6 +398,7 @@
     // shouldn't get new ones until this resolves or presentation ends/restarts.
     if (delayed_get_frame_data_callback_) {
       mojo::ReportBadMessage("Multiple outstanding GetFrameData calls");
+      return;
     }
     delayed_get_frame_data_callback_ = base::BindOnce(
         &XRCompositorCommon::GetFrameData, base::Unretained(this),
diff --git a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
index 891c981..7678e91 100644
--- a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
+++ b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
@@ -671,10 +671,8 @@
   // Following checks implement the step 10 of "4.4. HTTP-redirect fetch",
   // https://fetch.spec.whatwg.org/#http-redirect-fetch
   if (request_.request_initiator &&
-      (!url::Origin::Create(redirect_url_)
-            .IsSameOriginWith(url::Origin::Create(request_.url)) &&
-       !request_.request_initiator->IsSameOriginWith(
-           url::Origin::Create(request_.url)))) {
+      (!url::IsSameOriginWith(redirect_url_, request_.url) &&
+       !request_.request_initiator->IsSameOriginWith(request_.url))) {
     // Reset the initiator to pretend tainted origin flag of the spec is set.
     request_.request_initiator = url::Origin();
   }
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index 434874b..2a5357c 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -1672,6 +1672,7 @@
   OS_TELEMETRY_GETMEMORYINFO = 1609,
   AUTOTESTPRIVATE_COULDALLOWCROSTINI = 1610,
   WEB_AUTHENTICATION_PROXY_COMPLETE_CREATE_REQUEST = 1611,
+  DEVELOPERPRIVATE_GETUSERSITESETTINGS = 1612,
   // Last entry: Add new entries above, then run:
   // python tools/metrics/histograms/update_extension_histograms.py
   ENUM_BOUNDARY
diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
index 4fad18c..37922c3 100644
--- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
+++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
@@ -470,11 +470,8 @@
 
   if (navigation_handle->IsInMainFrame()) {
     // We should not navigate the guest away from the handling extension.
-    const url::Origin handler_origin =
-        url::Origin::Create(stream_->handler_url());
     const GURL& new_url = navigation_handle->GetURL();
-    const url::Origin new_origin = url::Origin::Create(new_url);
-    CHECK(new_origin.IsSameOriginWith(handler_origin) ||
+    CHECK(url::IsSameOriginWith(new_url, stream_->handler_url()) ||
           new_url.IsAboutBlank());
   }
 }
diff --git a/extensions/browser/guest_view/web_view/web_view_guest.cc b/extensions/browser/guest_view/web_view/web_view_guest.cc
index 589703f..2bcb453b 100644
--- a/extensions/browser/guest_view/web_view/web_view_guest.cc
+++ b/extensions/browser/guest_view/web_view/web_view_guest.cc
@@ -1250,8 +1250,7 @@
   }
   const url::Origin& owner_origin =
       owner_web_contents()->GetMainFrame()->GetLastCommittedOrigin();
-  const bool base_in_owner_origin =
-      owner_origin.IsSameOriginWith(url::Origin::Create(base_url));
+  const bool base_in_owner_origin = owner_origin.IsSameOriginWith(base_url);
   // |base_url| must be a valid URL. It is also limited to URLs that the owner
   // is trusted to have control over.
   if (!base_url.is_valid() ||
diff --git a/extensions/common/permissions/permissions_data.cc b/extensions/common/permissions/permissions_data.cc
index 599814e..e4b2c0e 100644
--- a/extensions/common/permissions/permissions_data.cc
+++ b/extensions/common/permissions/permissions_data.cc
@@ -446,8 +446,8 @@
     // sufficient.
     if ((origin_url.SchemeIs(url::kHttpScheme) ||
          origin_url.SchemeIs(url::kHttpsScheme)) &&
-        !origin.IsSameOriginWith(url::Origin::Create(
-            ExtensionsClient::Get()->GetWebstoreBaseURL()))) {
+        !origin.IsSameOriginWith(
+            ExtensionsClient::Get()->GetWebstoreBaseURL())) {
       return true;
     }
   }
@@ -483,8 +483,7 @@
       origin_url.SchemeIs(kExtensionScheme) ||
       // Note: The origin of a data: url is empty, so check the url itself.
       document_url.SchemeIs(url::kDataScheme) ||
-      origin.IsSameOriginWith(
-          url::Origin::Create(ExtensionsClient::Get()->GetWebstoreBaseURL()));
+      origin.IsSameOriginWith(ExtensionsClient::Get()->GetWebstoreBaseURL());
 
   if (!allowed_with_active_tab) {
     if (error)
diff --git a/extensions/renderer/api/automation/automation_internal_custom_bindings.cc b/extensions/renderer/api/automation/automation_internal_custom_bindings.cc
index c23b9d79..27dddd0 100644
--- a/extensions/renderer/api/automation/automation_internal_custom_bindings.cc
+++ b/extensions/renderer/api/automation/automation_internal_custom_bindings.cc
@@ -2837,7 +2837,7 @@
   if (!head_pos->AtStartOfParagraph()) {
     ui::AXNodePosition::AXPositionInstance start_para_pos =
         head_pos->CreatePreviousParagraphStartPosition(
-            ui::AXBoundaryBehavior::StopAtLastAnchorBoundary);
+            ui::AXBoundaryBehavior::kStopAtLastAnchorBoundary);
     ui::AXRange<ui::AXPosition<ui::AXNodePosition, ui::AXNode>> pre_range(
         start_para_pos->Clone(), head_pos->Clone());
     pre_str = pre_range.GetText();
@@ -2847,7 +2847,7 @@
   // node to the end of the paragraph.
   ui::AXNodePosition::AXPositionInstance end_para_pos =
       head_pos->CreateNextParagraphEndPosition(
-          ui::AXBoundaryBehavior::StopAtLastAnchorBoundary);
+          ui::AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ui::AXRange<ui::AXPosition<ui::AXNodePosition, ui::AXNode>> post_range(
       head_pos->Clone(), end_para_pos->Clone());
   post_str = post_range.GetText();
diff --git a/extensions/renderer/api/automation/automation_position.cc b/extensions/renderer/api/automation/automation_position.cc
index a704805b..445862f 100644
--- a/extensions/renderer/api/automation/automation_position.cc
+++ b/extensions/renderer/api/automation/automation_position.cc
@@ -273,118 +273,118 @@
 void AutomationPosition::MoveToNextCharacterPosition(
     gin::Arguments* arguments) {
   position_ = position_->CreateNextCharacterPosition(
-      ui::AXBoundaryBehavior::CrossBoundary);
+      ui::AXBoundaryBehavior::kCrossBoundary);
 }
 
 void AutomationPosition::MoveToPreviousCharacterPosition(
     gin::Arguments* arguments) {
   position_ = position_->CreatePreviousCharacterPosition(
-      ui::AXBoundaryBehavior::CrossBoundary);
+      ui::AXBoundaryBehavior::kCrossBoundary);
 }
 
 void AutomationPosition::MoveToNextWordStartPosition(
     gin::Arguments* arguments) {
   position_ = position_->CreateNextWordStartPosition(
-      ui::AXBoundaryBehavior::CrossBoundary);
+      ui::AXBoundaryBehavior::kCrossBoundary);
 }
 
 void AutomationPosition::MoveToPreviousWordStartPosition(
     gin::Arguments* arguments) {
   position_ = position_->CreatePreviousWordStartPosition(
-      ui::AXBoundaryBehavior::CrossBoundary);
+      ui::AXBoundaryBehavior::kCrossBoundary);
 }
 
 void AutomationPosition::MoveToNextWordEndPosition(gin::Arguments* arguments) {
   position_ = position_->CreateNextWordEndPosition(
-      ui::AXBoundaryBehavior::CrossBoundary);
+      ui::AXBoundaryBehavior::kCrossBoundary);
 }
 
 void AutomationPosition::MoveToPreviousWordEndPosition(
     gin::Arguments* arguments) {
   position_ = position_->CreatePreviousWordEndPosition(
-      ui::AXBoundaryBehavior::CrossBoundary);
+      ui::AXBoundaryBehavior::kCrossBoundary);
 }
 
 void AutomationPosition::MoveToNextLineStartPosition(
     gin::Arguments* arguments) {
   position_ = position_->CreateNextLineStartPosition(
-      ui::AXBoundaryBehavior::CrossBoundary);
+      ui::AXBoundaryBehavior::kCrossBoundary);
 }
 
 void AutomationPosition::MoveToPreviousLineStartPosition(
     gin::Arguments* arguments) {
   position_ = position_->CreatePreviousLineStartPosition(
-      ui::AXBoundaryBehavior::CrossBoundary);
+      ui::AXBoundaryBehavior::kCrossBoundary);
 }
 
 void AutomationPosition::MoveToNextLineEndPosition(gin::Arguments* arguments) {
   position_ = position_->CreateNextLineEndPosition(
-      ui::AXBoundaryBehavior::CrossBoundary);
+      ui::AXBoundaryBehavior::kCrossBoundary);
 }
 
 void AutomationPosition::MoveToPreviousLineEndPosition(
     gin::Arguments* arguments) {
   position_ = position_->CreatePreviousLineEndPosition(
-      ui::AXBoundaryBehavior::CrossBoundary);
+      ui::AXBoundaryBehavior::kCrossBoundary);
 }
 
 void AutomationPosition::MoveToPreviousFormatStartPosition(
     gin::Arguments* arguments) {
   position_ = position_->CreatePreviousFormatStartPosition(
-      ui::AXBoundaryBehavior::CrossBoundary);
+      ui::AXBoundaryBehavior::kCrossBoundary);
 }
 
 void AutomationPosition::MoveToNextFormatEndPosition(
     gin::Arguments* arguments) {
   position_ = position_->CreateNextFormatEndPosition(
-      ui::AXBoundaryBehavior::CrossBoundary);
+      ui::AXBoundaryBehavior::kCrossBoundary);
 }
 
 void AutomationPosition::MoveToNextParagraphStartPosition(
     gin::Arguments* arguments) {
   position_ = position_->CreateNextParagraphStartPosition(
-      ui::AXBoundaryBehavior::CrossBoundary);
+      ui::AXBoundaryBehavior::kCrossBoundary);
 }
 
 void AutomationPosition::MoveToPreviousParagraphStartPosition(
     gin::Arguments* arguments) {
   position_ = position_->CreatePreviousParagraphStartPosition(
-      ui::AXBoundaryBehavior::CrossBoundary);
+      ui::AXBoundaryBehavior::kCrossBoundary);
 }
 
 void AutomationPosition::MoveToNextParagraphEndPosition(
     gin::Arguments* arguments) {
   position_ = position_->CreateNextParagraphEndPosition(
-      ui::AXBoundaryBehavior::CrossBoundary);
+      ui::AXBoundaryBehavior::kCrossBoundary);
 }
 
 void AutomationPosition::MoveToPreviousParagraphEndPosition(
     gin::Arguments* arguments) {
   position_ = position_->CreatePreviousParagraphEndPosition(
-      ui::AXBoundaryBehavior::CrossBoundary);
+      ui::AXBoundaryBehavior::kCrossBoundary);
 }
 
 void AutomationPosition::MoveToNextPageStartPosition(
     gin::Arguments* arguments) {
   position_ = position_->CreateNextPageStartPosition(
-      ui::AXBoundaryBehavior::CrossBoundary);
+      ui::AXBoundaryBehavior::kCrossBoundary);
 }
 
 void AutomationPosition::MoveToPreviousPageStartPosition(
     gin::Arguments* arguments) {
   position_ = position_->CreatePreviousPageStartPosition(
-      ui::AXBoundaryBehavior::CrossBoundary);
+      ui::AXBoundaryBehavior::kCrossBoundary);
 }
 
 void AutomationPosition::MoveToNextPageEndPosition(gin::Arguments* arguments) {
   position_ = position_->CreateNextPageEndPosition(
-      ui::AXBoundaryBehavior::CrossBoundary);
+      ui::AXBoundaryBehavior::kCrossBoundary);
 }
 
 void AutomationPosition::MoveToPreviousPageEndPosition(
     gin::Arguments* arguments) {
   position_ = position_->CreatePreviousPageEndPosition(
-      ui::AXBoundaryBehavior::CrossBoundary);
+      ui::AXBoundaryBehavior::kCrossBoundary);
 }
 
 void AutomationPosition::MoveToNextAnchorPosition(gin::Arguments* arguments) {
diff --git a/fuchsia/engine/browser/frame_impl.cc b/fuchsia/engine/browser/frame_impl.cc
index 95d85e19..c0fc746 100644
--- a/fuchsia/engine/browser/frame_impl.cc
+++ b/fuchsia/engine/browser/frame_impl.cc
@@ -835,7 +835,7 @@
 
 void FrameImpl::SetNavigationEventListener(
     fidl::InterfaceHandle<fuchsia::web::NavigationEventListener> listener) {
-  SetNavigationEventListener2(std::move(listener), {});
+  SetNavigationEventListener2(std::move(listener), /*flags=*/{});
 }
 
 void FrameImpl::SetNavigationEventListener2(
diff --git a/fuchsia/engine/browser/frame_impl_browsertest.cc b/fuchsia/engine/browser/frame_impl_browsertest.cc
index da6b835..28d4ddf 100644
--- a/fuchsia/engine/browser/frame_impl_browsertest.cc
+++ b/fuchsia/engine/browser/frame_impl_browsertest.cc
@@ -1162,8 +1162,8 @@
   cr_fuchsia::TestNavigationListener navigation_listener;
   fidl::Binding<fuchsia::web::NavigationEventListener>
       navigation_listener_binding(&navigation_listener);
-  frame.ptr()->SetNavigationEventListener(
-      navigation_listener_binding.NewBinding());
+  frame.ptr()->SetNavigationEventListener2(
+      navigation_listener_binding.NewBinding(), /*flags=*/{});
   navigation_listener.RunUntilUrlAndTitleEquals(page_url, kPage1Title);
 }
 
diff --git a/fuchsia/engine/browser/popup_browsertest.cc b/fuchsia/engine/browser/popup_browsertest.cc
index 8565520..070c2be 100644
--- a/fuchsia/engine/browser/popup_browsertest.cc
+++ b/fuchsia/engine/browser/popup_browsertest.cc
@@ -109,8 +109,8 @@
     popup_listener_.GetAndAckNextPopup(&popup_frame_, &popup_info);
     EXPECT_EQ(popup_info.initial_url(), popup_child_url);
 
-    popup_frame_->SetNavigationEventListener(
-        popup_nav_listener_binding_.NewBinding());
+    popup_frame_->SetNavigationEventListener2(
+        popup_nav_listener_binding_.NewBinding(), /*flags=*/{});
 
     return popup_child_url;
   }
@@ -143,8 +143,8 @@
   EXPECT_EQ(popup_info.initial_url(), popup_child_url);
 
   // Verify that the popup eventually redirects to "title1.html".
-  popup_frame_->SetNavigationEventListener(
-      popup_nav_listener_binding_.NewBinding());
+  popup_frame_->SetNavigationEventListener2(
+      popup_nav_listener_binding_.NewBinding(), /*flags=*/{});
   popup_nav_listener_.RunUntilUrlAndTitleEquals(title1_url, kPage1Title);
 }
 
diff --git a/fuchsia/engine/context_provider_impl_unittest.cc b/fuchsia/engine/context_provider_impl_unittest.cc
index 2d278025..bd1b5f6b 100644
--- a/fuchsia/engine/context_provider_impl_unittest.cc
+++ b/fuchsia/engine/context_provider_impl_unittest.cc
@@ -356,7 +356,8 @@
     CapturingNavigationStateObserver change_listener(run_loop.QuitClosure());
     fidl::Binding<fuchsia::web::NavigationEventListener>
         change_listener_binding(&change_listener);
-    frame_ptr->SetNavigationEventListener(change_listener_binding.NewBinding());
+    frame_ptr->SetNavigationEventListener2(change_listener_binding.NewBinding(),
+                                           /*flags=*/{});
     run_loop.Run();
 
     ASSERT_TRUE(change_listener.captured_state()->has_url());
diff --git a/fuchsia/engine/fake_context.cc b/fuchsia/engine/fake_context.cc
index d777a762..2e154ca0 100644
--- a/fuchsia/engine/fake_context.cc
+++ b/fuchsia/engine/fake_context.cc
@@ -27,6 +27,12 @@
 
 void FakeFrame::SetNavigationEventListener(
     fidl::InterfaceHandle<fuchsia::web::NavigationEventListener> listener) {
+  SetNavigationEventListener2(std::move(listener), /*flags=*/{});
+}
+
+void FakeFrame::SetNavigationEventListener2(
+    fidl::InterfaceHandle<fuchsia::web::NavigationEventListener> listener,
+    fuchsia::web::NavigationEventListenerFlags flags) {
   listener_.Bind(std::move(listener));
   if (on_set_listener_callback_)
     std::move(on_set_listener_callback_).Run();
diff --git a/fuchsia/engine/fake_context.h b/fuchsia/engine/fake_context.h
index d1afc90..ba156c1 100644
--- a/fuchsia/engine/fake_context.h
+++ b/fuchsia/engine/fake_context.h
@@ -44,6 +44,9 @@
   void SetNavigationEventListener(
       fidl::InterfaceHandle<fuchsia::web::NavigationEventListener> listener)
       override;
+  void SetNavigationEventListener2(
+      fidl::InterfaceHandle<fuchsia::web::NavigationEventListener> listener,
+      fuchsia::web::NavigationEventListenerFlags flags) override;
 
   // fuchsia::web::testing::Frame_TestBase implementation.
   void NotImplemented_(const std::string& name) override;
diff --git a/fuchsia/engine/web_engine_integration_test_base.cc b/fuchsia/engine/web_engine_integration_test_base.cc
index cba804c..d11dceb 100644
--- a/fuchsia/engine/web_engine_integration_test_base.cc
+++ b/fuchsia/engine/web_engine_integration_test_base.cc
@@ -200,6 +200,6 @@
   navigation_listener_binding_ =
       std::make_unique<fidl::Binding<fuchsia::web::NavigationEventListener>>(
           navigation_listener_.get());
-  frame_->SetNavigationEventListener(
-      navigation_listener_binding_->NewBinding());
+  frame_->SetNavigationEventListener2(
+      navigation_listener_binding_->NewBinding(), /*flags=*/{});
 }
diff --git a/fuchsia/runners/common/web_component.cc b/fuchsia/runners/common/web_component.cc
index 2a04063..c8e9aaf 100644
--- a/fuchsia/runners/common/web_component.cc
+++ b/fuchsia/runners/common/web_component.cc
@@ -92,7 +92,8 @@
   frame_->SetContentAreaSettings(std::move(settings));
 
   // Observe the Frame for failures, via navigation state change events.
-  frame_->SetNavigationEventListener(navigation_listener_binding_.NewBinding());
+  frame_->SetNavigationEventListener2(navigation_listener_binding_.NewBinding(),
+                                      /*flags=*/{});
 
   if (startup_context()->has_outgoing_directory_request()) {
     // Publish outgoing services and start serving component's outgoing
diff --git a/gin/converter.cc b/gin/converter.cc
index f869522..12d12b87 100644
--- a/gin/converter.cc
+++ b/gin/converter.cc
@@ -7,6 +7,7 @@
 #include <stdint.h>
 
 #include "base/strings/string_util.h"
+#include "base/time/time.h"
 #include "v8/include/v8-array-buffer.h"
 #include "v8/include/v8-external.h"
 #include "v8/include/v8-function.h"
@@ -17,7 +18,6 @@
 #include "v8/include/v8-value.h"
 
 using v8::ArrayBuffer;
-using v8::Boolean;
 using v8::External;
 using v8::Function;
 using v8::Int32;
@@ -48,7 +48,7 @@
 namespace gin {
 
 Local<Value> Converter<bool>::ToV8(Isolate* isolate, bool val) {
-  return Boolean::New(isolate, val).As<Value>();
+  return v8::Boolean::New(isolate, val).As<Value>();
 }
 
 bool Converter<bool>::FromV8(Isolate* isolate, Local<Value> val, bool* out) {
@@ -182,6 +182,12 @@
   return true;
 }
 
+v8::Local<v8::Value> Converter<base::TimeTicks>::ToV8(v8::Isolate* isolate,
+                                                      base::TimeTicks val) {
+  return v8::BigInt::New(isolate, val.since_origin().InMicroseconds())
+      .As<v8::Value>();
+}
+
 Local<Value> Converter<Local<Function>>::ToV8(Isolate* isolate,
                                               Local<Function> val) {
   return val.As<Value>();
diff --git a/gin/converter.h b/gin/converter.h
index 3621dae..7a6392f 100644
--- a/gin/converter.h
+++ b/gin/converter.h
@@ -20,6 +20,10 @@
 #include "v8/include/v8-forward.h"
 #include "v8/include/v8-isolate.h"
 
+namespace base {
+class TimeTicks;
+}
+
 namespace gin {
 
 template<typename KeyType>
@@ -132,6 +136,14 @@
                      std::u16string* out);
 };
 
+// Converter for C++ TimeTicks to Javascript BigInt (unit: microseconds).
+// TimeTicks can't be converted using the existing Converter<int64_t> because
+// the target type will be Number and will lose precision.
+template <>
+struct GIN_EXPORT Converter<base::TimeTicks> {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate, base::TimeTicks val);
+};
+
 template <>
 struct GIN_EXPORT Converter<v8::Local<v8::Function>> {
   static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
diff --git a/gpu/ipc/client/command_buffer_proxy_impl.cc b/gpu/ipc/client/command_buffer_proxy_impl.cc
index d441842..2a3fac8c 100644
--- a/gpu/ipc/client/command_buffer_proxy_impl.cc
+++ b/gpu/ipc/client/command_buffer_proxy_impl.cc
@@ -790,7 +790,10 @@
 void CommandBufferProxyImpl::OnGpuSyncReplyError() {
   CheckLock();
   last_state_.error = gpu::error::kLostContext;
-  last_state_.context_lost_reason = gpu::error::kInvalidGpuMessage;
+  // This error typically happens while waiting for a synchronous
+  // reply from the GPU process because the GPU process crashed.
+  // Report this as a lost GPU channel rather than invalid GPU message.
+  last_state_.context_lost_reason = gpu::error::kGpuChannelLost;
   // This method may be inside a callstack from the GpuControlClient (we got a
   // bad reply to something we are sending to the GPU process). So avoid
   // re-entering the GpuControlClient here.
diff --git a/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_coordinator.mm b/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_coordinator.mm
index 5eb3d76..fa13168 100644
--- a/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_coordinator.mm
+++ b/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_coordinator.mm
@@ -285,11 +285,9 @@
 }
 
 - (void)didTapSecondaryActionButton {
-  [self finishPresentingAndSkipRemainingScreens:NO];
-  if (self.firstRun) {
-    base::UmaHistogramEnumeration(
-        "FirstRun.Stage", first_run::kSignInScreenCompletionWithoutSignIn);
-  }
+  // Cancel sync and sign out the user if needed.
+  [self.mediator cancelSyncAndRestoreSigninState:self.signinStateOnStart
+                           signinIdentityOnStart:self.signinIdentityOnStart];
 }
 
 #pragma mark - IdentityChooserCoordinatorDelegate
@@ -357,6 +355,15 @@
   [self showAdvancedSettings];
 }
 
+- (void)signinSyncMediatorDidSuccessfulyFinishSignout:
+    (SigninSyncMediator*)mediator {
+  [self finishPresentingAndSkipRemainingScreens:NO];
+  if (self.firstRun) {
+    base::UmaHistogramEnumeration(
+        "FirstRun.Stage", first_run::kSignInScreenCompletionWithoutSignIn);
+  }
+}
+
 #pragma mark - Private
 
 // Dismisses the Signed Out modal if it is still present and |skipScreens|.
@@ -473,12 +480,6 @@
 
   [self.advancedSettingsSigninCoordinator stop];
   self.advancedSettingsSigninCoordinator = nil;
-
-  // Should not stay signed in. Only sign-in the user when they selects the
-  // option to or when they are already signed in.
-  [self.mediator
-      cancelSigninWithIdentitySigninState:self.signinStateOnStart
-                    signinIdentityOnStart:self.signinIdentityOnStart];
 }
 
 @end
diff --git a/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_mediator.h b/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_mediator.h
index 16920e7..1cf9af90 100644
--- a/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_mediator.h
+++ b/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_mediator.h
@@ -67,11 +67,10 @@
 // Disconnect the mediator.
 - (void)disconnect;
 
-// Reverts the sign-in operation if needed.
+// Reverts the sign-in and sync operation if needed.
 // @param signinStateOnStart: Browser sign-in state when the coordinator starts.
 // @param signinIdentityOnStart: Sign-in identity when the coordinator starts.
-- (void)
-    cancelSigninWithIdentitySigninState:(IdentitySigninState)signinStateOnStart
+- (void)cancelSyncAndRestoreSigninState:(IdentitySigninState)signinStateOnStart
                   signinIdentityOnStart:(ChromeIdentity*)signinIdentityOnStart;
 
 // Starts the sync engine.
diff --git a/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_mediator.mm b/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_mediator.mm
index aa3f3e8..598e91d 100644
--- a/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_mediator.mm
+++ b/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_mediator.mm
@@ -104,17 +104,20 @@
   _accountManagerServiceObserver.reset();
 }
 
-- (void)
-    cancelSigninWithIdentitySigninState:(IdentitySigninState)signinStateOnStart
+- (void)cancelSyncAndRestoreSigninState:(IdentitySigninState)signinStateOnStart
                   signinIdentityOnStart:(ChromeIdentity*)signinIdentityOnStart {
+  [self.consumer setUIEnabled:NO];
   [self.authenticationFlow cancelAndDismissAnimated:NO];
 
   self.syncService->GetUserSettings()->SetSyncRequested(false);
   switch (signinStateOnStart) {
     case IdentitySigninStateSignedOut: {
-      self.authenticationService->SignOut(signin_metrics::ABORT_SIGNIN,
-                                          /*force_clear_browsing_data=*/false,
-                                          nil);
+      __weak __typeof(self) weakSelf = self;
+      self.authenticationService->SignOut(
+          signin_metrics::ABORT_SIGNIN,
+          /*force_clear_browsing_data=*/false, ^{
+            [weakSelf onSigninStateRestorationCompleted];
+          });
       break;
     }
     case IdentitySigninStateSignedInWithSyncDisabled: {
@@ -124,6 +127,7 @@
               signin::ConsentLevel::kSignin) isEqual:signinIdentityOnStart]) {
         // Can't be synced in this option because sync has to be disabled.
         _syncService->StopAndClear();
+        [self onSigninStateRestorationCompleted];
       } else {
         __weak __typeof(self) weakSelf = self;
         self.authenticationService->SignOut(
@@ -139,6 +143,7 @@
                 // Sign back in with a valid identity.
                 authenticationService->SignIn(identity);
               }
+              [weakSelf onSigninStateRestorationCompleted];
             });
       }
       break;
@@ -303,4 +308,10 @@
       signinSyncMediatorDidSuccessfulyFinishSigninForAdvancedSettings:self];
 }
 
+- (void)onSigninStateRestorationCompleted {
+  // Stop the loading overlay and call back to the coordinator.
+  [self.consumer setUIEnabled:YES];
+  [self.delegate signinSyncMediatorDidSuccessfulyFinishSignout:self];
+}
+
 @end
diff --git a/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_mediator_delegate.h b/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_mediator_delegate.h
index 58b34f3..1148faa 100644
--- a/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_mediator_delegate.h
+++ b/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_mediator_delegate.h
@@ -18,6 +18,11 @@
 - (void)signinSyncMediatorDidSuccessfulyFinishSigninForAdvancedSettings:
     (SigninSyncMediator*)signinSyncMediator;
 
+// Called when revert the sign-in and sync operation if needed did successfully
+// finish.
+- (void)signinSyncMediatorDidSuccessfulyFinishSignout:
+    (SigninSyncMediator*)signinSyncMediator;
+
 @end
 
-#endif  // IOS_CHROME_BROWSER_UI_AUTHENTICATION_SIGNIN_SYNC_SIGNIN_SYNC_MEDIATOR_DELEGATE_H_
\ No newline at end of file
+#endif  // IOS_CHROME_BROWSER_UI_AUTHENTICATION_SIGNIN_SYNC_SIGNIN_SYNC_MEDIATOR_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/first_run/BUILD.gn b/ios/chrome/browser/ui/first_run/BUILD.gn
index 59a2a9ce..67aec53 100644
--- a/ios/chrome/browser/ui/first_run/BUILD.gn
+++ b/ios/chrome/browser/ui/first_run/BUILD.gn
@@ -238,6 +238,7 @@
     "//ios/chrome/common",
     "//ios/chrome/common/ui/promo_style:constants",
     "//ios/chrome/test/earl_grey:eg_test_support+eg2",
+    "//ios/chrome/test/earl_grey:switches",
     "//ios/public/provider/chrome/browser/signin:constants",
     "//ios/public/provider/chrome/browser/signin:fake_chrome_identity",
     "//ios/testing/earl_grey:eg_test_support+eg2",
diff --git a/ios/chrome/browser/ui/first_run/first_run_egtest.mm b/ios/chrome/browser/ui/first_run/first_run_egtest.mm
index 1fb7732e..632536d3 100644
--- a/ios/chrome/browser/ui/first_run/first_run_egtest.mm
+++ b/ios/chrome/browser/ui/first_run/first_run_egtest.mm
@@ -28,6 +28,7 @@
 #import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
 #import "ios/chrome/test/earl_grey/chrome_matchers.h"
 #import "ios/chrome/test/earl_grey/chrome_test_case.h"
+#include "ios/chrome/test/earl_grey/test_switches.h"
 #import "ios/public/provider/chrome/browser/signin/fake_chrome_identity.h"
 #import "ios/public/provider/chrome/browser/signin/fake_chrome_identity_interaction_manager_constants.h"
 #import "ios/testing/earl_grey/app_launch_manager.h"
@@ -836,9 +837,10 @@
   [[self class] removeAnyOpenMenusAndInfoBars];
 }
 
-// Tests that the browser remains signed out when the advanced settings were
-// opened and the sign-in & sync screen was canceled.
-- (void)testTapLinkSyncOff {
+// The browser should only be signed in temporarily while the advanced settings
+// prompt is opened and then signed out when the user selects "No thanks".
+// Sync is also turned off.
+- (void)testAdvancedSettingsSignoutSyncOff {
   FakeChromeIdentity* fakeIdentity = [SigninEarlGrey fakeIdentity1];
   [SigninEarlGrey addFakeIdentity:fakeIdentity];
 
@@ -857,6 +859,8 @@
   GREYAssertFalse([FirstRunAppInterface isSyncFirstSetupComplete],
                   @"Sync shouldn't have finished its original setup yet");
 
+  [self scrollToElementAndAssertVisibility:
+            AdvancedSyncSettingsDoneButtonMatcher()];
   [[EarlGrey selectElementWithMatcher:AdvancedSyncSettingsDoneButtonMatcher()]
       performAction:grey_tap()];
 
@@ -877,6 +881,67 @@
   [[self class] removeAnyOpenMenusAndInfoBars];
 }
 
+// If browser is already signed in and the user opens the advanced settings then
+// selects "No thanks", the user should stay signed in, but sync should be
+// turned off.
+- (void)testAdvancedSettingsSignedInSyncOff {
+  // Sign-in browser.
+  FakeChromeIdentity* fakeIdentity = [SigninEarlGrey fakeIdentity1];
+  [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity enableSync:NO];
+
+  // Reload with forced first run enabled.
+  AppLaunchConfiguration config = self.appConfigurationForTestCase;
+  config.relaunch_policy = ForceRelaunchByCleanShutdown;
+
+  // Add the switch to make sure that fakeIdentity1 is known at startup to avoid
+  // automatic sign out.
+  config.additional_args.push_back(std::string("-") +
+                                   test_switches::kSignInAtStartup);
+
+  [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config];
+
+  // Add account for the identity switcher to be shown.
+  [SigninEarlGrey addFakeIdentity:fakeIdentity];
+
+  [self verifyWelcomeScreenIsDisplayed];
+  [self scrollToElementAndAssertVisibility:GetAcceptButton()];
+  [[EarlGrey selectElementWithMatcher:GetAcceptButton()]
+      performAction:grey_tap()];
+
+  [self verifySignInSyncScreenIsDisplayed];
+  [self scrollToElementAndAssertVisibility:GetSyncSettings()];
+  [[EarlGrey selectElementWithMatcher:GetSyncSettings()]
+      performAction:grey_tap()];
+
+  // Check that Sync hasn't started yet, allowing the user to change some
+  // settings.
+  GREYAssertFalse([FirstRunAppInterface isSyncFirstSetupComplete],
+                  @"Sync shouldn't have finished its original setup yet");
+
+  [self scrollToElementAndAssertVisibility:
+            AdvancedSyncSettingsDoneButtonMatcher()];
+  [[EarlGrey selectElementWithMatcher:AdvancedSyncSettingsDoneButtonMatcher()]
+      performAction:grey_tap()];
+
+  // Check sync did not start yet.
+  GREYAssertFalse([FirstRunAppInterface isSyncFirstSetupComplete],
+                  @"Sync shouldn't start when discarding advanced settings.");
+
+  [self scrollToElementAndAssertVisibility:GetNoThanksButton()];
+  [[EarlGrey selectElementWithMatcher:GetNoThanksButton()]
+      performAction:grey_tap()];
+
+  // Verify that the user is signed in.
+  [SigninEarlGrey verifySignedInWithFakeIdentity:fakeIdentity];
+
+  // Verify that the sync cell is visible and "Off" is displayed.
+  [ChromeEarlGreyUI openSettingsMenu];
+  [SigninEarlGrey verifySyncUIEnabled:NO];
+
+  // Close opened settings for proper tear down.
+  [[self class] removeAnyOpenMenusAndInfoBars];
+}
+
 // Checks that sync is turned on after the user chose to turn on
 // sync in the advanced sync settings screen.
 // TODO(crbug.com/1283229): re-enable the test.
diff --git a/ios/web/navigation/crw_wk_navigation_handler.mm b/ios/web/navigation/crw_wk_navigation_handler.mm
index 95f6cff..0a9dcd8 100644
--- a/ios/web/navigation/crw_wk_navigation_handler.mm
+++ b/ios/web/navigation/crw_wk_navigation_handler.mm
@@ -387,11 +387,9 @@
   BOOL isCrossOriginTargetFrame = NO;
   if (action.sourceFrame && action.targetFrame &&
       action.sourceFrame != action.targetFrame) {
-    url::Origin sourceOrigin = url::Origin::Create(
-        web::GURLOriginWithWKSecurityOrigin(action.sourceFrame.securityOrigin));
-    url::Origin targetOrigin = url::Origin::Create(
+    isCrossOriginTargetFrame = !url::IsSameOriginWith(
+        web::GURLOriginWithWKSecurityOrigin(action.sourceFrame.securityOrigin),
         web::GURLOriginWithWKSecurityOrigin(action.targetFrame.securityOrigin));
-    isCrossOriginTargetFrame = !sourceOrigin.IsSameOriginWith(targetOrigin);
   }
   const web::WebStatePolicyDecider::RequestInfo requestInfo(
       transition, isMainFrameNavigationAction, isCrossOriginTargetFrame,
diff --git a/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java b/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java
index 4dc7cb7..144dda4 100644
--- a/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java
+++ b/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java
@@ -505,7 +505,8 @@
 
     // List of supported HW encoders.
     @IntDef({HWEncoder.QcomVp8, HWEncoder.QcomH264, HWEncoder.ExynosVp8, HWEncoder.ExynosVp9,
-            HWEncoder.ExynosH264, HWEncoder.MediatekH264, HWEncoder.HisiH264})
+            HWEncoder.ExynosH264, HWEncoder.MediatekH264, HWEncoder.HisiH264,
+            HWEncoder.SpreadtrumH264})
     @Retention(RetentionPolicy.SOURCE)
     public @interface HWEncoder {
         int QcomVp8 = 0;
@@ -515,7 +516,8 @@
         int ExynosH264 = 4;
         int MediatekH264 = 5;
         int HisiH264 = 6;
-        int NUM_ENTRIES = 7;
+        int SpreadtrumH264 = 7;
+        int NUM_ENTRIES = 8;
     }
 
     private static String getMimeForHWEncoder(@HWEncoder int decoder) {
@@ -529,6 +531,7 @@
             case HWEncoder.ExynosH264:
             case HWEncoder.MediatekH264:
             case HWEncoder.HisiH264:
+            case HWEncoder.SpreadtrumH264:
                 return MimeTypes.VIDEO_H264;
         }
         return "";
@@ -548,6 +551,8 @@
                 return "mtk";
             case HWEncoder.HisiH264:
                 return "hisi";
+            case HWEncoder.SpreadtrumH264:
+                return "sprd";
         }
         return "";
     }
@@ -565,6 +570,8 @@
                 return Build.VERSION_CODES.O_MR1;
             case HWEncoder.HisiH264:
                 return Build.VERSION_CODES.N;
+            case HWEncoder.SpreadtrumH264:
+                return Build.VERSION_CODES.R;
         }
         return -1;
     }
@@ -579,6 +586,7 @@
             case HWEncoder.ExynosH264:
             case HWEncoder.MediatekH264:
             case HWEncoder.HisiH264:
+            case HWEncoder.SpreadtrumH264:
                 return BitrateAdjuster.Type.FRAMERATE_ADJUSTMENT;
         }
         throw new IllegalArgumentException("Invalid HWEncoder decoder parameter.");
diff --git a/media/filters/fuchsia/fuchsia_video_decoder.cc b/media/filters/fuchsia/fuchsia_video_decoder.cc
index 9669b80..7661dcc 100644
--- a/media/filters/fuchsia/fuchsia_video_decoder.cc
+++ b/media/filters/fuchsia/fuchsia_video_decoder.cc
@@ -617,7 +617,7 @@
   auto weak_this = weak_this_;
 
   for (auto& cb : decode_callbacks_) {
-    std::move(cb).Run(std::move(status));
+    std::move(cb).Run(status);
 
     // DecodeCB may destroy |this|.
     if (!weak_this)
diff --git a/net/dns/dns_config_service.cc b/net/dns/dns_config_service.cc
index 5c7f6a4..69aa66c 100644
--- a/net/dns/dns_config_service.cc
+++ b/net/dns/dns_config_service.cc
@@ -232,7 +232,7 @@
 }
 
 void DnsConfigService::OnCompleteConfig() {
-  timer_.Stop();
+  timer_.AbandonAndStop();
   if (!need_update_)
     return;
   need_update_ = false;
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
index f825524..b272905 100644
--- a/net/http/http_cache_transaction.cc
+++ b/net/http/http_cache_transaction.cc
@@ -3415,9 +3415,8 @@
   // have started and so request_ should exist.
   DCHECK(request_);
   if (request_->possibly_top_frame_origin) {
-    url::Origin request_origin = url::Origin::Create(request_->url);
     is_third_party =
-        !request_origin.IsSameOriginWith(*request_->possibly_top_frame_origin);
+        !request_->possibly_top_frame_origin->IsSameOriginWith(request_->url);
   }
 
   std::string mime_type;
diff --git a/net/url_request/redirect_util.cc b/net/url_request/redirect_util.cc
index a2e14e7b9..6bd87a0 100644
--- a/net/url_request/redirect_util.cc
+++ b/net/url_request/redirect_util.cc
@@ -76,8 +76,7 @@
   //
   // TODO(jww): This is a layering violation and should be refactored somewhere
   // up into //net's embedder. https://crbug.com/471397
-  if (!url::Origin::Create(redirect_info.new_url)
-           .IsSameOriginWith(url::Origin::Create(original_url)) &&
+  if (!url::IsSameOriginWith(redirect_info.new_url, original_url) &&
       request_headers->HasHeader(HttpRequestHeaders::kOrigin)) {
     request_headers->SetHeader(HttpRequestHeaders::kOrigin,
                                url::Origin().Serialize());
diff --git a/net/url_request/url_request_job.cc b/net/url_request/url_request_job.cc
index b9c9503..8cd6a64 100644
--- a/net/url_request/url_request_job.cc
+++ b/net/url_request/url_request_job.cc
@@ -319,8 +319,7 @@
   if (stripped_referrer.spec().size() > 4096)
     should_strip_to_origin = true;
 
-  bool same_origin = url::Origin::Create(original_referrer)
-                         .IsSameOriginWith(url::Origin::Create(destination));
+  bool same_origin = url::IsSameOriginWith(original_referrer, destination);
 
   if (same_origin_out_for_metrics)
     *same_origin_out_for_metrics = same_origin;
diff --git a/sandbox/linux/BUILD.gn b/sandbox/linux/BUILD.gn
index abbcc509..ec24cd81 100644
--- a/sandbox/linux/BUILD.gn
+++ b/sandbox/linux/BUILD.gn
@@ -78,11 +78,11 @@
 
   sources = [
     "services/proc_util_unittest.cc",
-    "services/resource_limits_unittests.cc",
+    "services/resource_limits_unittest.cc",
     "services/scoped_process_unittest.cc",
     "services/syscall_wrappers_unittest.cc",
-    "services/thread_helpers_unittests.cc",
-    "services/yama_unittests.cc",
+    "services/thread_helpers_unittest.cc",
+    "services/yama_unittest.cc",
     "syscall_broker/broker_file_permission_unittest.cc",
     "syscall_broker/broker_process_unittest.cc",
     "syscall_broker/broker_simple_message_unittest.cc",
diff --git a/sandbox/linux/services/resource_limits_unittests.cc b/sandbox/linux/services/resource_limits_unittest.cc
similarity index 100%
rename from sandbox/linux/services/resource_limits_unittests.cc
rename to sandbox/linux/services/resource_limits_unittest.cc
diff --git a/sandbox/linux/services/thread_helpers_unittests.cc b/sandbox/linux/services/thread_helpers_unittest.cc
similarity index 100%
rename from sandbox/linux/services/thread_helpers_unittests.cc
rename to sandbox/linux/services/thread_helpers_unittest.cc
diff --git a/sandbox/linux/services/yama_unittests.cc b/sandbox/linux/services/yama_unittest.cc
similarity index 93%
rename from sandbox/linux/services/yama_unittests.cc
rename to sandbox/linux/services/yama_unittest.cc
index 9f576ab..79038574 100644
--- a/sandbox/linux/services/yama_unittests.cc
+++ b/sandbox/linux/services/yama_unittest.cc
@@ -31,9 +31,9 @@
   bool is_kernel_64bit =
       base::SysInfo::OperatingSystemArchitecture() == "x86_64";
   bool is_linux = base::SysInfo::OperatingSystemName() == "Linux";
-  bool is_3_dot_2 = base::StartsWith(
-      base::SysInfo::OperatingSystemVersion(), "3.2",
-      base::CompareCase::INSENSITIVE_ASCII);
+  bool is_3_dot_2 =
+      base::StartsWith(base::SysInfo::OperatingSystemVersion(), "3.2",
+                       base::CompareCase::INSENSITIVE_ASCII);
   if (is_kernel_64bit && is_linux && is_3_dot_2)
     return true;
 #endif  // defined(__i386__)
@@ -109,10 +109,8 @@
   EXPECT_EQ(static_cast<bool>(status1 & Yama::STATUS_PRESENT),
             Yama::IsPresent());
 
-  fprintf(stdout,
-          "Yama present: %s - enforcing: %s\n",
-          Yama::IsPresent() ? "Y" : "N",
-          Yama::IsEnforcing() ? "Y" : "N");
+  fprintf(stdout, "Yama present: %s - enforcing: %s\n",
+          Yama::IsPresent() ? "Y" : "N", Yama::IsEnforcing() ? "Y" : "N");
 }
 
 SANDBOX_TEST(Yama, RestrictPtraceSucceedsWhenYamaPresent) {
diff --git a/services/network/cors/cors_url_loader.cc b/services/network/cors/cors_url_loader.cc
index d68c333..0a096b3 100644
--- a/services/network/cors/cors_url_loader.cc
+++ b/services/network/cors/cors_url_loader.cc
@@ -180,7 +180,7 @@
 
   if (request_mode == mojom::RequestMode::kNoCors) {
     if (tainted_origin ||
-        (!origin->IsSameOriginWith(url::Origin::Create(url)) &&
+        (!origin->IsSameOriginWith(url) &&
          origin_access_list.CheckAccessState(source_origin, url) !=
              OriginAccessList::AccessState::kAllowed)) {
       return mojom::FetchResponseType::kOpaque;
@@ -212,7 +212,7 @@
   // URL’s origin, then return a network error.
   DCHECK(!IsCorsEnabledRequestMode(request_mode) || origin);
   if (IsCorsEnabledRequestMode(request_mode) && url_has_credentials &&
-      (tainted || !origin->IsSameOriginWith(url::Origin::Create(url)))) {
+      (tainted || !origin->IsSameOriginWith(url))) {
     return CorsErrorStatus(mojom::CorsError::kRedirectContainsCredentials);
   }
 
@@ -557,10 +557,8 @@
   // with `request`’s current url’s origin, then set `request`’s tainted origin
   // flag.
   if (request_.request_initiator &&
-      (!url::Origin::Create(redirect_info.new_url)
-            .IsSameOriginWith(url::Origin::Create(request_.url)) &&
-       !request_.request_initiator->IsSameOriginWith(
-           url::Origin::Create(request_.url)))) {
+      (!url::IsSameOriginWith(redirect_info.new_url, request_.url) &&
+       !request_.request_initiator->IsSameOriginWith(request_.url))) {
     tainted_ = true;
   }
 
diff --git a/services/network/network_service_network_delegate.cc b/services/network/network_service_network_delegate.cc
index 4854cb2..d9b9da7 100644
--- a/services/network/network_service_network_delegate.cc
+++ b/services/network/network_service_network_delegate.cc
@@ -64,10 +64,10 @@
 
   if (base::FeatureList::IsEnabled(
           net::features::kCapReferrerToOriginOnCrossOrigin)) {
-    url::Origin destination_origin = url::Origin::Create(effective_url);
-    url::Origin source_origin = url::Origin::Create(GURL(request->referrer()));
-    if (!destination_origin.IsSameOriginWith(source_origin))
-      request->SetReferrer(source_origin.GetURL().spec());
+    if (!url::IsSameOriginWith(effective_url, GURL(request->referrer()))) {
+      auto capped_referrer = url::Origin::Create(GURL(request->referrer()));
+      request->SetReferrer(capped_referrer.GetURL().spec());
+    }
   }
 }
 
diff --git a/services/network/public/cpp/content_security_policy/content_security_policy.cc b/services/network/public/cpp/content_security_policy/content_security_policy.cc
index fc50bce..30aeb02 100644
--- a/services/network/public/cpp/content_security_policy/content_security_policy.cc
+++ b/services/network/public/cpp/content_security_policy/content_security_policy.cc
@@ -1525,7 +1525,7 @@
     return true;
   }
 
-  if (request_origin.IsSameOriginWith(url::Origin::Create(response_url))) {
+  if (request_origin.IsSameOriginWith(response_url)) {
     required_csp->self_origin = ComputeSelfOrigin(response_url);
     return true;
   }
diff --git a/services/network/public/cpp/corb/corb_impl.cc b/services/network/public/cpp/corb/corb_impl.cc
index 38a9366..ebf406f 100644
--- a/services/network/public/cpp/corb/corb_impl.cc
+++ b/services/network/public/cpp/corb/corb_impl.cc
@@ -695,8 +695,7 @@
   const url::Origin& initiator = request_initiator.value();
 
   // Don't block same-origin documents.
-  url::Origin target_origin = url::Origin::Create(request_url);
-  if (initiator.IsSameOriginWith(target_origin))
+  if (initiator.IsSameOriginWith(request_url))
     return Decision::kAllow;
 
   // Only apply CORB to `no-cors` requests.
diff --git a/services/network/public/cpp/corb/orb_impl.cc b/services/network/public/cpp/corb/orb_impl.cc
index 9c888b6..2e054090 100644
--- a/services/network/public/cpp/corb/orb_impl.cc
+++ b/services/network/public/cpp/corb/orb_impl.cc
@@ -127,8 +127,7 @@
 
   // Same-origin requests are allowed (the spec doesn't explicitly deal with
   // this).
-  url::Origin target_origin = url::Origin::Create(request_url);
-  if (request_initiator->IsSameOriginWith(target_origin))
+  if (request_initiator->IsSameOriginWith(request_url))
     return ResponseHeadersHeuristicForUma::kProcessedBasedOnHeaders;
 
   // Presence of an "X-Content-Type-Options: nosniff" header means that ORB will
diff --git a/services/network/public/cpp/cors/cors.cc b/services/network/public/cpp/cors/cors.cc
index 1279e1bab..d09d4348 100644
--- a/services/network/public/cpp/cors/cors.cc
+++ b/services/network/public/cpp/cors/cors.cc
@@ -260,7 +260,7 @@
   // DCHECK for a while, just in case.
   DCHECK(!request_url.SchemeIs(url::kDataScheme));
 
-  if (request_initiator->IsSameOriginWith(url::Origin::Create(request_url)))
+  if (request_initiator->IsSameOriginWith(request_url))
     return false;
   return true;
 }
diff --git a/services/network/public/cpp/devtools_observer_util.cc b/services/network/public/cpp/devtools_observer_util.cc
index c51e6d8..ad59aa1 100644
--- a/services/network/public/cpp/devtools_observer_util.cc
+++ b/services/network/public/cpp/devtools_observer_util.cc
@@ -26,7 +26,7 @@
       request.method, request.url, request.priority, request.referrer_policy,
       request.trust_token_params ? request.trust_token_params->Clone()
                                  : nullptr,
-      request.has_user_gesture);
+      request.has_user_gesture, request.resource_type);
 }
 
 }  // namespace network
diff --git a/services/network/public/cpp/origin_policy.cc b/services/network/public/cpp/origin_policy.cc
index beca7e2..6163e54 100644
--- a/services/network/public/cpp/origin_policy.cc
+++ b/services/network/public/cpp/origin_policy.cc
@@ -4,10 +4,12 @@
 
 #include "services/network/public/cpp/origin_policy.h"
 
+#include "base/memory/values_equivalent.h"
+
 namespace network {
 bool operator==(const OriginPolicyContentsPtr& a,
                 const OriginPolicyContentsPtr& b) {
-  return (a.get() == b.get()) || (a && b && *a == *b);
+  return base::ValuesEquivalent(a, b);
 }
 
 bool operator!=(const OriginPolicyContentsPtr& a,
diff --git a/services/network/public/cpp/simple_url_loader.cc b/services/network/public/cpp/simple_url_loader.cc
index 4f69404..c93c9907 100644
--- a/services/network/public/cpp/simple_url_loader.cc
+++ b/services/network/public/cpp/simple_url_loader.cc
@@ -1504,7 +1504,7 @@
 
   client_receiver_.reset();
   url_loader_.reset();
-  timeout_timer_.Stop();
+  timeout_timer_.AbandonAndStop();
 
   request_state_->finished = true;
   request_state_->net_error = net_error;
diff --git a/services/network/public/mojom/devtools_observer.mojom b/services/network/public/mojom/devtools_observer.mojom
index e1dbf51..64b219ec 100644
--- a/services/network/public/mojom/devtools_observer.mojom
+++ b/services/network/public/mojom/devtools_observer.mojom
@@ -33,6 +33,7 @@
   URLRequestReferrerPolicy referrer_policy;
   TrustTokenParams? trust_token_params;
   bool has_user_gesture;
+  uint32 resource_type;
 };
 
 // A struct with info about a URLResponseHead that is reported to DevTools.
diff --git a/services/network/restricted_cookie_manager.cc b/services/network/restricted_cookie_manager.cc
index 89dea656..38887f4 100644
--- a/services/network/restricted_cookie_manager.cc
+++ b/services/network/restricted_cookie_manager.cc
@@ -802,7 +802,7 @@
     return false;
   }
 
-  if (origin_.IsSameOriginWith(url::Origin::Create(url)))
+  if (origin_.IsSameOriginWith(url))
     return true;
 
   mojo::ReportBadMessage("Incorrect url origin");
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index f7260ed..8112ae2 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -2534,10 +2534,9 @@
   // [spec]: 4. If request’s origin is same origin with request’s current URL’s
   //            origin and request does not have a redirect-tainted origin, then
   //            return true.
-  url::Origin request_origin = url::Origin::Create(url);
   url::Origin request_initiator =
       url_request_->initiator().value_or(url::Origin());
-  if (request_origin.IsSameOriginWith(request_initiator))
+  if (request_initiator.IsSameOriginWith(url))
     return true;
 
   // [spec]: 5. Return false.
diff --git a/services/network/url_loader_factory.cc b/services/network/url_loader_factory.cc
index c090a14..fba737d5 100644
--- a/services/network/url_loader_factory.cc
+++ b/services/network/url_loader_factory.cc
@@ -143,9 +143,8 @@
                     origin_string != "null";
   absl::optional<url::Origin> request_initiator = url_request.request_initiator;
   if (has_origin && request_initiator.has_value()) {
-    url::Origin origin = url::Origin::Create(GURL(origin_string));
     bool origin_head_same_as_request_origin =
-        request_initiator.value().IsSameOriginWith(origin);
+        request_initiator.value().IsSameOriginWith(GURL(origin_string));
     UMA_HISTOGRAM_BOOLEAN(
         "NetworkService.URLLoaderFactory.OriginHeaderSameAsRequestOrigin",
         origin_head_same_as_request_origin);
diff --git a/storage/browser/file_system/file_system_url.cc b/storage/browser/file_system/file_system_url.cc
index 1c164adb..9d961fc9 100644
--- a/storage/browser/file_system/file_system_url.cc
+++ b/storage/browser/file_system/file_system_url.cc
@@ -69,10 +69,9 @@
   GURL origin_url;
   // URL should be able to be parsed and the parsed origin should match the
   // StorageKey's origin member.
-  is_valid_ =
-      ParseFileSystemSchemeURL(url, &origin_url, &mount_type_,
-                               &virtual_path_) &&
-      storage_key.origin().IsSameOriginWith(url::Origin::Create(origin_url));
+  is_valid_ = ParseFileSystemSchemeURL(url, &origin_url, &mount_type_,
+                                       &virtual_path_) &&
+              storage_key.origin().IsSameOriginWith(origin_url);
   storage_key_ = storage_key;
   path_ = virtual_path_;
   type_ = mount_type_;
diff --git a/testing/buildbot/chrome.json b/testing/buildbot/chrome.json
index f993e7da..62e84201 100644
--- a/testing/buildbot/chrome.json
+++ b/testing/buildbot/chrome.json
@@ -1752,7 +1752,7 @@
       {
         "args": [],
         "cros_board": "atlas",
-        "cros_img": "atlas-release/R99-14450.0.0",
+        "cros_img": "atlas-release/R99-14451.0.0",
         "name": "lacros_all_tast_tests_ATLAS_LKGM",
         "resultdb": {
           "enable": true,
@@ -1812,7 +1812,7 @@
       {
         "args": [],
         "cros_board": "eve",
-        "cros_img": "eve-release/R99-14450.0.0",
+        "cros_img": "eve-release/R99-14451.0.0",
         "name": "lacros_all_tast_tests_EVE_LKGM",
         "resultdb": {
           "enable": true,
@@ -1917,7 +1917,7 @@
       {
         "args": [],
         "cros_board": "kevin",
-        "cros_img": "kevin-release/R99-14450.0.0",
+        "cros_img": "kevin-release/R99-14451.0.0",
         "name": "lacros_all_tast_tests_KEVIN_LKGM",
         "resultdb": {
           "enable": true,
@@ -1932,7 +1932,7 @@
       {
         "args": [],
         "cros_board": "hana",
-        "cros_img": "hana-release/R99-14450.0.0",
+        "cros_img": "hana-release/R99-14451.0.0",
         "name": "lacros_all_tast_tests_HANA_LKGM",
         "resultdb": {
           "enable": true,
@@ -1947,7 +1947,7 @@
       {
         "args": [],
         "cros_board": "kevin",
-        "cros_img": "kevin-release/R99-14450.0.0",
+        "cros_img": "kevin-release/R99-14451.0.0",
         "name": "ozone_unittests_KEVIN_LKGM",
         "resultdb": {
           "enable": true,
@@ -1961,7 +1961,7 @@
       {
         "args": [],
         "cros_board": "hana",
-        "cros_img": "hana-release/R99-14450.0.0",
+        "cros_img": "hana-release/R99-14451.0.0",
         "name": "ozone_unittests_HANA_LKGM",
         "resultdb": {
           "enable": true,
@@ -1975,7 +1975,7 @@
       {
         "args": [],
         "cros_board": "kevin",
-        "cros_img": "kevin-release/R99-14450.0.0",
+        "cros_img": "kevin-release/R99-14451.0.0",
         "name": "viz_unittests_KEVIN_LKGM",
         "resultdb": {
           "enable": true,
@@ -1989,7 +1989,7 @@
       {
         "args": [],
         "cros_board": "hana",
-        "cros_img": "hana-release/R99-14450.0.0",
+        "cros_img": "hana-release/R99-14451.0.0",
         "name": "viz_unittests_HANA_LKGM",
         "resultdb": {
           "enable": true,
diff --git a/testing/buildbot/internal.chromeos.fyi.json b/testing/buildbot/internal.chromeos.fyi.json
index 8fc24da0..4c3ba7b8 100644
--- a/testing/buildbot/internal.chromeos.fyi.json
+++ b/testing/buildbot/internal.chromeos.fyi.json
@@ -1135,7 +1135,7 @@
       {
         "args": [],
         "cros_board": "octopus",
-        "cros_img": "octopus-release/R99-14450.0.0",
+        "cros_img": "octopus-release/R99-14451.0.0",
         "name": "lacros_fyi_tast_tests_OCTOPUS_LKGM",
         "swarming": {},
         "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && !informational)",
@@ -1179,7 +1179,7 @@
       {
         "args": [],
         "cros_board": "octopus",
-        "cros_img": "octopus-release/R99-14450.0.0",
+        "cros_img": "octopus-release/R99-14451.0.0",
         "name": "ozone_unittests_OCTOPUS_LKGM",
         "swarming": {},
         "test": "ozone_unittests",
@@ -1227,7 +1227,7 @@
       {
         "args": [],
         "cros_board": "kevin",
-        "cros_img": "kevin-release/R99-14450.0.0",
+        "cros_img": "kevin-release/R99-14451.0.0",
         "name": "lacros_all_tast_tests_KEVIN_LKGM",
         "swarming": {},
         "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && !informational)",
@@ -1238,7 +1238,7 @@
       {
         "args": [],
         "cros_board": "hana",
-        "cros_img": "hana-release/R99-14450.0.0",
+        "cros_img": "hana-release/R99-14451.0.0",
         "name": "lacros_all_tast_tests_HANA_LKGM",
         "swarming": {},
         "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && !informational)",
@@ -1249,7 +1249,7 @@
       {
         "args": [],
         "cros_board": "kevin",
-        "cros_img": "kevin-release/R99-14450.0.0",
+        "cros_img": "kevin-release/R99-14451.0.0",
         "name": "ozone_unittests_KEVIN_LKGM",
         "swarming": {},
         "test": "ozone_unittests",
@@ -1259,7 +1259,7 @@
       {
         "args": [],
         "cros_board": "hana",
-        "cros_img": "hana-release/R99-14450.0.0",
+        "cros_img": "hana-release/R99-14451.0.0",
         "name": "ozone_unittests_HANA_LKGM",
         "swarming": {},
         "test": "ozone_unittests",
@@ -1269,7 +1269,7 @@
       {
         "args": [],
         "cros_board": "kevin",
-        "cros_img": "kevin-release/R99-14450.0.0",
+        "cros_img": "kevin-release/R99-14451.0.0",
         "name": "viz_unittests_KEVIN_LKGM",
         "swarming": {},
         "test": "viz_unittests",
@@ -1279,7 +1279,7 @@
       {
         "args": [],
         "cros_board": "hana",
-        "cros_img": "hana-release/R99-14450.0.0",
+        "cros_img": "hana-release/R99-14451.0.0",
         "name": "viz_unittests_HANA_LKGM",
         "swarming": {},
         "test": "viz_unittests",
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index f453747..bed6b54 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -563,8 +563,8 @@
   'CROS_ATLAS_LKGM': {
     'skylab': {
       'cros_board': 'atlas',
-      'cros_chrome_version': '99.0.4817.0',
-      'cros_img': 'atlas-release/R99-14450.0.0',
+      'cros_chrome_version': '99.0.4819.0',
+      'cros_img': 'atlas-release/R99-14451.0.0',
     },
     'enabled': True,
     'identifier': 'ATLAS_LKGM',
@@ -599,8 +599,8 @@
   'CROS_EVE_LKGM': {
     'skylab': {
       'cros_board': 'eve',
-      'cros_chrome_version': '99.0.4817.0',
-      'cros_img': 'eve-release/R99-14450.0.0',
+      'cros_chrome_version': '99.0.4819.0',
+      'cros_img': 'eve-release/R99-14451.0.0',
     },
     'enabled': True,
     'identifier': 'EVE_LKGM',
@@ -635,8 +635,8 @@
   'CROS_KEVIN_LKGM': {
     'skylab': {
       'cros_board': 'kevin',
-      'cros_chrome_version': '99.0.4817.0',
-      'cros_img': 'kevin-release/R99-14450.0.0',
+      'cros_chrome_version': '99.0.4819.0',
+      'cros_img': 'kevin-release/R99-14451.0.0',
     },
     'enabled': True,
     'identifier': 'KEVIN_LKGM',
@@ -644,8 +644,8 @@
   'CROS_HANA_LKGM': {
     'skylab': {
       'cros_board': 'hana',
-      'cros_chrome_version': '99.0.4817.0',
-      'cros_img': 'hana-release/R99-14450.0.0',
+      'cros_chrome_version': '99.0.4819.0',
+      'cros_img': 'hana-release/R99-14451.0.0',
     },
     'enabled': True,
     'identifier': 'HANA_LKGM',
@@ -653,8 +653,8 @@
   'CROS_OCTOPUS_LKGM': {
     'skylab': {
       'cros_board': 'octopus',
-      'cros_chrome_version': '99.0.4817.0',
-      'cros_img': 'octopus-release/R99-14450.0.0',
+      'cros_chrome_version': '99.0.4819.0',
+      'cros_img': 'octopus-release/R99-14451.0.0',
     },
     'enabled': True,
     'identifier': 'OCTOPUS_LKGM',
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index a57477ed..3f124e3a 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -83,7 +83,7 @@
 declare_args() {
   # Set to true to enable the clang layout plugin that help you to follow the
   # layout-related restrictions during compilation.
-  use_layout_plugin = false
+  use_layout_plugin = true
 }
 
 # Config for code that builds as part of core.
diff --git a/third_party/blink/renderer/core/layout/layout_box.h b/third_party/blink/renderer/core/layout/layout_box.h
index e940d7e..0ae0b10 100644
--- a/third_party/blink/renderer/core/layout/layout_box.h
+++ b/third_party/blink/renderer/core/layout/layout_box.h
@@ -2212,7 +2212,7 @@
 #if DCHECK_IS_ON()
   void CheckIsVisualOverflowComputed() const;
 #else
-  ALWAYS_INLINE void CheckIsVisualOverflowComputed() const {}
+  ALWAYS_INLINE void CheckIsVisualOverflowComputed() const { NOT_DESTROYED(); }
 #endif
   inline bool VisualOverflowIsSet() const {
     NOT_DESTROYED();
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc
index a61c2fe9..7909d8ae 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc
@@ -56,9 +56,12 @@
   const CSSParserToken* result = range.begin();
   range.Consume();
   // If there is more than 1 dimension token or |spacing| is not a valid
-  // dimension token, return immediately.
-  if (!range.AtEnd() || result->GetType() != kDimensionToken)
+  // dimension token, or unit is not a valid CSS length unit, return
+  // immediately.
+  if (!range.AtEnd() || result->GetType() != kDimensionToken ||
+      !CSSPrimitiveValue::IsLength(result->GetUnitType())) {
     return false;
+  }
   *number_spacing = result->NumericValue();
   *unit = result->GetUnitType();
   return true;
diff --git a/third_party/blink/renderer/modules/subapps/sub_apps.cc b/third_party/blink/renderer/modules/subapps/sub_apps.cc
index 0c92b7cc..7eddcb7 100644
--- a/third_party/blink/renderer/modules/subapps/sub_apps.cc
+++ b/third_party/blink/renderer/modules/subapps/sub_apps.cc
@@ -90,8 +90,7 @@
   }
 
   KURL completed_url = KURL(navigator->DomWindow()->Url(), install_url);
-  if (!url::Origin::Create(navigator->DomWindow()->Url())
-           .IsSameOriginWith(url::Origin::Create(completed_url))) {
+  if (!url::IsSameOriginWith(navigator->DomWindow()->Url(), completed_url)) {
     exception_state.ThrowDOMException(
         DOMExceptionCode::kInvalidStateError,
         "API argument must be a relative path or a fully qualified URL matching"
diff --git a/third_party/blink/renderer/platform/audio/audio_array.h b/third_party/blink/renderer/platform/audio/audio_array.h
index 79b6131..5563ed8 100644
--- a/third_party/blink/renderer/platform/audio/audio_array.h
+++ b/third_party/blink/renderer/platform/audio/audio_array.h
@@ -71,8 +71,9 @@
     const unsigned kAlignment = 16;
 #endif
 
-    if (allocation_)
+    if (allocation_) {
       WTF::Partitions::FastFree(allocation_);
+    }
 
     // Always allocate extra space so that we are guaranteed to get
     // the desired alignment.  Some memory is wasted, but it should be
@@ -108,8 +109,9 @@
   void ZeroRange(unsigned start, unsigned end) {
     bool is_safe = (start <= end) && (end <= size());
     DCHECK(is_safe);
-    if (!is_safe)
+    if (!is_safe) {
       return;
+    }
 
     // This expression cannot overflow because end - start cannot be
     // greater than m_size, which is safe due to the check in Allocate().
@@ -119,8 +121,9 @@
   void CopyToRange(const T* source_data, unsigned start, unsigned end) {
     bool is_safe = (start <= end) && (end <= size());
     DCHECK(is_safe);
-    if (!is_safe)
+    if (!is_safe) {
       return;
+    }
 
     // This expression cannot overflow because end - start cannot be
     // greater than m_size, which is safe due to the check in Allocate().
diff --git a/third_party/blink/renderer/platform/audio/audio_bus.cc b/third_party/blink/renderer/platform/audio/audio_bus.cc
index 7e26b65..9a4d923 100644
--- a/third_party/blink/renderer/platform/audio/audio_bus.cc
+++ b/third_party/blink/renderer/platform/audio/audio_bus.cc
@@ -55,8 +55,9 @@
                                          uint32_t length,
                                          bool allocate) {
   DCHECK_LE(number_of_channels, kMaxBusChannels);
-  if (number_of_channels > kMaxBusChannels)
+  if (number_of_channels > kMaxBusChannels) {
     return nullptr;
+  }
 
   return base::AdoptRef(new AudioBus(number_of_channels, length, allocate));
 }
@@ -88,27 +89,32 @@
 
 void AudioBus::ResizeSmaller(uint32_t new_length) {
   DCHECK_LE(new_length, length_);
-  if (new_length <= length_)
+  if (new_length <= length_) {
     length_ = new_length;
+  }
 
-  for (AudioChannel& channel : channels_)
+  for (AudioChannel& channel : channels_) {
     channel.ResizeSmaller(new_length);
+  }
 }
 
 void AudioBus::Zero() {
-  for (AudioChannel& channel : channels_)
+  for (AudioChannel& channel : channels_) {
     channel.Zero();
+  }
 }
 
 AudioChannel* AudioBus::ChannelByType(unsigned channel_type) {
   // For now we only support canonical channel layouts...
-  if (layout_ != kLayoutCanonical)
+  if (layout_ != kLayoutCanonical) {
     return nullptr;
+  }
 
   switch (NumberOfChannels()) {
     case 1:  // mono
-      if (channel_type == kChannelMono || channel_type == kChannelLeft)
+      if (channel_type == kChannelMono || channel_type == kChannelLeft) {
         return Channel(0);
+      }
       return nullptr;
 
     case 2:  // stereo
@@ -180,12 +186,14 @@
 
 // Returns true if the channel count and frame-size match.
 bool AudioBus::TopologyMatches(const AudioBus& bus) const {
-  if (NumberOfChannels() != bus.NumberOfChannels())
+  if (NumberOfChannels() != bus.NumberOfChannels()) {
     return false;  // channel mismatch
+  }
 
   // Make sure source bus has enough frames.
-  if (length() > bus.length())
+  if (length() > bus.length()) {
     return false;  // frame-size mismatch
+  }
 
   return true;
 }
@@ -201,17 +209,19 @@
   bool is_range_safe =
       start_frame < end_frame && end_frame <= number_of_source_frames;
   DCHECK(is_range_safe);
-  if (!is_range_safe)
+  if (!is_range_safe) {
     return nullptr;
+  }
 
   uint32_t range_length = end_frame - start_frame;
 
   scoped_refptr<AudioBus> audio_bus = Create(number_of_channels, range_length);
   audio_bus->SetSampleRate(source_buffer->SampleRate());
 
-  for (unsigned i = 0; i < number_of_channels; ++i)
+  for (unsigned i = 0; i < number_of_channels; ++i) {
     audio_bus->Channel(i)->CopyFromRange(source_buffer->Channel(i), start_frame,
                                          end_frame);
+  }
 
   return audio_bus;
 }
@@ -228,19 +238,22 @@
 
 void AudioBus::Normalize() {
   float max = MaxAbsValue();
-  if (max)
+  if (max) {
     Scale(1.0f / max);
+  }
 }
 
 void AudioBus::Scale(float scale) {
-  for (unsigned i = 0; i < NumberOfChannels(); ++i)
+  for (unsigned i = 0; i < NumberOfChannels(); ++i) {
     Channel(i)->Scale(scale);
+  }
 }
 
 void AudioBus::CopyFrom(const AudioBus& source_bus,
                         ChannelInterpretation channel_interpretation) {
-  if (&source_bus == this)
+  if (&source_bus == this) {
     return;
+  }
 
   // Copying bus is equivalent to zeroing and then summing.
   Zero();
@@ -249,16 +262,18 @@
 
 void AudioBus::SumFrom(const AudioBus& source_bus,
                        ChannelInterpretation channel_interpretation) {
-  if (&source_bus == this)
+  if (&source_bus == this) {
     return;
+  }
 
   unsigned number_of_source_channels = source_bus.NumberOfChannels();
   unsigned number_of_destination_channels = NumberOfChannels();
 
   // If the channel numbers are equal, perform channels-wise summing.
   if (number_of_source_channels == number_of_destination_channels) {
-    for (unsigned i = 0; i < number_of_source_channels; ++i)
+    for (unsigned i = 0; i < number_of_source_channels; ++i) {
       Channel(i)->SumFrom(source_bus.Channel(i));
+    }
 
     return;
   }
@@ -267,10 +282,11 @@
   // number of channels and the channel interpretation.
   switch (channel_interpretation) {
     case kSpeakers:
-      if (number_of_source_channels < number_of_destination_channels)
+      if (number_of_source_channels < number_of_destination_channels) {
         SumFromByUpMixing(source_bus);
-      else
+      } else {
         SumFromByDownMixing(source_bus);
+      }
       break;
     case kDiscrete:
       DiscreteSumFrom(source_bus);
@@ -284,12 +300,14 @@
 
   if (number_of_destination_channels < number_of_source_channels) {
     // Down-mix by summing channels and dropping the remaining.
-    for (unsigned i = 0; i < number_of_destination_channels; ++i)
+    for (unsigned i = 0; i < number_of_destination_channels; ++i) {
       Channel(i)->SumFrom(source_bus.Channel(i));
+    }
   } else if (number_of_destination_channels > number_of_source_channels) {
     // Up-mix by summing as many channels as we have.
-    for (unsigned i = 0; i < number_of_source_channels; ++i)
+    for (unsigned i = 0; i < number_of_source_channels; ++i) {
       Channel(i)->SumFrom(source_bus.Channel(i));
+    }
   }
 }
 
@@ -497,12 +515,14 @@
 
   unsigned number_of_channels = NumberOfChannels();
   DCHECK_LE(number_of_channels, kMaxBusChannels);
-  if (number_of_channels > kMaxBusChannels)
+  if (number_of_channels > kMaxBusChannels) {
     return;
+  }
 
   // If it is copying from the same bus and no need to change gain, just return.
-  if (this == &source_bus && gain == 1)
+  if (this == &source_bus && gain == 1) {
     return;
+  }
 
   const float* sources[kMaxBusChannels];
   float* destinations[kMaxBusChannels];
@@ -562,8 +582,9 @@
   const float* source = source_bus.Channel(0)->Data();
   for (unsigned channel_index = 0; channel_index < NumberOfChannels();
        ++channel_index) {
-    if (source_bus.NumberOfChannels() == NumberOfChannels())
+    if (source_bus.NumberOfChannels() == NumberOfChannels()) {
       source = source_bus.Channel(channel_index)->Data();
+    }
     float* destination = Channel(channel_index)->MutableData();
     vector_math::Vmul(source, 1, gain_values, 1, destination, 1,
                       number_of_gain_values);
@@ -577,21 +598,24 @@
   // sourceBus's sample-rate must be known.
   DCHECK(source_bus);
   DCHECK(source_bus->SampleRate());
-  if (!source_bus || !source_bus->SampleRate())
+  if (!source_bus || !source_bus->SampleRate()) {
     return nullptr;
+  }
 
   double source_sample_rate = source_bus->SampleRate();
   double destination_sample_rate = new_sample_rate;
   double sample_rate_ratio = source_sample_rate / destination_sample_rate;
   unsigned number_of_source_channels = source_bus->NumberOfChannels();
 
-  if (number_of_source_channels == 1)
+  if (number_of_source_channels == 1) {
     mix_to_mono = false;  // already mono
+  }
 
   if (source_sample_rate == destination_sample_rate) {
     // No sample-rate conversion is necessary.
-    if (mix_to_mono)
+    if (mix_to_mono) {
       return AudioBus::CreateByMixingToMono(source_bus);
+    }
 
     // Return exact copy.
     return AudioBus::CreateBufferFromRange(source_bus, 0, source_bus->length());
@@ -641,8 +665,9 @@
 
 scoped_refptr<AudioBus> AudioBus::CreateByMixingToMono(
     const AudioBus* source_bus) {
-  if (source_bus->IsSilent())
+  if (source_bus->IsSilent()) {
     return Create(1, source_bus->length());
+  }
 
   switch (source_bus->NumberOfChannels()) {
     case 1:
@@ -658,8 +683,9 @@
       float* destination = destination_bus->Channel(0)->MutableData();
 
       // Do the mono mixdown.
-      for (unsigned i = 0; i < n; ++i)
+      for (unsigned i = 0; i < n; ++i) {
         destination[i] = (source_l[i] + source_r[i]) / 2;
+      }
 
       destination_bus->ClearSilentFlag();
       destination_bus->SetSampleRate(source_bus->SampleRate());
@@ -676,22 +702,25 @@
 }
 
 void AudioBus::ClearSilentFlag() {
-  for (AudioChannel& channel : channels_)
+  for (AudioChannel& channel : channels_) {
     channel.ClearSilentFlag();
+  }
 }
 
 scoped_refptr<AudioBus> DecodeAudioFileData(const char* data, size_t size) {
   WebAudioBus web_audio_bus;
-  if (Platform::Current()->DecodeAudioFileData(&web_audio_bus, data, size))
+  if (Platform::Current()->DecodeAudioFileData(&web_audio_bus, data, size)) {
     return web_audio_bus.Release();
+  }
   return nullptr;
 }
 
 scoped_refptr<AudioBus> AudioBus::GetDataResource(int resource_id,
                                                   float sample_rate) {
   const WebData& resource = Platform::Current()->GetDataResource(resource_id);
-  if (resource.IsEmpty())
+  if (resource.IsEmpty()) {
     return nullptr;
+  }
 
   // Currently, the only client of this method is caching the result -- so
   // it's reasonable to (potentially) pay a one-time flat access cost.
@@ -702,12 +731,14 @@
   scoped_refptr<AudioBus> audio_bus =
       DecodeAudioFileData(flat_data.Data(), flat_data.size());
 
-  if (!audio_bus.get())
+  if (!audio_bus.get()) {
     return nullptr;
+  }
 
   // If the bus is already at the requested sample-rate then return as is.
-  if (audio_bus->SampleRate() == sample_rate)
+  if (audio_bus->SampleRate() == sample_rate) {
     return audio_bus;
+  }
 
   return AudioBus::CreateBySampleRateConverting(audio_bus.get(), false,
                                                 sample_rate);
@@ -719,13 +750,15 @@
                                                        float sample_rate) {
   scoped_refptr<AudioBus> audio_bus =
       DecodeAudioFileData(static_cast<const char*>(data), data_size);
-  if (!audio_bus.get())
+  if (!audio_bus.get()) {
     return nullptr;
+  }
 
   // If the bus needs no conversion then return as is.
   if ((!mix_to_mono || audio_bus->NumberOfChannels() == 1) &&
-      audio_bus->SampleRate() == sample_rate)
+      audio_bus->SampleRate() == sample_rate) {
     return audio_bus;
+  }
 
   return AudioBus::CreateBySampleRateConverting(audio_bus.get(), mix_to_mono,
                                                 sample_rate);
diff --git a/third_party/blink/renderer/platform/audio/audio_channel.cc b/third_party/blink/renderer/platform/audio/audio_channel.cc
index e9089a2..4b235d3 100644
--- a/third_party/blink/renderer/platform/audio/audio_channel.cc
+++ b/third_party/blink/renderer/platform/audio/audio_channel.cc
@@ -41,8 +41,9 @@
 }
 
 void AudioChannel::Scale(float scale) {
-  if (IsSilent())
+  if (IsSilent()) {
     return;
+  }
 
   vector_math::Vsmul(Data(), 1, &scale, MutableData(), 1, length());
 }
@@ -67,8 +68,9 @@
   DCHECK_LT(start_frame, end_frame);
   DCHECK_LE(end_frame, source_channel->length());
 
-  if (source_channel->IsSilent() && IsSilent())
+  if (source_channel->IsSilent() && IsSilent()) {
     return;
+  }
 
   // Check that this channel has enough space.
   size_t range_length = end_frame - start_frame;
@@ -80,10 +82,11 @@
   const size_t safe_length =
       base::CheckMul(sizeof(float), range_length).ValueOrDie();
   if (source_channel->IsSilent()) {
-    if (range_length == length())
+    if (range_length == length()) {
       Zero();
-    else
+    } else {
       memset(destination, 0, safe_length);
+    }
   } else {
     memcpy(destination, source + start_frame, safe_length);
   }
@@ -93,8 +96,9 @@
   DCHECK(source_channel);
   DCHECK_GE(source_channel->length(), length());
 
-  if (source_channel->IsSilent())
+  if (source_channel->IsSilent()) {
     return;
+  }
 
   if (IsSilent()) {
     CopyFrom(source_channel);
@@ -105,8 +109,9 @@
 }
 
 float AudioChannel::MaxAbsValue() const {
-  if (IsSilent())
+  if (IsSilent()) {
     return 0;
+  }
 
   float max = 0;
 
diff --git a/third_party/blink/renderer/platform/audio/audio_channel.h b/third_party/blink/renderer/platform/audio/audio_channel.h
index 9cede60..89e4cd1 100644
--- a/third_party/blink/renderer/platform/audio/audio_channel.h
+++ b/third_party/blink/renderer/platform/audio/audio_channel.h
@@ -85,8 +85,9 @@
 
   // Zeroes out all sample values in buffer.
   void Zero() {
-    if (silent_)
+    if (silent_) {
       return;
+    }
 
     silent_ = true;
 
diff --git a/third_party/blink/renderer/platform/audio/audio_delay_dsp_kernel.cc b/third_party/blink/renderer/platform/audio/audio_delay_dsp_kernel.cc
index bb2b674..c1da61832 100644
--- a/third_party/blink/renderer/platform/audio/audio_delay_dsp_kernel.cc
+++ b/third_party/blink/renderer/platform/audio/audio_delay_dsp_kernel.cc
@@ -158,16 +158,18 @@
     double desired_delay_frames = delay_time * sample_rate;
 
     double read_position = w_index + buffer_length - desired_delay_frames;
-    if (read_position >= buffer_length)
+    if (read_position >= buffer_length) {
       read_position -= buffer_length;
+    }
 
     // Linearly interpolate in-between delay times.
     int read_index1 = static_cast<int>(read_position);
     DCHECK_GE(read_index1, 0);
     DCHECK_LT(read_index1, buffer_length);
     int read_index2 = read_index1 + 1;
-    if (read_index2 >= buffer_length)
+    if (read_index2 >= buffer_length) {
       read_index2 -= buffer_length;
+    }
     DCHECK_GE(read_index2, 0);
     DCHECK_LT(read_index2, buffer_length);
 
@@ -177,8 +179,9 @@
     float sample2 = buffer[read_index2];
 
     ++w_index;
-    if (w_index >= buffer_length)
+    if (w_index >= buffer_length) {
       w_index -= buffer_length;
+    }
 
     destination[i] = sample1 + interpolation_factor * (sample2 - sample1);
   }
@@ -251,8 +254,9 @@
   int w_index = write_index_;
   double read_position = w_index + buffer_length - desired_delay_frames;
 
-  if (read_position >= buffer_length)
+  if (read_position >= buffer_length) {
     read_position -= buffer_length;
+  }
 
   // Linearly interpolate in-between delay times.  |read_index1| and
   // |read_index2| are the indices of the frames to be used for
@@ -273,8 +277,9 @@
   CopyToCircularBuffer(buffer, write_index_, buffer_length, source,
                        frames_to_process);
   w_index += frames_to_process;
-  if (w_index >= buffer_length)
+  if (w_index >= buffer_length) {
     w_index -= buffer_length;
+  }
   write_index_ = w_index;
 
   // Now copy out the samples from the buffer, starting at the read pointer,
diff --git a/third_party/blink/renderer/platform/audio/audio_destination.cc b/third_party/blink/renderer/platform/audio/audio_destination.cc
index 0cfcf81..4f07caa 100644
--- a/third_party/blink/renderer/platform/audio/audio_destination.cc
+++ b/third_party/blink/renderer/platform/audio/audio_destination.cc
@@ -209,8 +209,9 @@
 
   // Associate the destination data array with the output bus then fill the
   // FIFO.
-  for (unsigned i = 0; i < number_of_output_channels_; ++i)
+  for (unsigned i = 0; i < number_of_output_channels_; ++i) {
     output_bus_->SetChannelMemory(i, destination_data[i], number_of_frames);
+  }
 
   if (worklet_task_runner_) {
     // Use the dual-thread rendering if the AudioWorklet is activated.
@@ -245,11 +246,13 @@
 
   // The state might be changing by ::Stop() call. If the state is locked, do
   // not touch the below.
-  if (!locker.Locked())
+  if (!locker.Locked()) {
     return;
+  }
 
-  if (device_state_ != DeviceState::kRunning)
+  if (device_state_ != DeviceState::kRunning) {
     return;
+  }
 
   metric_reporter_.BeginTrace();
 
@@ -277,8 +280,9 @@
 
     // Some implementations give only rough estimation of |delay| so
     // we might have negative estimation |outputPosition| value.
-    if (output_position_.position < 0.0)
+    if (output_position_.position < 0.0) {
       output_position_.position = 0.0;
+    }
 
     if (resampler_) {
       resampler_->ResampleInternal(RenderQuantumFrames(), resampler_bus_.get());
@@ -301,8 +305,9 @@
   TRACE_EVENT0("webaudio", "AudioDestination::Start");
   SendLogMessage(String::Format("%s", __func__));
 
-  if (device_state_ != DeviceState::kStopped)
+  if (device_state_ != DeviceState::kStopped) {
     return;
+  }
   web_audio_device_->Start();
   SetDeviceState(DeviceState::kRunning);
 }
@@ -314,8 +319,9 @@
   TRACE_EVENT0("webaudio", "AudioDestination::StartWithWorkletTaskRunner");
   SendLogMessage(String::Format("%s", __func__));
 
-  if (device_state_ != DeviceState::kStopped)
+  if (device_state_ != DeviceState::kStopped) {
     return;
+  }
 
   // The dual-thread rendering kicks off, so updates the earmark frames
   // accordingly.
@@ -331,8 +337,9 @@
   TRACE_EVENT0("webaudio", "AudioDestination::Stop");
   SendLogMessage(String::Format("%s", __func__));
 
-  if (device_state_ == DeviceState::kStopped)
+  if (device_state_ == DeviceState::kStopped) {
     return;
+  }
   web_audio_device_->Stop();
 
   // Resetting |worklet_task_runner_| here is safe because
@@ -348,8 +355,9 @@
   TRACE_EVENT0("webaudio", "AudioDestination::Pause");
   SendLogMessage(String::Format("%s", __func__));
 
-  if (device_state_ != DeviceState::kRunning)
+  if (device_state_ != DeviceState::kRunning) {
     return;
+  }
   web_audio_device_->Pause();
   SetDeviceState(DeviceState::kPaused);
 }
@@ -359,8 +367,9 @@
   TRACE_EVENT0("webaudio", "AudioDestination::Resume");
   SendLogMessage(String::Format("%s", __func__));
 
-  if (device_state_ != DeviceState::kPaused)
+  if (device_state_ != DeviceState::kPaused) {
     return;
+  }
   web_audio_device_->Resume();
   SetDeviceState(DeviceState::kRunning);
 }
diff --git a/third_party/blink/renderer/platform/audio/audio_dsp_kernel_processor.cc b/third_party/blink/renderer/platform/audio/audio_dsp_kernel_processor.cc
index 824c2a2..9753407 100644
--- a/third_party/blink/renderer/platform/audio/audio_dsp_kernel_processor.cc
+++ b/third_party/blink/renderer/platform/audio/audio_dsp_kernel_processor.cc
@@ -43,23 +43,26 @@
       has_just_reset_(true) {}
 
 void AudioDSPKernelProcessor::Initialize() {
-  if (IsInitialized())
+  if (IsInitialized()) {
     return;
+  }
 
   MutexLocker locker(process_lock_);
   DCHECK(!kernels_.size());
 
   // Create processing kernels, one per channel.
-  for (unsigned i = 0; i < NumberOfChannels(); ++i)
+  for (unsigned i = 0; i < NumberOfChannels(); ++i) {
     kernels_.push_back(CreateKernel());
+  }
 
   initialized_ = true;
   has_just_reset_ = true;
 }
 
 void AudioDSPKernelProcessor::Uninitialize() {
-  if (!IsInitialized())
+  if (!IsInitialized()) {
     return;
+  }
 
   MutexLocker locker(process_lock_);
   kernels_.clear();
@@ -83,10 +86,11 @@
     DCHECK_EQ(source->NumberOfChannels(), destination->NumberOfChannels());
     DCHECK_EQ(source->NumberOfChannels(), kernels_.size());
 
-    for (unsigned i = 0; i < kernels_.size(); ++i)
+    for (unsigned i = 0; i < kernels_.size(); ++i) {
       kernels_[i]->Process(source->Channel(i)->Data(),
                            destination->Channel(i)->MutableData(),
                            frames_to_process);
+    }
   } else {
     // Unfortunately, the kernel is being processed by another thread.
     // See also ConvolverNode::process().
@@ -96,24 +100,27 @@
 
 void AudioDSPKernelProcessor::ProcessOnlyAudioParams(
     uint32_t frames_to_process) {
-  if (!IsInitialized())
+  if (!IsInitialized()) {
     return;
+  }
 
   MutexTryLocker try_locker(process_lock_);
   // Only update the AudioParams if we can get the lock.  If not, some
   // other thread is updating the kernels, so we'll have to skip it
   // this time.
   if (try_locker.Locked()) {
-    for (unsigned i = 0; i < kernels_.size(); ++i)
+    for (unsigned i = 0; i < kernels_.size(); ++i) {
       kernels_[i]->ProcessOnlyAudioParams(frames_to_process);
+    }
   }
 }
 
 // Resets filter state
 void AudioDSPKernelProcessor::Reset() {
   DCHECK(IsMainThread());
-  if (!IsInitialized())
+  if (!IsInitialized()) {
     return;
+  }
 
   // Forces snap to parameter values - first time.
   // Any processing depending on this value must set it to false at the
@@ -121,13 +128,15 @@
   has_just_reset_ = true;
 
   MutexLocker locker(process_lock_);
-  for (unsigned i = 0; i < kernels_.size(); ++i)
+  for (unsigned i = 0; i < kernels_.size(); ++i) {
     kernels_[i]->Reset();
+  }
 }
 
 void AudioDSPKernelProcessor::SetNumberOfChannels(unsigned number_of_channels) {
-  if (number_of_channels == number_of_channels_)
+  if (number_of_channels == number_of_channels_) {
     return;
+  }
 
   DCHECK(!IsInitialized());
   number_of_channels_ = number_of_channels;
diff --git a/third_party/blink/renderer/platform/audio/audio_resampler.cc b/third_party/blink/renderer/platform/audio/audio_resampler.cc
index 0af1ab4f..b5a2de7 100644
--- a/third_party/blink/renderer/platform/audio/audio_resampler.cc
+++ b/third_party/blink/renderer/platform/audio/audio_resampler.cc
@@ -38,23 +38,27 @@
 }
 
 AudioResampler::AudioResampler(unsigned number_of_channels) : rate_(1.0) {
-  for (unsigned i = 0; i < number_of_channels; ++i)
+  for (unsigned i = 0; i < number_of_channels; ++i) {
     kernels_.push_back(std::make_unique<AudioResamplerKernel>(this));
+  }
 
   source_bus_ = AudioBus::Create(number_of_channels, 0, false);
 }
 
 void AudioResampler::ConfigureChannels(unsigned number_of_channels) {
   unsigned current_size = kernels_.size();
-  if (number_of_channels == current_size)
+  if (number_of_channels == current_size) {
     return;  // already setup
+  }
 
   // First deal with adding or removing kernels.
   if (number_of_channels > current_size) {
-    for (unsigned i = current_size; i < number_of_channels; ++i)
+    for (unsigned i = current_size; i < number_of_channels; ++i) {
       kernels_.push_back(std::make_unique<AudioResamplerKernel>(this));
-  } else
+    }
+  } else {
     kernels_.resize(number_of_channels);
+  }
 
   // Reconfigure our source bus to the new channel size.
   source_bus_ = AudioBus::Create(number_of_channels, 0, false);
@@ -98,16 +102,18 @@
 }
 
 void AudioResampler::SetRate(double rate) {
-  if (std::isnan(rate) || std::isinf(rate) || rate <= 0.0)
+  if (std::isnan(rate) || std::isinf(rate) || rate <= 0.0) {
     return;
+  }
 
   rate_ = std::min(AudioResampler::kMaxRate, rate);
 }
 
 void AudioResampler::Reset() {
   unsigned number_of_channels = kernels_.size();
-  for (unsigned i = 0; i < number_of_channels; ++i)
+  for (unsigned i = 0; i < number_of_channels; ++i) {
     kernels_[i]->Reset();
+  }
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/audio/audio_resampler_kernel.cc b/third_party/blink/renderer/platform/audio/audio_resampler_kernel.cc
index 505acf4..caad90c 100644
--- a/third_party/blink/renderer/platform/audio/audio_resampler_kernel.cc
+++ b/third_party/blink/renderer/platform/audio/audio_resampler_kernel.cc
@@ -62,8 +62,9 @@
   // We need to fill the buffer up to and including endIndex (so add 1) but
   // we've already buffered m_fillIndex frames from last time.
   unsigned frames_needed = 1 + end_index - fill_index_;
-  if (number_of_source_frames_needed_p)
+  if (number_of_source_frames_needed_p) {
     *number_of_source_frames_needed_p = frames_needed;
+  }
 
   // Do bounds checking for the source buffer.
   DCHECK_LT(fill_index_, source_buffer_.size());
diff --git a/third_party/blink/renderer/platform/audio/biquad.cc b/third_party/blink/renderer/platform/audio/biquad.cc
index effd923..1c3688c3b 100644
--- a/third_party/blink/renderer/platform/audio/biquad.cc
+++ b/third_party/blink/renderer/platform/audio/biquad.cc
@@ -654,8 +654,9 @@
   int iteration;
   for (iteration = 0; iteration < kMaxIterations; ++iteration) {
     root = (f_low * high - f_high * low) / (f_low - f_high);
-    if (fabs(high - low) < kAccuracyThreshold * fabs(high + low))
+    if (fabs(high - low) < kAccuracyThreshold * fabs(high + low)) {
       break;
+    }
     double fr = RepeatedRootResponse(root, c1, c2, r, log_eps);
 
     DCHECK(std::isfinite(fr));
@@ -669,8 +670,9 @@
       // fr and f_low have same sign. Copy root to f_low
       low = root;
       f_low = fr;
-      if (side == 1)
+      if (side == 1) {
         f_high /= 2;
+      }
       side = 1;
     } else {
       // f_low * fr looks like zero, so assume we've converged.
diff --git a/third_party/blink/renderer/platform/audio/cone_effect.cc b/third_party/blink/renderer/platform/audio/cone_effect.cc
index 21bd828..f762e8d0 100644
--- a/third_party/blink/renderer/platform/audio/cone_effect.cc
+++ b/third_party/blink/renderer/platform/audio/cone_effect.cc
@@ -40,8 +40,9 @@
                         gfx::Vector3dF source_orientation,
                         gfx::Point3F listener_position) {
   if (source_orientation.IsZero() ||
-      ((inner_angle_ == 360.0) && (outer_angle_ == 360.0)))
+      ((inner_angle_ == 360.0) && (outer_angle_ == 360.0))) {
     return 1.0;  // no cone specified - unity gain
+  }
 
   // Source-listener vector
   gfx::Vector3dF source_to_listener = listener_position - source_position;
diff --git a/third_party/blink/renderer/platform/audio/distance_effect.cc b/third_party/blink/renderer/platform/audio/distance_effect.cc
index d7f06351..d19d940b 100644
--- a/third_party/blink/renderer/platform/audio/distance_effect.cc
+++ b/third_party/blink/renderer/platform/audio/distance_effect.cc
@@ -61,8 +61,9 @@
   double dmax = std::max(ref_distance_, max_distance_);
   distance = ClampTo(distance, dref, dmax);
 
-  if (dref == dmax)
+  if (dref == dmax) {
     return 1 - rolloff_factor_;
+  }
 
   // We want a gain that decreases linearly from m_refDistance to
   // m_maxDistance. The gain is 1 at m_refDistance.
@@ -71,8 +72,9 @@
 }
 
 double DistanceEffect::InverseGain(double distance) {
-  if (ref_distance_ == 0)
+  if (ref_distance_ == 0) {
     return 0;
+  }
 
   // Clamp distance according to spec
   distance = ClampTo(distance, ref_distance_);
@@ -82,8 +84,9 @@
 }
 
 double DistanceEffect::ExponentialGain(double distance) {
-  if (ref_distance_ == 0)
+  if (ref_distance_ == 0) {
     return 0;
+  }
 
   // Clamp distance according to spec
   distance = ClampTo(distance, ref_distance_);
diff --git a/third_party/blink/renderer/platform/audio/down_sampler.cc b/third_party/blink/renderer/platform/audio/down_sampler.cc
index 41b880f..9befea57 100644
--- a/third_party/blink/renderer/platform/audio/down_sampler.cc
+++ b/third_party/blink/renderer/platform/audio/down_sampler.cc
@@ -113,8 +113,9 @@
   // (destination sample-rate) to match shifting forward in time in
   // m_reducedKernel.
   float* odd_samples_p = temp_buffer_.Data();
-  for (unsigned i = 0; i < dest_frames_to_process; ++i)
+  for (unsigned i = 0; i < dest_frames_to_process; ++i) {
     odd_samples_p[i] = *((input_p - 1) + i * 2);
+  }
 
   // Actually process oddSamplesP with m_reducedKernel for efficiency.
   // The theoretical kernel is double this size with 0 values for even terms
@@ -126,8 +127,9 @@
   // sample-rate), scaled by 0.5.
 
   // Sum into the destination.
-  for (unsigned i = 0; i < dest_frames_to_process; ++i)
+  for (unsigned i = 0; i < dest_frames_to_process; ++i) {
     dest_p[i] += 0.5 * *((input_p - half_size) + i * 2);
+  }
 
   // Copy 2nd half of input buffer to 1st half.
   memcpy(input_buffer_.Data(), input_p,
diff --git a/third_party/blink/renderer/platform/audio/dynamics_compressor.cc b/third_party/blink/renderer/platform/audio/dynamics_compressor.cc
index 8df6c82..08dd7474 100644
--- a/third_party/blink/renderer/platform/audio/dynamics_compressor.cc
+++ b/third_party/blink/renderer/platform/audio/dynamics_compressor.cc
@@ -106,12 +106,13 @@
     case 2:  // stereo
       source_channels_[0] = source_bus->Channel(0)->Data();
 
-      if (number_of_source_channels > 1)
+      if (number_of_source_channels > 1) {
         source_channels_[1] = source_bus->Channel(1)->Data();
-      else
+      } else {
         // Simply duplicate mono channel input data to right channel for stereo
         // processing.
         source_channels_[1] = source_channels_[0];
+      }
 
       break;
     default:
@@ -121,8 +122,9 @@
       return;
   }
 
-  for (unsigned i = 0; i < number_of_channels; ++i)
+  for (unsigned i = 0; i < number_of_channels; ++i) {
     destination_channels_[i] = destination_bus->Channel(i)->MutableData();
+  }
 
   float filter_stage_gain = ParameterValue(kParamFilterStageGain);
   float filter_stage_ratio = ParameterValue(kParamFilterStageRatio);
diff --git a/third_party/blink/renderer/platform/audio/dynamics_compressor_kernel.cc b/third_party/blink/renderer/platform/audio/dynamics_compressor_kernel.cc
index 3331555a..d4160c4 100644
--- a/third_party/blink/renderer/platform/audio/dynamics_compressor_kernel.cc
+++ b/third_party/blink/renderer/platform/audio/dynamics_compressor_kernel.cc
@@ -69,8 +69,9 @@
 
 void DynamicsCompressorKernel::SetNumberOfChannels(
     unsigned number_of_channels) {
-  if (pre_delay_buffers_.size() == number_of_channels)
+  if (pre_delay_buffers_.size() == number_of_channels) {
     return;
+  }
 
   pre_delay_buffers_.clear();
   for (unsigned i = 0; i < number_of_channels; ++i) {
@@ -82,13 +83,15 @@
 void DynamicsCompressorKernel::SetPreDelayTime(float pre_delay_time) {
   // Re-configure look-ahead section pre-delay if delay time has changed.
   unsigned pre_delay_frames = pre_delay_time * SampleRate();
-  if (pre_delay_frames > kMaxPreDelayFrames - 1)
+  if (pre_delay_frames > kMaxPreDelayFrames - 1) {
     pre_delay_frames = kMaxPreDelayFrames - 1;
+  }
 
   if (last_pre_delay_frames_ != pre_delay_frames) {
     last_pre_delay_frames_ = pre_delay_frames;
-    for (unsigned i = 0; i < pre_delay_buffers_.size(); ++i)
+    for (unsigned i = 0; i < pre_delay_buffers_.size(); ++i) {
       pre_delay_buffers_[i]->Zero();
+    }
 
     pre_delay_read_index_ = 0;
     pre_delay_write_index_ = pre_delay_frames;
@@ -100,8 +103,9 @@
 // approaches the value m_linearThreshold + 1 / k.
 float DynamicsCompressorKernel::KneeCurve(float x, float k) const {
   // Linear up to threshold.
-  if (x < linear_threshold_)
+  if (x < linear_threshold_) {
     return x;
+  }
 
   return linear_threshold_ + (1 - static_cast<float>(exp(static_cast<double>(
                                       -k * (x - linear_threshold_))))) /
@@ -112,9 +116,9 @@
 float DynamicsCompressorKernel::Saturate(float x, float k) const {
   float y;
 
-  if (x < knee_threshold_)
+  if (x < knee_threshold_) {
     y = KneeCurve(x, k);
-  else {
+  } else {
     // Constant ratio after knee.
     float x_db = audio_utilities::LinearToDecibels(x);
     float y_db = yknee_threshold_db_ + slope_ * (x_db - knee_threshold_db_);
@@ -129,8 +133,9 @@
 // This slope is equal to the inverse of the compression "ratio".
 // In other words, a compression ratio of 20 would be a slope of 1/20.
 float DynamicsCompressorKernel::SlopeAt(float x, float k) const {
-  if (x < linear_threshold_)
+  if (x < linear_threshold_) {
     return 1;
+  }
 
   float x2 = x * 1.001;
 
@@ -292,10 +297,12 @@
     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
     // Fix gremlins.
-    if (std::isnan(detector_average_))
+    if (std::isnan(detector_average_)) {
       detector_average_ = 1;
-    if (std::isinf(detector_average_))
+    }
+    if (std::isinf(detector_average_)) {
       detector_average_ = 1;
+    }
 
     float desired_gain = detector_average_;
 
@@ -331,10 +338,12 @@
       // Fix gremlins.
       // TODO(rtoy): Replace with a DCHECK so we can figure out how NaN can
       // occur.
-      if (std::isnan(compression_diff_db))
+      if (std::isnan(compression_diff_db)) {
         compression_diff_db = -1;
-      if (std::isinf(compression_diff_db))
+      }
+      if (std::isinf(compression_diff_db)) {
         compression_diff_db = -1;
+      }
 
       // Adaptive release - higher compression (lower compressionDiffDb)
       // releases faster.
@@ -362,16 +371,19 @@
       // Fix gremlins.
       // TODO(rtoy): Replace with a DCHECK so we can figure out how NaN can
       // occur.
-      if (std::isnan(compression_diff_db))
+      if (std::isnan(compression_diff_db)) {
         compression_diff_db = 1;
-      if (std::isinf(compression_diff_db))
+      }
+      if (std::isinf(compression_diff_db)) {
         compression_diff_db = 1;
+      }
 
       // As long as we're still in attack mode, use a rate based off
       // the largest compressionDiffDb we've encountered so far.
       if (max_attack_compression_diff_db_ == -1 ||
-          max_attack_compression_diff_db_ < compression_diff_db)
+          max_attack_compression_diff_db_ < compression_diff_db) {
         max_attack_compression_diff_db_ = compression_diff_db;
+      }
 
       float eff_atten_diff_db = std::max(0.5f, max_attack_compression_diff_db_);
 
@@ -402,8 +414,9 @@
 
           float abs_undelayed_source =
               undelayed_source > 0 ? undelayed_source : -undelayed_source;
-          if (compressor_input < abs_undelayed_source)
+          if (compressor_input < abs_undelayed_source) {
             compressor_input = abs_undelayed_source;
+          }
         }
 
         // Calculate shaped power on undelayed input.
@@ -435,10 +448,12 @@
         detector_average = std::min(1.0f, detector_average);
 
         // Fix gremlins.
-        if (std::isnan(detector_average))
+        if (std::isnan(detector_average)) {
           detector_average = 1;
-        if (std::isinf(detector_average))
+        }
+        if (std::isinf(detector_average)) {
           detector_average = 1;
+        }
 
         // Exponential approach to desired gain.
         if (envelope_rate < 1) {
@@ -462,11 +477,12 @@
 
         // Calculate metering.
         float db_real_gain = 20 * log10(post_warp_compressor_gain);
-        if (db_real_gain < metering_gain_)
+        if (db_real_gain < metering_gain_) {
           metering_gain_ = db_real_gain;
-        else
+        } else {
           metering_gain_ +=
               (db_real_gain - metering_gain_) * metering_release_k_;
+        }
 
         // Apply final gain.
         for (unsigned j = 0; j < number_of_channels; ++j) {
@@ -499,8 +515,9 @@
   metering_gain_ = 1;
 
   // Predelay section.
-  for (unsigned i = 0; i < pre_delay_buffers_.size(); ++i)
+  for (unsigned i = 0; i < pre_delay_buffers_.size(); ++i) {
     pre_delay_buffers_[i]->Zero();
+  }
 
   pre_delay_read_index_ = 0;
   pre_delay_write_index_ = kDefaultPreDelayFrames;
diff --git a/third_party/blink/renderer/platform/audio/equal_power_panner.cc b/third_party/blink/renderer/platform/audio/equal_power_panner.cc
index b038fce..21e8d02 100644
--- a/third_party/blink/renderer/platform/audio/equal_power_panner.cc
+++ b/third_party/blink/renderer/platform/audio/equal_power_panner.cc
@@ -61,18 +61,20 @@
   float* destination_r =
       output_bus->ChannelByType(AudioBus::kChannelRight)->MutableData();
 
-  if (!source_l || !source_r || !destination_l || !destination_r)
+  if (!source_l || !source_r || !destination_l || !destination_r) {
     return;
+  }
 
   // Clamp azimuth to allowed range of -180 -> +180.
   azimuth = ClampTo(azimuth, -180.0, 180.0);
 
   // Alias the azimuth ranges behind us to in front of us:
   // -90 -> -180 to -90 -> 0 and 90 -> 180 to 90 -> 0
-  if (azimuth < -90)
+  if (azimuth < -90) {
     azimuth = -180 - azimuth;
-  else if (azimuth > 90)
+  } else if (azimuth > 90) {
     azimuth = 180 - azimuth;
+  }
 
   double desired_pan_position;
   double desired_gain_l;
@@ -140,10 +142,11 @@
 
   // Alias the azimuth ranges behind us to in front of us:
   // -90 -> -180 to -90 -> 0 and 90 -> 180 to 90 -> 0
-  if (azimuth < -90)
+  if (azimuth < -90) {
     azimuth = -180 - azimuth;
-  else if (azimuth > 90)
+  } else if (azimuth > 90) {
     azimuth = 180 - azimuth;
+  }
 
   double desired_pan_position;
 
diff --git a/third_party/blink/renderer/platform/audio/fft_frame.cc b/third_party/blink/renderer/platform/audio/fft_frame.cc
index c74cbb8..1956f96 100644
--- a/third_party/blink/renderer/platform/audio/fft_frame.cc
+++ b/third_party/blink/renderer/platform/audio/fft_frame.cc
@@ -159,14 +159,18 @@
     last_phase2 = phase2;
 
     // Unwrap phase deltas
-    if (delta_phase1 > kPiDouble)
+    if (delta_phase1 > kPiDouble) {
       delta_phase1 -= kTwoPiDouble;
-    if (delta_phase1 < -kPiDouble)
+    }
+    if (delta_phase1 < -kPiDouble) {
       delta_phase1 += kTwoPiDouble;
-    if (delta_phase2 > kPiDouble)
+    }
+    if (delta_phase2 > kPiDouble) {
       delta_phase2 -= kTwoPiDouble;
-    if (delta_phase2 < -kPiDouble)
+    }
+    if (delta_phase2 < -kPiDouble) {
       delta_phase2 += kTwoPiDouble;
+    }
 
     // Blend group-delays
     double delta_phase_blend;
@@ -184,10 +188,12 @@
     phase_accum += delta_phase_blend;
 
     // Unwrap
-    if (phase_accum > kPiDouble)
+    if (phase_accum > kPiDouble) {
       phase_accum -= kTwoPiDouble;
-    if (phase_accum < -kPiDouble)
+    }
+    if (phase_accum < -kPiDouble) {
       phase_accum += kTwoPiDouble;
+    }
 
     std::complex<double> c = std::polar(mag, phase_accum);
 
@@ -219,10 +225,12 @@
     last_phase = phase;
 
     // Unwrap
-    if (delta_phase < -kPiDouble)
+    if (delta_phase < -kPiDouble) {
       delta_phase += kTwoPiDouble;
-    if (delta_phase > kPiDouble)
+    }
+    if (delta_phase > kPiDouble) {
       delta_phase -= kTwoPiDouble;
+    }
 
     ave_sum += mag * delta_phase;
     weight_sum += mag;
@@ -234,8 +242,9 @@
   double ave_sample_delay = -ave / sample_phase_delay;
 
   // Leave 20 sample headroom (for leading edge of impulse)
-  if (ave_sample_delay > 20.0)
+  if (ave_sample_delay > 20.0) {
     ave_sample_delay -= 20.0;
+  }
 
   // Remove average group delay (minus 20 samples for headroom)
   AddConstantGroupDelay(-ave_sample_delay);
diff --git a/third_party/blink/renderer/platform/audio/hrtf_database.cc b/third_party/blink/renderer/platform/audio/hrtf_database.cc
index 9e8d299..302e1c9 100644
--- a/third_party/blink/renderer/platform/audio/hrtf_database.cc
+++ b/third_party/blink/renderer/platform/audio/hrtf_database.cc
@@ -65,8 +65,9 @@
     for (unsigned i = 0; i < kNumberOfTotalElevations;
          i += kInterpolationFactor) {
       unsigned j = (i + kInterpolationFactor);
-      if (j >= kNumberOfTotalElevations)
+      if (j >= kNumberOfTotalElevations) {
         j = i;  // for last elevation interpolate with itself
+      }
 
       // Create the interpolated convolution kernels and delays.
       for (unsigned jj = 1; jj < kInterpolationFactor; ++jj) {
@@ -91,8 +92,9 @@
   SECURITY_DCHECK(elevation_index < elevations_.size());
   SECURITY_DCHECK(elevations_.size() > 0);
 
-  if (elevation_index > elevations_.size() - 1)
+  if (elevation_index > elevations_.size() - 1) {
     elevation_index = elevations_.size() - 1;
+  }
 
   HRTFElevation* hrtf_elevation = elevations_[elevation_index].get();
   DCHECK(hrtf_elevation);
diff --git a/third_party/blink/renderer/platform/audio/hrtf_database_loader.cc b/third_party/blink/renderer/platform/audio/hrtf_database_loader.cc
index c62c486..e6f3c0f 100644
--- a/third_party/blink/renderer/platform/audio/hrtf_database_loader.cc
+++ b/third_party/blink/renderer/platform/audio/hrtf_database_loader.cc
@@ -113,8 +113,9 @@
   // It's ok to return nullptr if we can't get the lock.
   MutexTryLocker try_locker(lock_);
 
-  if (!try_locker.Locked())
+  if (!try_locker.Locked()) {
     return nullptr;
+  }
 
   return hrtf_database_.get();
 }
@@ -130,8 +131,9 @@
   // the offline audio rendering thread.
   MutexLocker locker(lock_);
 
-  if (!thread_)
+  if (!thread_) {
     return;
+  }
 
   base::WaitableEvent sync;
   // TODO(alexclarke): Should this be posted as a loading task?
diff --git a/third_party/blink/renderer/platform/audio/hrtf_elevation.cc b/third_party/blink/renderer/platform/audio/hrtf_elevation.cc
index 9859e53c..d93239c4 100644
--- a/third_party/blink/renderer/platform/audio/hrtf_elevation.cc
+++ b/third_party/blink/renderer/platform/audio/hrtf_elevation.cc
@@ -83,8 +83,9 @@
 
     bus = concatenated_impulse_responses;
     audio_bus_map.Set(subject_resource_id, bus);
-  } else
+  } else {
     bus = iterator->value;
+  }
 
   size_t response_length = bus->length();
   size_t expected_length =
@@ -120,8 +121,9 @@
   scoped_refptr<AudioBus> bus(
       GetConcatenatedImpulseResponsesForSubject(subject_resource_id));
 
-  if (!bus)
+  if (!bus) {
     return false;
+  }
 
   // Just sequentially search the table to find the correct index.
   int elevation_index = -1;
@@ -245,8 +247,9 @@
         raw_index * kAzimuthSpacing, actual_elevation, sample_rate,
         subject_resource_id, kernel_list_l->at(interpolated_index),
         kernel_list_r->at(interpolated_index));
-    if (!success)
+    if (!success) {
       return nullptr;
+    }
 
     interpolated_index += kInterpolationFactor;
   }
diff --git a/third_party/blink/renderer/platform/audio/hrtf_panner.cc b/third_party/blink/renderer/platform/audio/hrtf_panner.cc
index b5b194e..970c1ff 100644
--- a/third_party/blink/renderer/platform/audio/hrtf_panner.cc
+++ b/third_party/blink/renderer/platform/audio/hrtf_panner.cc
@@ -114,8 +114,9 @@
                                                      double& azimuth_blend) {
   // Convert the azimuth angle from the range -180 -> +180 into the range 0 ->
   // 360.  The azimuth index may then be calculated from this positive value.
-  if (azimuth < 0)
+  if (azimuth < 0) {
     azimuth += 360.0;
+  }
 
   int number_of_azimuths = HRTFDatabase::NumberOfAzimuths();
   const double angle_between_azimuths = 360.0 / number_of_azimuths;
diff --git a/third_party/blink/renderer/platform/audio/iir_filter.cc b/third_party/blink/renderer/platform/audio/iir_filter.cc
index 44aafaf..dc3f15d 100644
--- a/third_party/blink/renderer/platform/audio/iir_filter.cc
+++ b/third_party/blink/renderer/platform/audio/iir_filter.cc
@@ -44,8 +44,9 @@
   // 0, order);
   std::complex<double> result = 0;
 
-  for (int k = order; k >= 0; --k)
+  for (int k = order; k >= 0; --k) {
     result = result * z + std::complex<double>(coef[k]);
+  }
 
   return result;
 }
@@ -93,12 +94,14 @@
     }
 
     // Handle any remaining feedforward or feedback terms.
-    for (int k = min_length; k < feedforward_length; ++k)
+    for (int k = min_length; k < feedforward_length; ++k) {
       yn +=
           feedforward[k] * x_buffer[(buffer_index_ - k) & (kBufferLength - 1)];
+    }
 
-    for (int k = min_length; k < feedback_length; ++k)
+    for (int k = min_length; k < feedback_length; ++k) {
       yn -= feedback[k] * y_buffer[(buffer_index_ - k) & (kBufferLength - 1)];
+    }
 
     // Save the current input and output values in the memory buffers for the
     // next output.
diff --git a/third_party/blink/renderer/platform/audio/push_pull_fifo.cc b/third_party/blink/renderer/platform/audio/push_pull_fifo.cc
index eb029773..a6b85aa 100644
--- a/third_party/blink/renderer/platform/audio/push_pull_fifo.cc
+++ b/third_party/blink/renderer/platform/audio/push_pull_fifo.cc
@@ -33,8 +33,9 @@
 
 PushPullFIFO::~PushPullFIFO() {
   // Capture metrics only after the FIFO is actually pulled.
-  if (pull_count_ == 0)
+  if (pull_count_ == 0) {
     return;
+  }
 
   // TODO(hongchan): The fast-shutdown process prevents the data below from
   // being collected correctly. Consider using "outside metric collector" that
diff --git a/third_party/blink/renderer/platform/audio/reverb.cc b/third_party/blink/renderer/platform/audio/reverb.cc
index 4b71e8e..ba8fb9fb 100644
--- a/third_party/blink/renderer/platform/audio/reverb.cc
+++ b/third_party/blink/renderer/platform/audio/reverb.cc
@@ -68,8 +68,9 @@
   power = sqrt(power / (number_of_channels * length));
 
   // Protect against accidental overload
-  if (std::isinf(power) || std::isnan(power) || power < kMinPower)
+  if (std::isinf(power) || std::isnan(power) || power < kMinPower) {
     power = kMinPower;
+  }
 
   float scale = 1 / power;
 
@@ -78,12 +79,14 @@
               0.05f);  // calibrate to make perceived volume same as unprocessed
 
   // Scale depends on sample-rate.
-  if (response->SampleRate())
+  if (response->SampleRate()) {
     scale *= kGainCalibrationSampleRate / response->SampleRate();
+  }
 
   // True-stereo compensation
-  if (response->NumberOfChannels() == 4)
+  if (response->NumberOfChannels() == 4) {
     scale *= 0.5f;
+  }
 
   return scale;
 }
@@ -133,8 +136,9 @@
   // For "True" stereo processing we allocate a temporary buffer to avoid
   // repeatedly allocating it in the process() method.  It can be bad to
   // allocate memory in a real-time thread.
-  if (number_of_response_channels_ == 4)
+  if (number_of_response_channels_ == 4) {
     temp_buffer_ = AudioBus::Create(2, render_slice_size);
+  }
 }
 
 void Reverb::Process(const AudioBus* source_bus,
@@ -269,8 +273,9 @@
 }
 
 void Reverb::Reset() {
-  for (wtf_size_t i = 0; i < convolvers_.size(); ++i)
+  for (wtf_size_t i = 0; i < convolvers_.size(); ++i) {
     convolvers_[i]->Reset();
+  }
 }
 
 size_t Reverb::LatencyFrames() const {
diff --git a/third_party/blink/renderer/platform/audio/reverb_convolver.cc b/third_party/blink/renderer/platform/audio/reverb_convolver.cc
index 4807fbb..77df6038 100644
--- a/third_party/blink/renderer/platform/audio/reverb_convolver.cc
+++ b/third_party/blink/renderer/platform/audio/reverb_convolver.cc
@@ -95,8 +95,9 @@
     // For the last stage, it's possible that stageOffset is such that we're
     // straddling the end of the impulse response buffer (if we use stageSize),
     // so reduce the last stage's length...
-    if (stage_size + stage_offset > total_response_length)
+    if (stage_size + stage_offset > total_response_length) {
       stage_size = total_response_length - stage_offset;
+    }
 
     // This "staggers" the time when each FFT happens so they don't all happen
     // at the same time
@@ -128,10 +129,12 @@
     }
 
     if (use_background_threads && !is_background_stage &&
-        fft_size > max_realtime_fft_size_)
+        fft_size > max_realtime_fft_size_) {
       fft_size = max_realtime_fft_size_;
-    if (fft_size > max_fft_size_)
+    }
+    if (fft_size > max_fft_size_) {
       fft_size = max_fft_size_;
+    }
   }
 
   // Start up background thread
@@ -163,8 +166,9 @@
     const int kSliceSize = kMinFFTSize / 2;
 
     // Accumulate contributions from each stage
-    for (wtf_size_t i = 0; i < background_stages_.size(); ++i)
+    for (wtf_size_t i = 0; i < background_stages_.size(); ++i) {
       background_stages_[i]->ProcessInBackground(this, kSliceSize);
+    }
   }
 }
 
@@ -185,8 +189,9 @@
   input_buffer_.Write(source, frames_to_process);
 
   // Accumulate contributions from each stage
-  for (wtf_size_t i = 0; i < stages_.size(); ++i)
+  for (wtf_size_t i = 0; i < stages_.size(); ++i) {
     stages_[i]->Process(source, frames_to_process);
+  }
 
   // Finally read from accumulation buffer
   accumulation_buffer_.ReadAndClear(destination, frames_to_process);
@@ -202,11 +207,13 @@
 }
 
 void ReverbConvolver::Reset() {
-  for (wtf_size_t i = 0; i < stages_.size(); ++i)
+  for (wtf_size_t i = 0; i < stages_.size(); ++i) {
     stages_[i]->Reset();
+  }
 
-  for (wtf_size_t i = 0; i < background_stages_.size(); ++i)
+  for (wtf_size_t i = 0; i < background_stages_.size(); ++i) {
     background_stages_[i]->Reset();
+  }
 
   accumulation_buffer_.Reset();
   input_buffer_.Reset();
diff --git a/third_party/blink/renderer/platform/audio/reverb_convolver_stage.cc b/third_party/blink/renderer/platform/audio/reverb_convolver_stage.cc
index bfe8bcf2..14e491b3 100644
--- a/third_party/blink/renderer/platform/audio/reverb_convolver_stage.cc
+++ b/third_party/blink/renderer/platform/audio/reverb_convolver_stage.cc
@@ -94,8 +94,9 @@
   size_t half_size = fft_size / 2;
   if (!direct_mode_) {
     DCHECK_GE(total_delay, half_size);
-    if (total_delay >= half_size)
+    if (total_delay >= half_size) {
       total_delay -= half_size;
+    }
   }
 
   // We divide up the total delay, into pre and post delay sections so that we
@@ -104,8 +105,9 @@
   // same time...
   size_t max_pre_delay_length = std::min(half_size, total_delay);
   pre_delay_length_ = total_delay > 0 ? render_phase % max_pre_delay_length : 0;
-  if (pre_delay_length_ > total_delay)
+  if (pre_delay_length_ > total_delay) {
     pre_delay_length_ = 0;
+  }
 
   post_delay_length_ = total_delay - pre_delay_length_;
   pre_read_write_index_ = 0;
@@ -129,8 +131,9 @@
 void ReverbConvolverStage::Process(const float* source,
                                    uint32_t frames_to_process) {
   DCHECK(source);
-  if (!source)
+  if (!source) {
     return;
+  }
 
   // Deal with pre-delay stream : note special handling of zero delay.
 
@@ -144,8 +147,9 @@
     bool is_pre_delay_safe =
         pre_read_write_index_ + frames_to_process <= pre_delay_buffer_.size();
     DCHECK(is_pre_delay_safe);
-    if (!is_pre_delay_safe)
+    if (!is_pre_delay_safe) {
       return;
+    }
 
     is_temporary_buffer_safe = frames_to_process <= temporary_buffer_.size();
 
@@ -162,8 +166,9 @@
   }
 
   DCHECK(is_temporary_buffer_safe);
-  if (!is_temporary_buffer_safe)
+  if (!is_temporary_buffer_safe) {
     return;
+  }
 
   if (frames_processed_ < pre_delay_length_) {
     // For the first m_preDelayLength frames don't process the convolver,
@@ -175,12 +180,13 @@
     // Now, run the convolution (into the delay buffer).
     // An expensive FFT will happen every fftSize / 2 frames.
     // We process in-place here...
-    if (!direct_mode_)
+    if (!direct_mode_) {
       fft_convolver_->Process(fft_kernel_.get(), pre_delayed_source,
                               temporary_buffer, frames_to_process);
-    else
+    } else {
       direct_convolver_->Process(pre_delayed_source, temporary_buffer,
                                  frames_to_process);
+    }
 
     // Now accumulate into reverb's accumulation buffer.
     accumulation_buffer_->Accumulate(temporary_buffer, frames_to_process,
@@ -194,18 +200,20 @@
     pre_read_write_index_ += frames_to_process;
 
     DCHECK_LE(pre_read_write_index_, pre_delay_length_);
-    if (pre_read_write_index_ >= pre_delay_length_)
+    if (pre_read_write_index_ >= pre_delay_length_) {
       pre_read_write_index_ = 0;
+    }
   }
 
   frames_processed_ += frames_to_process;
 }
 
 void ReverbConvolverStage::Reset() {
-  if (!direct_mode_)
+  if (!direct_mode_) {
     fft_convolver_->Reset();
-  else
+  } else {
     direct_convolver_->Reset();
+  }
   pre_delay_buffer_.Zero();
   accumulation_read_index_ = 0;
   input_read_index_ = 0;
diff --git a/third_party/blink/renderer/platform/audio/reverb_input_buffer.cc b/third_party/blink/renderer/platform/audio/reverb_input_buffer.cc
index 3fc585a..40cd32d2 100644
--- a/third_party/blink/renderer/platform/audio/reverb_input_buffer.cc
+++ b/third_party/blink/renderer/platform/audio/reverb_input_buffer.cc
@@ -42,8 +42,9 @@
 
   memcpy(buffer_.Data() + index, source_p, sizeof(float) * number_of_frames);
 
-  if (new_index >= buffer_length)
+  if (new_index >= buffer_length) {
     new_index = 0;
+  }
 
   SetWriteIndex(new_index);
 }
diff --git a/third_party/blink/renderer/platform/audio/sinc_resampler.cc b/third_party/blink/renderer/platform/audio/sinc_resampler.cc
index a84673f..b822e2da 100644
--- a/third_party/blink/renderer/platform/audio/sinc_resampler.cc
+++ b/third_party/blink/renderer/platform/audio/sinc_resampler.cc
@@ -161,8 +161,9 @@
   void ProvideInput(AudioBus* bus, int frames_to_process) override {
     DCHECK(source_);
     DCHECK(bus);
-    if (!source_ || !bus)
+    if (!source_ || !bus) {
       return;
+    }
 
     float* buffer = bus->Channel(0)->MutableData();
 
@@ -171,9 +172,10 @@
     memcpy(buffer, source_, sizeof(float) * frames_to_copy);
 
     // Zero-pad if necessary.
-    if (frames_to_copy < frames_to_process)
+    if (frames_to_copy < frames_to_process) {
       memset(buffer + frames_to_copy, 0,
              sizeof(float) * (frames_to_process - frames_to_copy));
+    }
 
     source_frames_available_ -= frames_to_copy;
     source_ += frames_to_copy;
@@ -474,8 +476,9 @@
       virtual_source_index_ += scale_factor_;
 
       --number_of_destination_frames;
-      if (!number_of_destination_frames)
+      if (!number_of_destination_frames) {
         return;
+      }
     }
 
     // Wrap back around to the start.
diff --git a/third_party/blink/renderer/platform/audio/stereo_panner.cc b/third_party/blink/renderer/platform/audio/stereo_panner.cc
index b1e7fed..223e24d 100644
--- a/third_party/blink/renderer/platform/audio/stereo_panner.cc
+++ b/third_party/blink/renderer/platform/audio/stereo_panner.cc
@@ -43,8 +43,9 @@
   float* destination_r =
       output_bus->ChannelByType(AudioBus::kChannelRight)->MutableData();
 
-  if (!source_l || !source_r || !destination_l || !destination_r)
+  if (!source_l || !source_r || !destination_l || !destination_r) {
     return;
+  }
 
   double gain_l, gain_r, pan_radian;
 
@@ -104,8 +105,9 @@
   float* destination_r =
       output_bus->ChannelByType(AudioBus::kChannelRight)->MutableData();
 
-  if (!source_l || !source_r || !destination_l || !destination_r)
+  if (!source_l || !source_r || !destination_l || !destination_r) {
     return;
+  }
 
   float target_pan = ClampTo(pan_value, -1.0, 1.0);
 
diff --git a/third_party/blink/renderer/platform/audio/up_sampler.cc b/third_party/blink/renderer/platform/audio/up_sampler.cc
index dba347182..bfa0366 100644
--- a/third_party/blink/renderer/platform/audio/up_sampler.cc
+++ b/third_party/blink/renderer/platform/audio/up_sampler.cc
@@ -116,8 +116,9 @@
 
   // Copy even sample-frames 0,2,4,6... (delayed by the linear phase delay)
   // directly into destP.
-  for (unsigned i = 0; i < source_frames_to_process; ++i)
+  for (unsigned i = 0; i < source_frames_to_process; ++i) {
     dest_p[i * 2] = *((input_p - half_size) + i);
+  }
 
   // Compute odd sample-frames 1,3,5,7...
   float* odd_samples_p = temp_buffer_.Data();
@@ -129,8 +130,9 @@
                                    source_frames_to_process);
   }
 
-  for (unsigned i = 0; i < source_frames_to_process; ++i)
+  for (unsigned i = 0; i < source_frames_to_process; ++i) {
     dest_p[i * 2 + 1] = odd_samples_p[i];
+  }
 
   // Copy 2nd half of input buffer to 1st half.
   memcpy(input_buffer_.Data(), input_p,
diff --git a/third_party/blink/renderer/platform/audio/vector_math.cc b/third_party/blink/renderer/platform/audio/vector_math.cc
index e4200618..f90bb4a 100644
--- a/third_party/blink/renderer/platform/audio/vector_math.cc
+++ b/third_party/blink/renderer/platform/audio/vector_math.cc
@@ -129,8 +129,9 @@
 #if DCHECK_IS_ON()
   // Do the same DCHECKs that |ClampTo| would do so that optimization paths do
   // not have to do them.
-  for (size_t i = 0u; i < frames_to_process; ++i)
+  for (size_t i = 0u; i < frames_to_process; ++i) {
     DCHECK(!std::isnan(source_p[i]));
+  }
   // This also ensures that thresholds are not NaNs.
   DCHECK_LE(low_threshold, high_threshold);
 #endif
@@ -152,8 +153,9 @@
 #if DCHECK_IS_ON()
   // Do the same DCHECKs that |ClampTo| would do so that optimization paths do
   // not have to do them.
-  for (size_t i = 0u; i < frames_to_process; ++i)
+  for (size_t i = 0u; i < frames_to_process; ++i) {
     DCHECK(!std::isnan(source_p[i]));
+  }
   // This also ensures that thresholds are not NaNs.
   DCHECK_LE(low_threshold, high_threshold);
 #endif
diff --git a/third_party/blink/renderer/platform/audio/vector_math_test.cc b/third_party/blink/renderer/platform/audio/vector_math_test.cc
index 286db63d..cc81fad 100644
--- a/third_party/blink/renderer/platform/audio/vector_math_test.cc
+++ b/third_party/blink/renderer/platform/audio/vector_math_test.cc
@@ -60,8 +60,9 @@
 
 // Compare two floats and consider all NaNs to be equal.
 bool Equal(float a, float b) {
-  if (std::isnan(a))
+  if (std::isnan(a)) {
     return std::isnan(b);
+  }
   return a == b;
 }
 
@@ -245,12 +246,14 @@
     std::uniform_int_distribution<size_t> index_distribution(
         0u, kFloatArraySize / 2u - 1u);
     for (size_t i = 0u; i < kSourceCount; ++i) {
-      if (i == kFullyFiniteSource || i == kFullyFiniteSource2)
+      if (i == kFullyFiniteSource || i == kFullyFiniteSource2) {
         continue;
+      }
       sources_[i][index_distribution(generator)] = INFINITY;
       sources_[i][index_distribution(generator)] = -INFINITY;
-      if (i != kFullyNonNanSource)
+      if (i != kFullyNonNanSource) {
         sources_[i][index_distribution(generator)] = NAN;
+      }
     }
   }
 
@@ -264,16 +267,18 @@
 
 TEST_F(VectorMathTest, Conv) {
   for (const auto& source : GetPrimaryVectors(GetSource(kFullyFiniteSource))) {
-    if (source.stride() != 1)
+    if (source.stride() != 1) {
       continue;
+    }
     for (size_t filter_size : {3u, 32u, 64u, 128u}) {
       // The maximum number of frames which could be processed here is
       // |source.size() - filter_size + 1|. However, in order to test
       // optimization paths, |frames_to_process| should be optimal (divisible
       // by a power of 2) whenever |filter_size| is optimal. Therefore, let's
       // process only |source.size() - filter_size| frames here.
-      if (filter_size >= source.size())
+      if (filter_size >= source.size()) {
         break;
+      }
       uint32_t frames_to_process = source.size() - filter_size;
       // The stride of a convolution filter must be -1. Let's first create
       // a reversed filter whose stride is 1.
@@ -286,8 +291,9 @@
           GetDestination(0u), source.memory_layout(), frames_to_process);
       for (size_t i = 0u; i < frames_to_process; ++i) {
         expected_dest[i] = 0u;
-        for (size_t j = 0u; j < filter_size; ++j)
+        for (size_t j = 0u; j < filter_size; ++j) {
           expected_dest[i] += source[i + j] * *(filter_p - j);
+        }
       }
       for (auto& dest : GetSecondaryVectors(
                GetDestination(1u), source.memory_layout(), frames_to_process)) {
@@ -308,8 +314,9 @@
   for (const auto& source1 : GetPrimaryVectors(GetSource(0u))) {
     for (const auto& source2 : GetSecondaryVectors(GetSource(1u), source1)) {
       TestVector<float> expected_dest(GetDestination(0u), source1);
-      for (size_t i = 0u; i < source1.size(); ++i)
+      for (size_t i = 0u; i < source1.size(); ++i) {
         expected_dest[i] = source1[i] + source2[i];
+      }
       for (auto& dest : GetSecondaryVectors(GetDestination(1u), source1)) {
         Vadd(source1.p(), source1.stride(), source2.p(), source2.stride(),
              dest.p(), dest.stride(), source1.size());
@@ -323,8 +330,9 @@
   for (const auto& source1 : GetPrimaryVectors(GetSource(0u))) {
     for (const auto& source2 : GetSecondaryVectors(GetSource(1u), source1)) {
       TestVector<float> expected_dest(GetDestination(0u), source1);
-      for (size_t i = 0u; i < source1.size(); ++i)
+      for (size_t i = 0u; i < source1.size(); ++i) {
         expected_dest[i] = source1[i] - source2[i];
+      }
       for (auto& dest : GetSecondaryVectors(GetDestination(1u), source1)) {
         Vsub(source1.p(), source1.stride(), source2.p(), source2.stride(),
              dest.p(), dest.stride(), source1.size());
@@ -341,8 +349,9 @@
     const float low_threshold = std::min(thresholds[0], thresholds[1]);
     const float high_threshold = std::max(thresholds[0], thresholds[1]);
     TestVector<float> expected_dest(GetDestination(0u), source);
-    for (size_t i = 0u; i < source.size(); ++i)
+    for (size_t i = 0u; i < source.size(); ++i) {
       expected_dest[i] = ClampTo(source[i], low_threshold, high_threshold);
+    }
     for (auto& dest : GetSecondaryVectors(GetDestination(1u), source)) {
       Vclip(source.p(), source.stride(), &low_threshold, &high_threshold,
             dest.p(), dest.stride(), source.size());
@@ -372,8 +381,9 @@
   for (const auto& source1 : GetPrimaryVectors(GetSource(0u))) {
     for (const auto& source2 : GetSecondaryVectors(GetSource(1u), source1)) {
       TestVector<float> expected_dest(GetDestination(0u), source1);
-      for (size_t i = 0u; i < source1.size(); ++i)
+      for (size_t i = 0u; i < source1.size(); ++i) {
         expected_dest[i] = source1[i] * source2[i];
+      }
       for (auto& dest : GetSecondaryVectors(GetDestination(1u), source1)) {
         Vmul(source1.p(), source1.stride(), source2.p(), source2.stride(),
              dest.p(), dest.stride(), source1.size());
@@ -388,8 +398,9 @@
     const float scale = *GetSource(1u);
     const TestVector<const float> dest_source(GetSource(2u), source);
     TestVector<float> expected_dest(GetDestination(0u), source);
-    for (size_t i = 0u; i < source.size(); ++i)
+    for (size_t i = 0u; i < source.size(); ++i) {
       expected_dest[i] = dest_source[i] + scale * source[i];
+    }
     for (auto& dest : GetSecondaryVectors(GetDestination(1u), source)) {
       std::copy(dest_source.begin(), dest_source.end(), dest.begin());
       Vsma(source.p(), source.stride(), &scale, dest.p(), dest.stride(),
@@ -419,8 +430,9 @@
   for (const auto& source : GetPrimaryVectors(GetSource(0u))) {
     const float scale = *GetSource(1u);
     TestVector<float> expected_dest(GetDestination(0u), source);
-    for (size_t i = 0u; i < source.size(); ++i)
+    for (size_t i = 0u; i < source.size(); ++i) {
       expected_dest[i] = scale * source[i];
+    }
     for (auto& dest : GetSecondaryVectors(GetDestination(1u), source)) {
       Vsmul(source.p(), source.stride(), &scale, dest.p(), dest.stride(),
             source.size());
@@ -433,8 +445,9 @@
   for (const auto& source : GetPrimaryVectors(GetSource(0u))) {
     const float addend = *GetSource(1u);
     TestVector<float> expected_dest(GetDestination(0u), source);
-    for (size_t i = 0u; i < source.size(); ++i)
+    for (size_t i = 0u; i < source.size(); ++i) {
       expected_dest[i] = addend + source[i];
+    }
     for (auto& dest : GetSecondaryVectors(GetDestination(1u), source)) {
       Vsadd(source.p(), source.stride(), &addend, dest.p(), dest.stride(),
             source.size());
@@ -473,12 +486,14 @@
     std::copy_n(GetSource(i), kFloatArraySize, sources[i].begin());
     // Put +FLT_MAX and -FLT_MAX in the middle of the source. Use a different
     // sequence for each source in order to get 16 different combinations.
-    for (size_t j = 0u; j < 16u; ++j)
+    for (size_t j = 0u; j < 16u; ++j) {
       sources[i][kFloatArraySize / 2u + j] = ((j >> i) & 1) ? -kMax : kMax;
+    }
   }
   for (const auto& real1 : GetPrimaryVectors(sources[0u].data())) {
-    if (real1.stride() != 1)
+    if (real1.stride() != 1) {
       continue;
+    }
     const TestVector<const float> imag1(sources[1u].data(), real1);
     const TestVector<const float> real2(sources[2u].data(), real1);
     const TestVector<const float> imag2(sources[3u].data(), real1);
diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader.cc b/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader.cc
index ad6359c..600fda84 100644
--- a/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader.cc
@@ -6,7 +6,6 @@
 
 #include "services/network/public/mojom/early_hints.mojom.h"
 #include "services/network/public/mojom/url_response_head.mojom.h"
-#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/common/loader/referrer_utils.h"
 #include "third_party/blink/public/mojom/loader/code_cache.mojom-shared.h"
 #include "third_party/blink/public/platform/resource_load_info_notifier_wrapper.h"
@@ -49,19 +48,12 @@
   resource_load_observer_ = resource_load_observer;
   fetch_context_ = fetch_context;
   client_ = client;
-
   resource_load_info_notifier_wrapper_ =
       fetch_context->CreateResourceLoadInfoNotifierWrapper();
 
   // TODO(crbug.com/929370): Support CSP check to post violation reports for
   // worker top-level scripts, if off-the-main-thread fetch is enabled.
 
-  ResourceRequest resource_request(initial_request_);
-  resource_load_observer_->WillSendRequest(
-      resource_request,
-      /*redirect_response=*/ResourceResponse(), ResourceType::kScript,
-      resource_loader_options_, RenderBlockingBehavior::kNonBlocking);
-
   resource_load_info_notifier_wrapper_->NotifyResourceLoadInitiated(
       request_id_, initial_request_url_, initial_request_.HttpMethod().Latin1(),
       WebStringToGURL(WebString(initial_request_.ReferrerString())),
@@ -81,6 +73,7 @@
   resource_load_info_notifier_wrapper_->NotifyResourceResponseReceived(
       std::move(response_head), PreviewsTypes::kPreviewsUnspecified);
 
+  ResourceRequest resource_request(initial_request_);
   resource_load_observer_->DidReceiveResponse(
       initial_request_.InspectorId(), resource_request, resource_response_,
       /*resource=*/nullptr,
@@ -327,9 +320,6 @@
     WebURLLoader::PopulateURLResponse(
         WebURL(last_request_url_), *redirect_response, &response,
         redirect_response->ssl_info.has_value(), request_id_);
-    resource_load_observer_->WillSendRequest(
-        *new_request, response.ToResourceResponse(), ResourceType::kScript,
-        resource_loader_options_, RenderBlockingBehavior::kNonBlocking);
     resource_load_info_notifier_wrapper_->NotifyResourceRedirectReceived(
         redirect_info, std::move(redirect_response));
   }
diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader_unittest.cc b/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader_unittest.cc
index db6883f0..8ed7f468 100644
--- a/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader_unittest.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader_unittest.cc
@@ -268,7 +268,6 @@
   MockResourceLoadObserver* mock_observer =
       MakeGarbageCollected<MockResourceLoadObserver>();
   FakeResourceLoadInfoNotifier fake_resource_load_info_notifier;
-  EXPECT_CALL(*mock_observer, WillSendRequest(_, _, _, _, _));
   EXPECT_CALL(*mock_observer, DidReceiveResponse(_, _, _, _, _));
   EXPECT_CALL(*mock_observer, DidReceiveData(_, _));
   EXPECT_CALL(*mock_observer, DidFinishLoading(_, _, _, _, _));
@@ -299,7 +298,6 @@
   MockResourceLoadObserver* mock_observer =
       MakeGarbageCollected<MockResourceLoadObserver>();
   FakeResourceLoadInfoNotifier fake_resource_load_info_notifier;
-  EXPECT_CALL(*mock_observer, WillSendRequest(_, _, _, _, _));
   EXPECT_CALL(*mock_observer, DidReceiveResponse(_, _, _, _, _));
   EXPECT_CALL(*mock_observer, DidFinishLoading(_, _, _, _, _)).Times(0);
   EXPECT_CALL(*mock_observer, DidFailLoading(_, _, _, _, _));
@@ -323,7 +321,6 @@
   MockResourceLoadObserver* mock_observer =
       MakeGarbageCollected<MockResourceLoadObserver>();
   FakeResourceLoadInfoNotifier fake_resource_load_info_notifier;
-  EXPECT_CALL(*mock_observer, WillSendRequest(_, _, _, _, _));
   EXPECT_CALL(*mock_observer, DidReceiveResponse(_, _, _, _, _));
   EXPECT_CALL(*mock_observer, DidFinishLoading(_, _, _, _, _)).Times(0);
   EXPECT_CALL(*mock_observer, DidFailLoading(_, _, _, _, _));
@@ -347,7 +344,6 @@
   MockResourceLoadObserver* mock_observer =
       MakeGarbageCollected<MockResourceLoadObserver>();
   FakeResourceLoadInfoNotifier fake_resource_load_info_notifier;
-  EXPECT_CALL(*mock_observer, WillSendRequest(_, _, _, _, _));
   EXPECT_CALL(*mock_observer, DidReceiveResponse(_, _, _, _, _));
   EXPECT_CALL(*mock_observer, DidReceiveData(_, _));
   EXPECT_CALL(*mock_observer, DidFinishLoading(_, _, _, _, _)).Times(0);
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
index 03a2b40..fec56f4 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
@@ -826,27 +826,27 @@
 }
 
 TEST_F(FrameSchedulerImplTest, PauseAndResumeForCooperativeScheduling) {
-  EXPECT_TRUE(LoadingTaskQueue()->GetTaskQueue()->IsQueueEnabled());
-  EXPECT_TRUE(ThrottleableTaskQueue()->GetTaskQueue()->IsQueueEnabled());
-  EXPECT_TRUE(DeferrableTaskQueue()->GetTaskQueue()->IsQueueEnabled());
-  EXPECT_TRUE(PausableTaskQueue()->GetTaskQueue()->IsQueueEnabled());
-  EXPECT_TRUE(UnpausableTaskQueue()->GetTaskQueue()->IsQueueEnabled());
+  EXPECT_TRUE(LoadingTaskQueue()->IsQueueEnabled());
+  EXPECT_TRUE(ThrottleableTaskQueue()->IsQueueEnabled());
+  EXPECT_TRUE(DeferrableTaskQueue()->IsQueueEnabled());
+  EXPECT_TRUE(PausableTaskQueue()->IsQueueEnabled());
+  EXPECT_TRUE(UnpausableTaskQueue()->IsQueueEnabled());
 
   frame_scheduler_->SetPreemptedForCooperativeScheduling(
       FrameOrWorkerScheduler::Preempted(true));
-  EXPECT_FALSE(LoadingTaskQueue()->GetTaskQueue()->IsQueueEnabled());
-  EXPECT_FALSE(ThrottleableTaskQueue()->GetTaskQueue()->IsQueueEnabled());
-  EXPECT_FALSE(DeferrableTaskQueue()->GetTaskQueue()->IsQueueEnabled());
-  EXPECT_FALSE(PausableTaskQueue()->GetTaskQueue()->IsQueueEnabled());
-  EXPECT_FALSE(UnpausableTaskQueue()->GetTaskQueue()->IsQueueEnabled());
+  EXPECT_FALSE(LoadingTaskQueue()->IsQueueEnabled());
+  EXPECT_FALSE(ThrottleableTaskQueue()->IsQueueEnabled());
+  EXPECT_FALSE(DeferrableTaskQueue()->IsQueueEnabled());
+  EXPECT_FALSE(PausableTaskQueue()->IsQueueEnabled());
+  EXPECT_FALSE(UnpausableTaskQueue()->IsQueueEnabled());
 
   frame_scheduler_->SetPreemptedForCooperativeScheduling(
       FrameOrWorkerScheduler::Preempted(false));
-  EXPECT_TRUE(LoadingTaskQueue()->GetTaskQueue()->IsQueueEnabled());
-  EXPECT_TRUE(ThrottleableTaskQueue()->GetTaskQueue()->IsQueueEnabled());
-  EXPECT_TRUE(DeferrableTaskQueue()->GetTaskQueue()->IsQueueEnabled());
-  EXPECT_TRUE(PausableTaskQueue()->GetTaskQueue()->IsQueueEnabled());
-  EXPECT_TRUE(UnpausableTaskQueue()->GetTaskQueue()->IsQueueEnabled());
+  EXPECT_TRUE(LoadingTaskQueue()->IsQueueEnabled());
+  EXPECT_TRUE(ThrottleableTaskQueue()->IsQueueEnabled());
+  EXPECT_TRUE(DeferrableTaskQueue()->IsQueueEnabled());
+  EXPECT_TRUE(PausableTaskQueue()->IsQueueEnabled());
+  EXPECT_TRUE(UnpausableTaskQueue()->IsQueueEnabled());
 }
 
 namespace {
@@ -1085,9 +1085,9 @@
 TEST_F(FrameSchedulerImplTestWithUnfreezableLoading,
        LoadingTasksKeepRunningWhenFrozen) {
   int counter = 0;
-  UnfreezableLoadingTaskQueue()->GetTaskQueue()->task_runner()->PostTask(
+  UnfreezableLoadingTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask(
       FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter)));
-  LoadingTaskQueue()->GetTaskQueue()->task_runner()->PostTask(
+  LoadingTaskQueue()->GetTaskRunnerWithDefaultTaskType()->PostTask(
       FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter)));
 
   page_scheduler_->SetPageVisible(false);
@@ -3639,16 +3639,13 @@
       TaskQueue::QueuePriority expected_priority) {
     EXPECT_EQ(
         JavaScriptTimerNormalThrottleableTaskQueueForFrame(frame_scheduler)
-            ->GetTaskQueue()
             ->GetQueuePriority(),
         expected_priority);
     EXPECT_EQ(
         JavaScriptTimerIntensivelyThrottleableTaskQueueForFrame(frame_scheduler)
-            ->GetTaskQueue()
             ->GetQueuePriority(),
         expected_priority);
     EXPECT_EQ(JavaScriptTimerNonThrottleableTaskQueueForFrame(frame_scheduler)
-                  ->GetTaskQueue()
                   ->GetQueuePriority(),
               expected_priority);
   }
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
index 8f39b9c..1ef91e0 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
@@ -2736,8 +2736,7 @@
     bool expect_queue_enabled = (i == 0) || (Now() > first_run_time);
     if (paused)
       expect_queue_enabled = false;
-    EXPECT_EQ(expect_queue_enabled,
-              throttleable_task_queue()->GetTaskQueue()->IsQueueEnabled())
+    EXPECT_EQ(expect_queue_enabled, throttleable_task_queue()->IsQueueEnabled())
         << "i = " << i;
 
     // After we've run any expensive tasks suspend the queue.  The throttling
@@ -2782,8 +2781,7 @@
 
     base::RunLoop().RunUntilIdle();
     EXPECT_EQ(UseCase::kSynchronizedGesture, CurrentUseCase()) << "i = " << i;
-    EXPECT_TRUE(throttleable_task_queue()->GetTaskQueue()->IsQueueEnabled())
-        << "i = " << i;
+    EXPECT_TRUE(throttleable_task_queue()->IsQueueEnabled()) << "i = " << i;
   }
 
   // Task is not throttled.
@@ -3452,8 +3450,8 @@
   scoped_refptr<MainThreadTaskQueue> queue2 =
       scheduler_->NewThrottleableTaskQueueForTest(nullptr);
 
-  EXPECT_TRUE(queue1->GetTaskQueue()->IsQueueEnabled());
-  EXPECT_TRUE(queue2->GetTaskQueue()->IsQueueEnabled());
+  EXPECT_TRUE(queue1->IsQueueEnabled());
+  EXPECT_TRUE(queue2->IsQueueEnabled());
 
   scheduler_->OnShutdownTaskQueue(queue1);
 
@@ -3461,8 +3459,8 @@
 
   // queue2 should be disabled, as it is a regular queue and nothing should
   // change for queue1 because it was shut down.
-  EXPECT_TRUE(queue1->GetTaskQueue()->IsQueueEnabled());
-  EXPECT_FALSE(queue2->GetTaskQueue()->IsQueueEnabled());
+  EXPECT_TRUE(queue1->IsQueueEnabled());
+  EXPECT_FALSE(queue2->IsQueueEnabled());
 }
 
 TEST_F(MainThreadSchedulerImplTest, MicrotaskCheckpointTiming) {
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h
index 0a8f55c..eaee4d0 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h
@@ -36,10 +36,6 @@
 class MainThreadSchedulerImplTest;
 }
 
-namespace task_queue_throttler_unittest {
-class TaskQueueThrottlerTest;
-}
-
 class FrameSchedulerImpl;
 class MainThreadSchedulerImpl;
 class WakeUpBudgetPool;
@@ -490,6 +486,9 @@
     return task_queue_->GetQueuePriority();
   }
 
+  bool IsQueueEnabled() const { return task_queue_->IsQueueEnabled(); }
+  bool IsEmpty() const { return task_queue_->IsEmpty(); }
+
   base::WeakPtr<MainThreadTaskQueue> AsWeakPtr() {
     return weak_ptr_factory_.GetWeakPtr();
   }
@@ -499,11 +498,6 @@
  protected:
   void SetFrameSchedulerForTest(FrameSchedulerImpl* frame_scheduler);
 
-  // Returns the underlying task queue. Only to be used for tests that need to
-  // test functionality of the task queue specifically without the wrapping
-  // MainThreadTaskQueue (ex TaskQueueThrottlerTest).
-  TaskQueue* GetTaskQueueForTest() { return task_queue_.get(); }
-
   // TODO(kdillon): Remove references to TaskQueueImpl once TaskQueueImpl
   // inherits from TaskQueue.
   MainThreadTaskQueue(
@@ -522,8 +516,6 @@
   friend class base::sequence_manager::SequenceManager;
   friend class blink::scheduler::main_thread_scheduler_impl_unittest::
       MainThreadSchedulerImplTest;
-  friend class blink::scheduler::task_queue_throttler_unittest::
-      TaskQueueThrottlerTest;
 
   // Clear references to main thread scheduler and frame scheduler and dispatch
   // appropriate notifications. This is the common part of ShutdownTaskQueue and
diff --git a/third_party/blink/renderer/platform/timer_test.cc b/third_party/blink/renderer/platform/timer_test.cc
index 63ff064..9dd5abcc 100644
--- a/third_party/blink/renderer/platform/timer_test.cc
+++ b/third_party/blink/renderer/platform/timer_test.cc
@@ -590,7 +590,7 @@
   timer.StartOneShot(base::TimeDelta(), FROM_HERE);
 
   // Make sure the task was posted on taskRunner.
-  EXPECT_FALSE(task_queue->GetTaskQueue()->IsEmpty());
+  EXPECT_FALSE(task_queue->IsEmpty());
 }
 
 TEST_F(TimerTest, RunOnHeapTimer) {
@@ -712,8 +712,8 @@
 
   EXPECT_THAT(run_order, ElementsAre(task_runner2));
 
-  EXPECT_TRUE(task_queue1->GetTaskQueue()->IsEmpty());
-  EXPECT_TRUE(task_queue2->GetTaskQueue()->IsEmpty());
+  EXPECT_TRUE(task_queue1->IsEmpty());
+  EXPECT_TRUE(task_queue2->IsEmpty());
 }
 
 TEST_F(TimerTest, MoveToNewTaskRunnerRepeating) {
@@ -755,8 +755,8 @@
   EXPECT_THAT(run_order, ElementsAre(task_runner1, task_runner1, task_runner2,
                                      task_runner2));
 
-  EXPECT_TRUE(task_queue1->GetTaskQueue()->IsEmpty());
-  EXPECT_FALSE(task_queue2->GetTaskQueue()->IsEmpty());
+  EXPECT_TRUE(task_queue1->IsEmpty());
+  EXPECT_FALSE(task_queue2->IsEmpty());
 }
 
 // This test checks that when inactive timer is moved to a different task
@@ -778,8 +778,8 @@
 
   platform_->RunUntilIdle();
   EXPECT_TRUE(!run_times_.size());
-  EXPECT_TRUE(task_queue1->GetTaskQueue()->IsEmpty());
-  EXPECT_TRUE(task_queue2->GetTaskQueue()->IsEmpty());
+  EXPECT_TRUE(task_queue1->IsEmpty());
+  EXPECT_TRUE(task_queue2->IsEmpty());
 }
 
 }  // namespace
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
index 2c7a612..cf3b84e 100644
--- a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
+++ b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
@@ -1578,6 +1578,7 @@
 
 crbug.com/674631 external/wpt/css/css-color/inline-opacity-float-child.html [ Failure ]
 crbug.com/1275215 external/wpt/svg/text/scripted/getstartpositionofchar-dominant-baseline.html [ Failure ]
+crbug.com/1179585 svg/custom/visibility-collapse.html [ Failure ]
 
 # Off by one errors cause by SwiftShader update
 crbug.com/1266821 compositing/gestures/gesture-tapHighlight-pixel-rotated-div.html [ Failure ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 3e02fa2..b08b24c7 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1523,9 +1523,6 @@
 crbug.com/1121942 virtual/layout_ng_printing/printing/webgl-oversized-printing.html [ Skip ]
 crbug.com/1121942 virtual/layout_ng_printing/printing/width-overflow.html [ Failure ]
 
-### Textarea NG
-crbug.com/1140307 accessibility/inline-text-textarea.html [ Failure ]
-
 ### TablesNG
 # crbug.com/958381
 
@@ -3077,13 +3074,10 @@
 crbug.com/626703 [ Mac11-arm64 ] external/wpt/css/css-flexbox/flexbox_flow-column-wrap.html [ Crash Failure ]
 
 # ====== New tests from wpt-importer added here ======
-crbug.com/626703 [ Mac11 ] virtual/off-main-thread-css-paint/external/wpt/css/css-paint-api/geometry-border-image-002.https.html [ Failure ]
 crbug.com/626703 [ Mac10.14 ] external/wpt/web-share/share-url-invalid.https.html [ Timeout ]
 crbug.com/626703 [ Mac10.14 ] external/wpt/webxr/depth-sensing/cpu/depth_sensing_cpu_staleView.https.html [ Timeout ]
-crbug.com/626703 [ Mac11 ] virtual/off-main-thread-css-paint/external/wpt/css/css-paint-api/parse-input-arguments-009.https.html [ Failure ]
 crbug.com/626703 [ Mac10.14 ] virtual/scroll-unification/external/wpt/dom/events/scrolling/overscroll-event-fired-to-document.html [ Timeout ]
 crbug.com/626703 [ Mac10.14 ] virtual/portals/external/wpt/portals/no-portal-in-sandboxed-popup.html [ Timeout ]
-crbug.com/626703 [ Mac11 ] virtual/off-main-thread-css-paint/external/wpt/css/css-paint-api/registered-property-value-002.https.html [ Failure ]
 crbug.com/626703 [ Mac10.13 ] virtual/plz-dedicated-worker/external/wpt/resource-timing/object-not-found-adds-entry.html [ Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/css/css-color-adjust/inheritance.html [ Crash Failure ]
 crbug.com/626703 [ Mac11-arm64 ] external/wpt/fetch/private-network-access/fetch.window.html [ Timeout ]
@@ -3099,8 +3093,6 @@
 crbug.com/626703 [ Mac11-arm64 ] wpt_internal/bluetooth/characteristic/getDescriptors/blocklisted-descriptors-not-present.https.html [ Crash Failure ]
 crbug.com/626703 [ Mac11-arm64 ] wpt_internal/css/css-transforms/raster-scale-perspective-001.html [ Crash Failure ]
 crbug.com/626703 [ Mac11-arm64 ] wpt_internal/css/selectors/focus-visible-select-001.html [ Crash Failure ]
-crbug.com/626703 [ Mac10.15 ] virtual/off-main-thread-css-paint/external/wpt/css/css-paint-api/parse-input-arguments-012.https.html [ Failure ]
-crbug.com/626703 [ Mac10.15 ] virtual/off-main-thread-css-paint/external/wpt/css/css-paint-api/invalid-image-constructor-error.https.html [ Failure ]
 crbug.com/626703 [ Mac11-arm64 ] external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-022.html [ Crash Failure ]
 crbug.com/626703 [ Mac11-arm64 ] external/wpt/fetch/private-network-access/fetch.https.window.html?include=from-treat-as-public [ Timeout ]
 crbug.com/626703 [ Mac11-arm64 ] virtual/plz-dedicated-worker/external/wpt/fetch/private-network-access/fetch.window.html [ Timeout ]
@@ -4555,9 +4547,6 @@
 crbug.com/618969 external/wpt/css/css-grid/subgrid/subgrid-mbp-overflow-003.html [ Failure ]
 crbug.com/618969 external/wpt/css/css-grid/subgrid/subgrid-mbp-overflow-004.html [ Failure ]
 
-### Tests failing with SVGTextNG enabled:
-crbug.com/1179585 svg/custom/visibility-collapse.html [ Failure ]
-
 crbug.com/1236992 svg/dom/SVGListPropertyTearOff-gccrash.html [ Failure Pass ]
 
 # [css-animations]
@@ -6290,7 +6279,7 @@
 crbug.com/1222114 http/tests/devtools/console/console-dir.js [ Failure Pass ]
 crbug.com/1222114 http/tests/devtools/console/console-format.js [ Failure Pass ]
 
-crbug.com/1247844 external/wpt/css/css-contain/content-visibility/content-visibility-input-image.html [ Timeout ]
+crbug.com/1247844 external/wpt/css/css-contain/content-visibility/content-visibility-input-image.html [ Skip ]
 
 # Expected to fail with SuppressDifferentOriginSubframeJSDialogs feature disabled, tested in VirtualTestSuite
 crbug.com/1065085 external/wpt/html/webappapis/user-prompts/cannot-show-simple-dialogs/confirm-different-origin-frame.sub.html [ Failure ]
@@ -6466,10 +6455,6 @@
 
 crbug.com/1143102 virtual/plz-dedicated-worker/http/tests/inspector-protocol/fetch/dedicated-worker-main-script.js [ Skip ]
 
-# Should be fixed before PlzDedicatedWorker is shipped.
-crbug.com/1143102 virtual/plz-dedicated-worker/http/tests/devtools/network/network-worker-fetch.js [ Skip ]
-crbug.com/1143102 virtual/plz-dedicated-worker/http/tests/devtools/network/network-worker-fetch-parallel.js [ Skip ]
-
 # These timeout because COEP reporting to a worker is not implemented.
 crbug.com/1197041 external/wpt/html/cross-origin-embedder-policy/reporting-to-worker-owner.https.html [ Skip ]
 crbug.com/1197041 virtual/plz-dedicated-worker/external/wpt/html/cross-origin-embedder-policy/reporting-to-worker-owner.https.html [ Skip ]
@@ -7635,8 +7620,6 @@
 crbug.com/1285411 external/wpt/css/css-scroll-snap/input/mouse-wheel.html [ Timeout ]
 
 # Sheriff 2022-01-07
-crbug.com/1285348 [ Mac ] virtual/off-main-thread-css-paint/external/wpt/css/css-paint-api/hidpi/canvas-transform.https.html [ Failure Pass ]
-crbug.com/1285350 virtual/off-main-thread-css-paint/external/wpt/css/css-paint-api/parse-input-arguments-011.https.html [ Failure Pass ]
 crbug.com/1285438 fast/layers/clip-rects-transformed.html [ Failure Pass ]
 crbug.com/1285431 [ Mac ] virtual/backface-visibility-interop/compositing/overflow/transform-should-update-absolute-clip-rects.html [ Crash Failure Pass ]
 crbug.com/1285437 virtual/scroll-unification-prefer_compositing_to_lcd_text/fast/scroll-behavior/smooth-scroll/ongoing-smooth-scroll-vertical-rl-anchors.html [ Pass Timeout ]
@@ -7654,3 +7637,12 @@
 
 # Changes to fork() on Mac causing test to crash
 crbug.com/1284401 [ Mac ] virtual/fenced-frame-mparch/wpt_internal/fenced_frame/create-credential.https.html [ Crash Failure ]
+
+# Flaky failures in finding the reference file on Mac
+crbug.com/1286944 [ Mac10.15 ] virtual/off-main-thread-css-paint/external/wpt/css/css-paint-api/parse-input-arguments-012.https.html [ Failure Pass ]
+crbug.com/1286944 [ Mac10.15 ] virtual/off-main-thread-css-paint/external/wpt/css/css-paint-api/invalid-image-constructor-error.https.html [ Failure Pass ]
+crbug.com/1286944 [ Mac11 ] virtual/off-main-thread-css-paint/external/wpt/css/css-paint-api/registered-property-value-002.https.html [ Failure Pass ]
+crbug.com/1286944 [ Mac11 ] virtual/off-main-thread-css-paint/external/wpt/css/css-paint-api/parse-input-arguments-009.https.html [ Failure Pass ]
+crbug.com/1286944 [ Mac11 ] virtual/off-main-thread-css-paint/external/wpt/css/css-paint-api/geometry-border-image-002.https.html [ Failure Pass ]
+crbug.com/1286944 [ Mac ] virtual/off-main-thread-css-paint/external/wpt/css/css-paint-api/hidpi/canvas-transform.https.html [ Failure Pass ]
+crbug.com/1286944 virtual/off-main-thread-css-paint/external/wpt/css/css-paint-api/parse-input-arguments-011.https.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/accessibility/inline-text-textarea-expected.txt b/third_party/blink/web_tests/accessibility/inline-text-textarea-expected.txt
index 502256ff..b5226e7 100644
--- a/third_party/blink/web_tests/accessibility/inline-text-textarea-expected.txt
+++ b/third_party/blink/web_tests/accessibility/inline-text-textarea-expected.txt
@@ -3,7 +3,7 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 PASS firstInlineTextBoxBefore.isEqual(firstInlineTextBoxAfter) is false
-PASS lastInlineTextBoxBefore.isEqual(lastInlineTextBoxAfter) is true
+FAIL lastInlineTextBoxBefore.isEqual(lastInlineTextBoxAfter) should be true. Was false.
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/blink/web_tests/accessibility/inline-text-textarea.html b/third_party/blink/web_tests/accessibility/inline-text-textarea.html
index d98a418..c6e42d5 100644
--- a/third_party/blink/web_tests/accessibility/inline-text-textarea.html
+++ b/third_party/blink/web_tests/accessibility/inline-text-textarea.html
@@ -45,6 +45,9 @@
         var lastInlineTextBoxAfter = inlineTextBoxesAfter[inlineTextBoxesAfter.length - 1];
 
         shouldBe("firstInlineTextBoxBefore.isEqual(firstInlineTextBoxAfter)", "false");
+
+        // The following check fails with LayoutNG, which doesn't recycle
+        // AXInlineTextBoxes instances. crbug.com/1140307
         shouldBe("lastInlineTextBoxBefore.isEqual(lastInlineTextBoxAfter)", "true");
     }
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/drawing-text-to-the-canvas/2d.text.drawing.style.invalid.spacing.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/drawing-text-to-the-canvas/2d.text.drawing.style.invalid.spacing.html
new file mode 100644
index 0000000..61ca6d4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/drawing-text-to-the-canvas/2d.text.drawing.style.invalid.spacing.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.text.drawing.style.invalid.spacing</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/html/canvas/resources/canvas-tests.js"></script>
+<link rel="stylesheet" href="/html/canvas/resources/canvas-tests.css">
+<body class="show_output">
+
+<h1>2d.text.drawing.style.invalid.spacing</h1>
+<p class="desc">Testing letter spacing and word spacing with invalid units</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Testing letter spacing and word spacing with invalid units");
+_addTest(function(canvas, ctx) {
+
+_assertSame(ctx.letterSpacing, '0px', "ctx.letterSpacing", "'0px'");
+_assertSame(ctx.wordSpacing, '0px', "ctx.wordSpacing", "'0px'");
+
+function test_word_spacing(value) {
+  ctx.wordSpacing = value;
+  ctx.letterSpacing = value;
+  _assertSame(ctx.wordSpacing, '0px', "ctx.wordSpacing", "'0px'");
+  _assertSame(ctx.letterSpacing, '0px', "ctx.letterSpacing", "'0px'");
+}
+test_word_spacing('0s');
+test_word_spacing('1min');
+test_word_spacing('1deg');
+test_word_spacing('1pp');
+
+
+});
+</script>
+
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.invalid.spacing.html b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.invalid.spacing.html
new file mode 100644
index 0000000..a117be0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.invalid.spacing.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>OffscreenCanvas test: 2d.text.drawing.style.invalid.spacing</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/html/canvas/resources/canvas-tests.js"></script>
+
+<h1>2d.text.drawing.style.invalid.spacing</h1>
+<p class="desc">Testing letter spacing and word spacing with invalid units</p>
+
+
+<script>
+var t = async_test("Testing letter spacing and word spacing with invalid units");
+var t_pass = t.done.bind(t);
+var t_fail = t.step_func(function(reason) {
+    throw reason;
+});
+t.step(function() {
+
+var canvas = new OffscreenCanvas(100, 50);
+var ctx = canvas.getContext('2d');
+
+_assertSame(ctx.letterSpacing, '0px', "ctx.letterSpacing", "'0px'");
+_assertSame(ctx.wordSpacing, '0px', "ctx.wordSpacing", "'0px'");
+
+function test_word_spacing(value) {
+  ctx.wordSpacing = value;
+  ctx.letterSpacing = value;
+  _assertSame(ctx.wordSpacing, '0px', "ctx.wordSpacing", "'0px'");
+  _assertSame(ctx.letterSpacing, '0px', "ctx.letterSpacing", "'0px'");
+}
+test_word_spacing('0s');
+test_word_spacing('1min');
+test_word_spacing('1deg');
+test_word_spacing('1pp');
+
+t.done();
+
+});
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.invalid.spacing.worker.js b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.invalid.spacing.worker.js
new file mode 100644
index 0000000..7f6baf28
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/text/2d.text.drawing.style.invalid.spacing.worker.js
@@ -0,0 +1,36 @@
+// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
+// OffscreenCanvas test in a worker:2d.text.drawing.style.invalid.spacing
+// Description:Testing letter spacing and word spacing with invalid units
+// Note:
+
+importScripts("/resources/testharness.js");
+importScripts("/html/canvas/resources/canvas-tests.js");
+
+var t = async_test("Testing letter spacing and word spacing with invalid units");
+var t_pass = t.done.bind(t);
+var t_fail = t.step_func(function(reason) {
+    throw reason;
+});
+t.step(function() {
+
+var canvas = new OffscreenCanvas(100, 50);
+var ctx = canvas.getContext('2d');
+
+_assertSame(ctx.letterSpacing, '0px', "ctx.letterSpacing", "'0px'");
+_assertSame(ctx.wordSpacing, '0px', "ctx.wordSpacing", "'0px'");
+
+function test_word_spacing(value) {
+  ctx.wordSpacing = value;
+  ctx.letterSpacing = value;
+  _assertSame(ctx.wordSpacing, '0px', "ctx.wordSpacing", "'0px'");
+  _assertSame(ctx.letterSpacing, '0px', "ctx.letterSpacing", "'0px'");
+}
+test_word_spacing('0s');
+test_word_spacing('1min');
+test_word_spacing('1deg');
+test_word_spacing('1pp');
+
+t.done();
+
+});
+done();
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/element/drawing-text-to-the-canvas.yaml b/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/element/drawing-text-to-the-canvas.yaml
index 846c3f9..686bd076 100644
--- a/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/element/drawing-text-to-the-canvas.yaml
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/element/drawing-text-to-the-canvas.yaml
@@ -780,6 +780,22 @@
     }
     @nonfinite test_word_spacing(<0 NaN Infinity -Infinity>);
 
+- name: 2d.text.drawing.style.invalid.spacing
+  desc: Testing letter spacing and word spacing with invalid units
+  testing:
+  - 2d.text.drawing.style.spacing
+  code: |
+    @assert ctx.letterSpacing === '0px';
+    @assert ctx.wordSpacing === '0px';
+
+    function test_word_spacing(value) {
+      ctx.wordSpacing = value;
+      ctx.letterSpacing = value;
+      @assert ctx.wordSpacing === '0px';
+      @assert ctx.letterSpacing === '0px';
+    }
+    @nonfinite test_word_spacing(< '0s' '1min' '1deg' '1pp'>);
+
 - name: 2d.text.drawing.style.letterSpacing.measure
   desc: Testing letter spacing and word spacing
   testing:
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/offscreen/text.yaml b/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/offscreen/text.yaml
index 9713626..636d7f5e 100644
--- a/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/offscreen/text.yaml
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/offscreen/text.yaml
@@ -1303,6 +1303,24 @@
 
     t.done();
 
+- name: 2d.text.drawing.style.invalid.spacing
+  desc: Testing letter spacing and word spacing with invalid units
+  testing:
+  - 2d.text.drawing.style.spacing
+  code: |
+    @assert ctx.letterSpacing === '0px';
+    @assert ctx.wordSpacing === '0px';
+
+    function test_word_spacing(value) {
+      ctx.wordSpacing = value;
+      ctx.letterSpacing = value;
+      @assert ctx.wordSpacing === '0px';
+      @assert ctx.letterSpacing === '0px';
+    }
+    @nonfinite test_word_spacing(< '0s' '1min' '1deg' '1pp'>);
+
+    t.done();
+
 - name: 2d.text.drawing.style.letterSpacing.measure
   desc: Testing letter spacing and word spacing
   testing:
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/generic/inheritance/iframe-inheritance-history-about-blank.html b/third_party/blink/web_tests/external/wpt/referrer-policy/generic/inheritance/iframe-inheritance-history-about-blank.html
new file mode 100644
index 0000000..8d68ffb5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/referrer-policy/generic/inheritance/iframe-inheritance-history-about-blank.html
@@ -0,0 +1,80 @@
+<!doctype html>
+<title>Referrer Policy: navigating back to an about:blank iframe reuses the original referrer policy</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<meta name="referrer" content="no-referrer">
+<div id="log"></div>
+<script>
+  let checkReferrer = document => {
+    let script = document.createElement('script');
+    script.innerText = `
+      fetch("${origin}/common/security-features/subresource/xhr.py",
+            {referrer: "${location.origin}/custom"})
+        .then(r => r.json())
+        .then(j => {
+          top.postMessage({referrer: j.headers.referer}, "*")
+        }).catch(e => {
+          top.postMessage({referrer: "FAILURE"}, "*");
+        });
+    `
+
+    let referrer = new Promise(resolve => {
+      window.addEventListener("message", function listener(msg) {
+        window.removeEventListener("message", listener, false);
+        resolve(msg.data.referrer);
+      });
+    });
+
+    document.body.appendChild(script);
+
+    return referrer;
+  };
+
+  let iframeLoaded = iframe => {
+    return new Promise(resolve => {
+      iframe.onload = resolve;
+    });
+  };
+
+  promise_test(async t => {
+    // 1. Create an iframe and navigate it to about:blank.
+    // (We cannot just create an empty iframe since the initial empty
+    // document will get its history entry replaced, so we cannot
+    // navigate back to it.)
+    const iframe = document.createElement("iframe");
+    iframe.name = 'test_frame';
+    iframe.src = "/referrer-policy";
+    document.body.appendChild(iframe);
+    await iframeLoaded(iframe);
+
+    window.open('about:blank', 'test_frame');
+    await iframeLoaded(iframe);
+    let referrer_1 = await checkReferrer(iframe.contentDocument);
+    assert_equals(referrer_1, undefined,
+                  "First navigation uses correct policy.");
+
+    // 2. Change the referrer policy of the iframe.
+    let meta = iframe.contentDocument.createElement('meta');
+    meta.name = 'referrer';
+    meta.content = "unsafe-url";
+    iframe.contentDocument.head.appendChild(meta);
+
+    let referrer_2 = await checkReferrer(iframe.contentDocument);
+    assert_equals(referrer_2, location.origin + '/custom',
+                  "Referrer policy correctly changed.");
+
+    // 3. Navigate the iframe elsewhere.
+    window.open('/referrer-policy', 'test_frame');
+    await iframeLoaded(iframe);
+
+    // 4. Navigate the iframe back.
+    iframe.contentWindow.history.back();
+    await iframeLoaded(iframe);
+
+    let referrer_3 = await checkReferrer(iframe.contentDocument);
+    assert_equals(referrer_3, undefined,
+                  "History navigation reuses original policy.");
+    document.body.removeChild(iframe);
+  }, "History navigation reuses original policy.");
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/svg/text/scripted/lengthadjust.html b/third_party/blink/web_tests/external/wpt/svg/text/scripted/lengthadjust.html
new file mode 100644
index 0000000..51b06675
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/text/scripted/lengthadjust.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<title>lengthAdjust content/IDL attribute</title>
+<link rel="help" href="https://svgwg.org/svg2-draft/text.html#TextElementLengthAdjustAttribute">
+<link rel="help" href="https://svgwg.org/svg2-draft/text.html#__svg__SVGTextContentElement__getComputedTextLength">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<svg>
+ <text x="0" y="215" textLength="200">Stretched text</text>
+ <text x="0" y="215" textLength="200">Stretched text</text>
+</svg>
+
+<script>
+test(() => {
+  const text = document.querySelectorAll('text')[0];
+  assert_equals(text.getAttribute('lengthAdjust'), null);
+  assert_equals(text.lengthAdjust.baseVal, SVGTextContentElement.LENGTHADJUST_SPACING);
+  assert_equals(text.textLength.baseVal.value, 200);
+  let lastLength = text.getComputedTextLength();
+  assert_between_exclusive(lastLength, 0, 200);
+
+  text.setAttribute('lengthAdjust', 'spacingAndGlyphs');
+  assert_equals(text.lengthAdjust.baseVal, SVGTextContentElement.LENGTHADJUST_SPACINGANDGLYPHS);
+  assert_equals(text.textLength.baseVal.value, 200);
+  assert_greater_than(text.getComputedTextLength(), lastLength);
+}, 'Tests dynamic updates of the "lengthAdjust" content attribute');
+
+test(() => {
+  const text = document.querySelectorAll('text')[1];
+  assert_equals(text.getAttribute('lengthAdjust'), null);
+  assert_equals(text.lengthAdjust.baseVal, SVGTextContentElement.LENGTHADJUST_SPACING);
+  assert_equals(text.textLength.baseVal.value, 200);
+  let lastLength = text.getComputedTextLength();
+  assert_between_exclusive(lastLength, 0, 200);
+
+  text.lengthAdjust.baseVal = SVGTextContentElement.LENGTHADJUST_SPACINGANDGLYPHS;
+  assert_equals(text.getAttribute('lengthAdjust'), 'spacingAndGlyphs');
+  assert_equals(text.lengthAdjust.baseVal, SVGTextContentElement.LENGTHADJUST_SPACINGANDGLYPHS);
+  assert_equals(text.textLength.baseVal.value, 200);
+  assert_greater_than(text.getComputedTextLength(), lastLength);
+}, 'Tests dynamic updates of the "lengthAdjust" IDL attribute');
+</script>
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/accessibility/inline-text-textarea-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/accessibility/inline-text-textarea-expected.txt
new file mode 100644
index 0000000..502256ff
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/accessibility/inline-text-textarea-expected.txt
@@ -0,0 +1,10 @@
+Demonstrates that when typing in a textarea, not all of the InlineTextBoxes need to be updated for every character pressed.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS firstInlineTextBoxBefore.isEqual(firstInlineTextBoxAfter) is false
+PASS lastInlineTextBoxBefore.isEqual(lastInlineTextBoxAfter) is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/svg/text/scripted/lengthadjust-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/svg/text/scripted/lengthadjust-expected.txt
new file mode 100644
index 0000000..81f17d78
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/svg/text/scripted/lengthadjust-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL Tests dynamic updates of the "lengthAdjust" content attribute assert_greater_than: expected a number greater than 86 but got 86
+FAIL Tests dynamic updates of the "lengthAdjust" IDL attribute assert_greater_than: expected a number greater than 86 but got 86
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/svg/custom/visibility-collapse-expected.html b/third_party/blink/web_tests/svg/custom/visibility-collapse-expected.html
index 6455516..a1abf790 100644
--- a/third_party/blink/web_tests/svg/custom/visibility-collapse-expected.html
+++ b/third_party/blink/web_tests/svg/custom/visibility-collapse-expected.html
@@ -1,6 +1,8 @@
 <!DOCTYPE HTML>
 <svg>
-  <text y="125">
-      PASS if NOT underlined
+  <text y="125" text-decoration="underline">
+      PASS if underlined
   </text>
-</svg>
\ No newline at end of file
+</svg>
+
+<p style="text-decoration: underline;">PASS if underlined</p>
diff --git a/third_party/blink/web_tests/svg/custom/visibility-collapse.html b/third_party/blink/web_tests/svg/custom/visibility-collapse.html
index 1e94a0a3b..4ba3e087 100644
--- a/third_party/blink/web_tests/svg/custom/visibility-collapse.html
+++ b/third_party/blink/web_tests/svg/custom/visibility-collapse.html
@@ -4,7 +4,9 @@
   <image xlink:href="resources/red-checker.png" x="110" width="100" height="100" visibility="collapse"/>
   <text y="125">
     <tspan text-decoration="underline" visibility="collapse">
-      <tspan visibility="visible">PASS if NOT underlined</tspan>
+      <tspan visibility="visible">PASS if underlined</tspan>
     </tspan>
   </text>
-</svg>
\ No newline at end of file
+</svg>
+<p><span style="text-decoration: underline; visibility: collapse;"><span style="visibility: visible">
+PASS if underlined</span></span></p>
diff --git a/third_party/blink/web_tests/svg/dynamic-updates/SVGTextElement-dom-lengthAdjust-attr-expected.txt b/third_party/blink/web_tests/svg/dynamic-updates/SVGTextElement-dom-lengthAdjust-attr-expected.txt
deleted file mode 100644
index cce52210..0000000
--- a/third_party/blink/web_tests/svg/dynamic-updates/SVGTextElement-dom-lengthAdjust-attr-expected.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-SVG 1.1 dynamic update tests
-Stretched text
-
-Tests dynamic updates of the 'lengthAdjust' attribute of the SVGTextElement object
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-PASS textElement.getAttribute('lengthAdjust') is null
-PASS textElement.lengthAdjust.baseVal is SVGTextContentElement.LENGTHADJUST_SPACING
-PASS textElement.textLength.baseVal.value is 200
-PASS lastLength = textElement.getComputedTextLength(); lastLength > 0 && lastLength < 200 is true
-PASS textElement.lengthAdjust.baseVal is SVGTextContentElement.LENGTHADJUST_SPACINGANDGLYPHS
-PASS textElement.textLength.baseVal.value is 200
-FAIL textElement.getComputedTextLength() == lastLength should be true. Was false.
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/blink/web_tests/svg/dynamic-updates/SVGTextElement-dom-lengthAdjust-attr.html b/third_party/blink/web_tests/svg/dynamic-updates/SVGTextElement-dom-lengthAdjust-attr.html
deleted file mode 100644
index c5480f9..0000000
--- a/third_party/blink/web_tests/svg/dynamic-updates/SVGTextElement-dom-lengthAdjust-attr.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="resources/SVGTestCase.js"></script>
-<script src="../../resources/js-test.js"></script>
-<script src="../../paint/invalidation/resources/text-based-repaint.js"></script>
-</head>
-<body onload="runRepaintTest()">
-<h1>SVG 1.1 dynamic update tests</h1>
-<p id="description"></p>
-<div id="console"></div>
-<script src="script-tests/SVGTextElement-dom-lengthAdjust-attr.js"></script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/svg/dynamic-updates/SVGTextElement-svgdom-lengthAdjust-prop-expected.txt b/third_party/blink/web_tests/svg/dynamic-updates/SVGTextElement-svgdom-lengthAdjust-prop-expected.txt
deleted file mode 100644
index f071417..0000000
--- a/third_party/blink/web_tests/svg/dynamic-updates/SVGTextElement-svgdom-lengthAdjust-prop-expected.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-SVG 1.1 dynamic update tests
-Stretched text
-
-Tests dynamic updates of the 'lengthAdjust' property of the SVGTextElement object
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-PASS textElement.getAttribute('lengthAdjust') is null
-PASS textElement.lengthAdjust.baseVal is SVGTextContentElement.LENGTHADJUST_SPACING
-PASS textElement.textLength.baseVal.value is 200
-PASS lastLength = textElement.getComputedTextLength(); lastLength > 0 && lastLength < 200 is true
-PASS textElement.getAttribute('lengthAdjust') is "spacingAndGlyphs"
-PASS textElement.lengthAdjust.baseVal is SVGTextContentElement.LENGTHADJUST_SPACINGANDGLYPHS
-PASS textElement.textLength.baseVal.value is 200
-FAIL textElement.getComputedTextLength() == lastLength should be true. Was false.
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/blink/web_tests/svg/dynamic-updates/SVGTextElement-svgdom-lengthAdjust-prop.html b/third_party/blink/web_tests/svg/dynamic-updates/SVGTextElement-svgdom-lengthAdjust-prop.html
deleted file mode 100644
index 65fbc04..0000000
--- a/third_party/blink/web_tests/svg/dynamic-updates/SVGTextElement-svgdom-lengthAdjust-prop.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="resources/SVGTestCase.js"></script>
-<script src="../../resources/js-test.js"></script>
-<script src="../../paint/invalidation/resources/text-based-repaint.js"></script>
-</head>
-<body onload="runRepaintTest()">
-<h1>SVG 1.1 dynamic update tests</h1>
-<p id="description"></p>
-<div id="console"></div>
-<script src="script-tests/SVGTextElement-svgdom-lengthAdjust-prop.js"></script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/svg/dynamic-updates/script-tests/SVGTextElement-dom-lengthAdjust-attr.js b/third_party/blink/web_tests/svg/dynamic-updates/script-tests/SVGTextElement-dom-lengthAdjust-attr.js
deleted file mode 100644
index 61e7b87..0000000
--- a/third_party/blink/web_tests/svg/dynamic-updates/script-tests/SVGTextElement-dom-lengthAdjust-attr.js
+++ /dev/null
@@ -1,26 +0,0 @@
-// [Name] SVGTextElement-dom-lengthAdjust-attr.js
-// [Expected rendering result] Text streteched using a skew transformation with a length of 200 - and a series of PASS messages
-
-description("Tests dynamic updates of the 'lengthAdjust' attribute of the SVGTextElement object")
-createSVGTestCase();
-
-var textElement = createSVGElement("text");
-textElement.setAttribute("x", "0");
-textElement.setAttribute("y", "215");
-textElement.setAttribute("textLength", "200");
-textElement.textContent = "Stretched text";
-rootSVGElement.appendChild(textElement);
-
-shouldBeNull("textElement.getAttribute('lengthAdjust')");
-shouldBe("textElement.lengthAdjust.baseVal", "SVGTextContentElement.LENGTHADJUST_SPACING");
-shouldBe("textElement.textLength.baseVal.value", "200");
-shouldBeTrue("lastLength = textElement.getComputedTextLength(); lastLength > 0 && lastLength < 200");
-
-function repaintTest() {
-    textElement.setAttribute("lengthAdjust", "spacingAndGlyphs");
-    shouldBe("textElement.lengthAdjust.baseVal", "SVGTextContentElement.LENGTHADJUST_SPACINGANDGLYPHS");
-    shouldBe("textElement.textLength.baseVal.value", "200");
-    shouldBeTrue("textElement.getComputedTextLength() == lastLength");
-}
-
-var successfullyParsed = true;
diff --git a/third_party/blink/web_tests/svg/dynamic-updates/script-tests/SVGTextElement-svgdom-lengthAdjust-prop.js b/third_party/blink/web_tests/svg/dynamic-updates/script-tests/SVGTextElement-svgdom-lengthAdjust-prop.js
deleted file mode 100644
index b2f474f..0000000
--- a/third_party/blink/web_tests/svg/dynamic-updates/script-tests/SVGTextElement-svgdom-lengthAdjust-prop.js
+++ /dev/null
@@ -1,27 +0,0 @@
-// [Name] SVGTextElement-svgdom-lengthAdjust-prop.js
-// [Expected rendering result] Text streteched using a skew transformation with a length of 200 - and a series of PASS messages
-
-description("Tests dynamic updates of the 'lengthAdjust' property of the SVGTextElement object")
-createSVGTestCase();
-
-var textElement = createSVGElement("text");
-textElement.setAttribute("x", "0");
-textElement.setAttribute("y", "215");
-textElement.setAttribute("textLength", "200");
-textElement.textContent = "Stretched text";
-rootSVGElement.appendChild(textElement);
-
-shouldBeNull("textElement.getAttribute('lengthAdjust')");
-shouldBe("textElement.lengthAdjust.baseVal", "SVGTextContentElement.LENGTHADJUST_SPACING");
-shouldBe("textElement.textLength.baseVal.value", "200");
-shouldBeTrue("lastLength = textElement.getComputedTextLength(); lastLength > 0 && lastLength < 200");
-
-function repaintTest() {
-    textElement.lengthAdjust.baseVal = SVGTextContentElement.LENGTHADJUST_SPACINGANDGLYPHS;
-    shouldBeEqualToString("textElement.getAttribute('lengthAdjust')", "spacingAndGlyphs");
-    shouldBe("textElement.lengthAdjust.baseVal", "SVGTextContentElement.LENGTHADJUST_SPACINGANDGLYPHS");
-    shouldBe("textElement.textLength.baseVal.value", "200");
-    shouldBeTrue("textElement.getComputedTextLength() == lastLength");
-}
-
-var successfullyParsed = true;
diff --git a/third_party/blink/web_tests/virtual/plz-dedicated-worker/http/tests/devtools/network/network-worker-fetch-expected.txt b/third_party/blink/web_tests/virtual/plz-dedicated-worker/http/tests/devtools/network/network-worker-fetch-expected.txt
new file mode 100644
index 0000000..cd20610d
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/plz-dedicated-worker/http/tests/devtools/network/network-worker-fetch-expected.txt
@@ -0,0 +1,10 @@
+Tests fetch in worker.
+
+Fetch in worker result: Hello world
+http://127.0.0.1:8000/devtools/network/resources/fetch-worker.js
+resource.type: script
+request.failed: false
+http://127.0.0.1:8000/devtools/network/resources/resource.php
+resource.type: fetch
+request.failed: false
+
diff --git a/third_party/blink/web_tests/virtual/plz-dedicated-worker/http/tests/devtools/network/network-worker-fetch-parallel-expected.txt b/third_party/blink/web_tests/virtual/plz-dedicated-worker/http/tests/devtools/network/network-worker-fetch-parallel-expected.txt
new file mode 100644
index 0000000..e4c7f080
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/plz-dedicated-worker/http/tests/devtools/network/network-worker-fetch-parallel-expected.txt
@@ -0,0 +1,13 @@
+Test that parallel fetches in worker should not cause crash.
+
+Parallel fetch in worker result: ["Hello world","Hello world"]
+http://127.0.0.1:8000/devtools/network/resources/fetch-parallel-worker.js
+resource.type: script
+request.failed: false
+http://127.0.0.1:8000/devtools/network/resources/resource.php?1
+resource.type: fetch
+request.failed: false
+http://127.0.0.1:8000/devtools/network/resources/resource.php?2
+resource.type: fetch
+request.failed: false
+
diff --git a/third_party/closure_compiler/externs/developer_private.js b/third_party/closure_compiler/externs/developer_private.js
index 47f8cc75..9e2d155 100644
--- a/third_party/closure_compiler/externs/developer_private.js
+++ b/third_party/closure_compiler/externs/developer_private.js
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -7,7 +7,7 @@
 // NOTE: The format of types has changed. 'FooType' is now
 //   'chrome.developerPrivate.FooType'.
 // Please run the closure compiler before committing changes.
-// See https://chromium.googlesource.com/chromium/src/+/master/docs/closure_compilation.md
+// See https://chromium.googlesource.com/chromium/src/+/main/docs/closure_compilation.md
 
 /** @fileoverview Externs generated from namespace: developerPrivate */
 
@@ -426,6 +426,14 @@
 chrome.developerPrivate.LoadUnpackedOptions;
 
 /**
+ * @typedef {{
+ *   permittedSites: !Array<string>,
+ *   restrictedSites: !Array<string>
+ * }}
+ */
+chrome.developerPrivate.UserSiteSettings;
+
+/**
  * @enum {string}
  */
 chrome.developerPrivate.PackStatus = {
@@ -780,6 +788,13 @@
 chrome.developerPrivate.removeHostPermission = function(extensionId, host, callback) {};
 
 /**
+ * Returns the user specified site settings (which origins can extensions
+ * always/never run on) for the current profile.
+ * @param {function(!chrome.developerPrivate.UserSiteSettings): void=} callback
+ */
+chrome.developerPrivate.getUserSiteSettings = function(callback) {};
+
+/**
  * @param {string} id
  * @param {boolean} enabled
  * @param {function(): void=} callback
diff --git a/tools/binary_size/BUILD.gn b/tools/binary_size/BUILD.gn
index df429e2..1de82868 100644
--- a/tools/binary_size/BUILD.gn
+++ b/tools/binary_size/BUILD.gn
@@ -28,8 +28,8 @@
   group("caspian_all") {
     testonly = true
     deps = [
-      "//tools/binary_size/libsupersize/caspian:caspian_cli",
-      "//tools/binary_size/libsupersize/caspian:caspian_unittests",
+      "//tools/binary_size/libsupersize/viewer/caspian:caspian_cli",
+      "//tools/binary_size/libsupersize/viewer/caspian:caspian_unittests",
     ]
   }
 }
@@ -37,6 +37,6 @@
 # is_wasm is defined in BUILDCONFIG.gn only when wasmbuild.patch is applied.
 if (defined(is_wasm)) {
   group("caspian_web") {
-    deps = [ "//tools/binary_size/libsupersize/caspian:caspian_web(//build/toolchain/wasm:wasm)" ]
+    deps = [ "//tools/binary_size/libsupersize/viewer/caspian:caspian_web(//build/toolchain/wasm:wasm)" ]
   }
 }
diff --git a/tools/binary_size/libsupersize/.gitignore b/tools/binary_size/libsupersize/.gitignore
index 60c7ab4..9383d1e 100644
--- a/tools/binary_size/libsupersize/.gitignore
+++ b/tools/binary_size/libsupersize/.gitignore
@@ -1 +1 @@
-static/caspian_web*
+viewer/static/caspian_web*
diff --git a/tools/binary_size/libsupersize/caspian/diff.h b/tools/binary_size/libsupersize/caspian/diff.h
deleted file mode 100644
index 6bccdd1..0000000
--- a/tools/binary_size/libsupersize/caspian/diff.h
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef TOOLS_BINARY_SIZE_LIBSUPERSIZE_CASPIAN_DIFF_H_
-#define TOOLS_BINARY_SIZE_LIBSUPERSIZE_CASPIAN_DIFF_H_
-
-#include "tools/binary_size/libsupersize/caspian/model.h"
-
-namespace caspian {
-DeltaSizeInfo Diff(const SizeInfo* before, const SizeInfo* after);
-}
-
-#endif  // TOOLS_BINARY_SIZE_LIBSUPERSIZE_CASPIAN_DIFF_H_
diff --git a/tools/binary_size/libsupersize/static/README.md b/tools/binary_size/libsupersize/static/README.md
deleted file mode 100644
index 24f9f34..0000000
--- a/tools/binary_size/libsupersize/static/README.md
+++ /dev/null
@@ -1,9 +0,0 @@
-# SuperSize Tiger Viewer
-
-This is the source for SuperSize Tiger Viewer. It is deployed at
-https://chrome-supersize.firebaseapp.com.
-
-If you are a Googler, you can see this [doc][deploy doc] for how to deploy a new
-version of the viewer.
-
-[deploy doc]: https://docs.google.com/document/d/1qstcG9DxtwoohCnslvLs6Z7UfvO-dlkNi0s8PH-HYtI/edit?usp=sharing
diff --git a/tools/binary_size/libsupersize/viewer/README.md b/tools/binary_size/libsupersize/viewer/README.md
new file mode 100644
index 0000000..aa0ae4c
--- /dev/null
+++ b/tools/binary_size/libsupersize/viewer/README.md
@@ -0,0 +1,48 @@
+# SuperSize Tiger Viewer
+
+This is the source for SuperSize Tiger Viewer. The viewer runs entirely in
+browser and has no server component beyond static file serving. `.size` files
+are parsed using WebAssembly (`caspian/` directory) within a Web Worker, and
+node information is sent to the main page via JSON on-demand (when tree nodes
+are expanded).
+
+The project is deployed at https://chrome-supersize.firebaseapp.com. Googlers:
+see [this doc] for deployment instructions.
+
+To run the viewer locally:
+
+1. Install [Firebase CLI]
+2. Run `./upload_html_viewer.py --local`
+
+*** note
+**Note:** Authentication does not work when running locally, so fetching `.size`
+files from GCS does not work.
+***
+
+The WebAssembly files will be fetched from the deployed instance if you have
+not built them locally. To build them, see [caspian/README.md].
+
+[Firebase CLI]: https://firebase.google.com/docs/cli#install_the_firebase_cli
+[this doc]: https://docs.google.com/document/d/1qstcG9DxtwoohCnslvLs6Z7UfvO-dlkNi0s8PH-HYtI/edit?usp=sharing
+[caspian/README.md]: /tools/binary_size/libsupersize/viewer/caspian/README.md
+
+## Developer Overview
+
+### static/index.html
+
+This uses JSON files to populate the dropdowns:
+
+ * `gs://chrome-supersize/milestones/milestones.json`
+   * Updated by a Googler via: [`//tools/binary_size/generate_milestone_reports.py`]
+ * `gs://chrome-supersize/official_builds/canary_reports.json`
+   * Updated by official builders via: [`//tools/binary_size/generate_official_build_report.py`]
+
+All `.size` files pointed to by this launcher are restricted to Googlers.
+
+[`//tools/binary_size/generate_milestone_reports.py`] /tools/binary_size/generate_milestone_reports.py
+[`//tools/binary_size/generate_official_build_report.py`] /tools/binary_size/generate_official_build_report.py
+
+### static/viewer.html
+
+This is the viewer webapp. It uses a service worker (`sw.js`) and app manifest
+(`manifest.json`) to be more slick (and work offline).
diff --git a/tools/binary_size/libsupersize/caspian/BUILD.gn b/tools/binary_size/libsupersize/viewer/caspian/BUILD.gn
similarity index 100%
rename from tools/binary_size/libsupersize/caspian/BUILD.gn
rename to tools/binary_size/libsupersize/viewer/caspian/BUILD.gn
diff --git a/tools/binary_size/libsupersize/caspian/DEPS b/tools/binary_size/libsupersize/viewer/caspian/DEPS
similarity index 100%
rename from tools/binary_size/libsupersize/caspian/DEPS
rename to tools/binary_size/libsupersize/viewer/caspian/DEPS
diff --git a/tools/binary_size/libsupersize/caspian/README.md b/tools/binary_size/libsupersize/viewer/caspian/README.md
similarity index 75%
rename from tools/binary_size/libsupersize/caspian/README.md
rename to tools/binary_size/libsupersize/viewer/caspian/README.md
index 3b37625d..2ee4ce4 100644
--- a/tools/binary_size/libsupersize/caspian/README.md
+++ b/tools/binary_size/libsupersize/viewer/caspian/README.md
@@ -9,15 +9,15 @@
 Caspian needs some minor edits that we don't want to commit:
 
 ```sh
-git apply -3 tools/binary_size/libsupersize/caspian/wasmbuild.patch
+git apply -3 tools/binary_size/libsupersize/viewer/caspian/wasmbuild.patch
 ```
 
 To re-create .patch file:
 ```sh
 git add ...files to include in patch...
-git diff --staged > tools/binary_size/libsupersize/caspian/wasmbuild.patch
+git diff --staged > tools/binary_size/libsupersize/viewer/caspian/wasmbuild.patch
 # Double check that only expected files are included in the patch:
-grep +++ tools/binary_size/libsupersize/caspian/wasmbuild.patch
+grep +++ tools/binary_size/libsupersize/viewer/caspian/wasmbuild.patch
 ```
 
 ## Building the test app & tests
@@ -48,13 +48,3 @@
 gn gen out/caspian --args='is_official_build=true treat_warnings_as_errors=false fatal_linker_warnings=false chrome_pgo_phase=0'
 ( cd out/caspian; autoninja caspian_web && cp wasm/caspian_web.* ../../tools/binary_size/libsupersize/static/ )
 ```
-
-Run local test server:
-```sh
-tools/binary_size/libsupersize/upload_html_viewer.py --local
-```
-
-Deploy to firebase:
-```sh
-tools/binary_size/libsupersize/upload_html_viewer.py [--prod | --staging]
-```
diff --git a/tools/binary_size/libsupersize/caspian/caspian_web.cc b/tools/binary_size/libsupersize/viewer/caspian/caspian_web.cc
similarity index 95%
rename from tools/binary_size/libsupersize/caspian/caspian_web.cc
rename to tools/binary_size/libsupersize/viewer/caspian/caspian_web.cc
index 0a465e5..f24ffd2a 100644
--- a/tools/binary_size/libsupersize/caspian/caspian_web.cc
+++ b/tools/binary_size/libsupersize/viewer/caspian/caspian_web.cc
@@ -15,11 +15,11 @@
 
 #include "third_party/jsoncpp/source/include/json/json.h"
 #include "third_party/re2/src/re2/re2.h"
-#include "tools/binary_size/libsupersize/caspian/diff.h"
-#include "tools/binary_size/libsupersize/caspian/file_format.h"
-#include "tools/binary_size/libsupersize/caspian/lens.h"
-#include "tools/binary_size/libsupersize/caspian/model.h"
-#include "tools/binary_size/libsupersize/caspian/tree_builder.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/diff.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/file_format.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/lens.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/model.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/tree_builder.h"
 
 namespace caspian {
 namespace {
diff --git a/tools/binary_size/libsupersize/caspian/cli.cc b/tools/binary_size/libsupersize/viewer/caspian/cli.cc
similarity index 93%
rename from tools/binary_size/libsupersize/caspian/cli.cc
rename to tools/binary_size/libsupersize/viewer/caspian/cli.cc
index d8954c24..541d8d9 100644
--- a/tools/binary_size/libsupersize/caspian/cli.cc
+++ b/tools/binary_size/libsupersize/viewer/caspian/cli.cc
@@ -10,9 +10,9 @@
 #include <fstream>
 #include <iostream>
 
-#include "tools/binary_size/libsupersize/caspian/diff.h"
-#include "tools/binary_size/libsupersize/caspian/file_format.h"
-#include "tools/binary_size/libsupersize/caspian/model.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/diff.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/file_format.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/model.h"
 
 void ParseSizeInfoFromFile(const char* filename, caspian::SizeInfo* info) {
   std::ifstream ifs(filename, std::ifstream::in);
diff --git a/tools/binary_size/libsupersize/caspian/diff.cc b/tools/binary_size/libsupersize/viewer/caspian/diff.cc
similarity index 96%
rename from tools/binary_size/libsupersize/caspian/diff.cc
rename to tools/binary_size/libsupersize/viewer/caspian/diff.cc
index 72ca321..42cb6ed 100644
--- a/tools/binary_size/libsupersize/caspian/diff.cc
+++ b/tools/binary_size/libsupersize/viewer/caspian/diff.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "tools/binary_size/libsupersize/caspian/diff.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/diff.h"
 
 #include <deque>
 #include <functional>
@@ -216,10 +216,10 @@
   // symbols.  Any symbols still unmatched are tried in the next round.
   int step = 0;
   DiffHelper helper;
-  std::vector<DiffHelper::MatchFunc>
-      key_funcs = {helper.SectionAndFullNameAndPathAndSize(),
-                   helper.SectionAndFullNameAndPath(),
-                   helper.SectionAndNameAndPath(), helper.SectionAndFullName()};
+  std::vector<DiffHelper::MatchFunc> key_funcs = {
+      helper.SectionAndFullNameAndPathAndSize(),
+      helper.SectionAndFullNameAndPath(), helper.SectionAndNameAndPath(),
+      helper.SectionAndFullName()};
   std::unordered_map<SectionId, float> padding_by_section_name;
   for (const auto& key_function : key_funcs) {
     int n_matched_symbols =
diff --git a/tools/binary_size/libsupersize/viewer/caspian/diff.h b/tools/binary_size/libsupersize/viewer/caspian/diff.h
new file mode 100644
index 0000000..dfeca7ed
--- /dev/null
+++ b/tools/binary_size/libsupersize/viewer/caspian/diff.h
@@ -0,0 +1,14 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TOOLS_BINARY_SIZE_LIBSUPERSIZE_VIEWER_CASPIAN_DIFF_H_
+#define TOOLS_BINARY_SIZE_LIBSUPERSIZE_VIEWER_CASPIAN_DIFF_H_
+
+#include "tools/binary_size/libsupersize/viewer/caspian/model.h"
+
+namespace caspian {
+DeltaSizeInfo Diff(const SizeInfo* before, const SizeInfo* after);
+}
+
+#endif  // TOOLS_BINARY_SIZE_LIBSUPERSIZE_VIEWER_CASPIAN_DIFF_H_
diff --git a/tools/binary_size/libsupersize/caspian/diff_test.cc b/tools/binary_size/libsupersize/viewer/caspian/diff_test.cc
similarity index 98%
rename from tools/binary_size/libsupersize/caspian/diff_test.cc
rename to tools/binary_size/libsupersize/viewer/caspian/diff_test.cc
index a924576..39fd8ca9 100644
--- a/tools/binary_size/libsupersize/caspian/diff_test.cc
+++ b/tools/binary_size/libsupersize/viewer/caspian/diff_test.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "tools/binary_size/libsupersize/caspian/diff.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/diff.h"
 
 #include <stdint.h>
 
@@ -14,7 +14,7 @@
 #include <vector>
 
 #include "testing/gtest/include/gtest/gtest.h"
-#include "tools/binary_size/libsupersize/caspian/model.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/model.h"
 
 namespace caspian {
 namespace {
diff --git a/tools/binary_size/libsupersize/caspian/file_format.cc b/tools/binary_size/libsupersize/viewer/caspian/file_format.cc
similarity index 98%
rename from tools/binary_size/libsupersize/caspian/file_format.cc
rename to tools/binary_size/libsupersize/viewer/caspian/file_format.cc
index 5634422..c7951a36 100644
--- a/tools/binary_size/libsupersize/caspian/file_format.cc
+++ b/tools/binary_size/libsupersize/viewer/caspian/file_format.cc
@@ -6,7 +6,7 @@
  * The .size file spec is found in libsupersize/file_format.py
  */
 
-#include "tools/binary_size/libsupersize/caspian/file_format.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/file_format.h"
 
 #include <assert.h>
 #include <stdint.h>
@@ -23,7 +23,7 @@
 
 #include "third_party/jsoncpp/source/include/json/json.h"
 #include "third_party/zlib/google/compression_utils_portable.h"
-#include "tools/binary_size/libsupersize/caspian/model.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/model.h"
 
 namespace {
 const char kDiffHeader[] = "# Created by //tools/binary_size\nDIFF\n";
diff --git a/tools/binary_size/libsupersize/caspian/file_format.h b/tools/binary_size/libsupersize/viewer/caspian/file_format.h
similarity index 76%
rename from tools/binary_size/libsupersize/caspian/file_format.h
rename to tools/binary_size/libsupersize/viewer/caspian/file_format.h
index 1564fe69..ca7ad04 100644
--- a/tools/binary_size/libsupersize/caspian/file_format.h
+++ b/tools/binary_size/libsupersize/viewer/caspian/file_format.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef TOOLS_BINARY_SIZE_LIBSUPERSIZE_CASPIAN_FILE_FORMAT_H_
-#define TOOLS_BINARY_SIZE_LIBSUPERSIZE_CASPIAN_FILE_FORMAT_H_
+#ifndef TOOLS_BINARY_SIZE_LIBSUPERSIZE_VIEWER_CASPIAN_FILE_FORMAT_H_
+#define TOOLS_BINARY_SIZE_LIBSUPERSIZE_VIEWER_CASPIAN_FILE_FORMAT_H_
 
 namespace caspian {
 
@@ -23,4 +23,4 @@
 
 }  // namespace caspian
 
-#endif  // TOOLS_BINARY_SIZE_LIBSUPERSIZE_CASPIAN_FILE_FORMAT_H_
+#endif  // TOOLS_BINARY_SIZE_LIBSUPERSIZE_VIEWER_CASPIAN_FILE_FORMAT_H_
diff --git a/tools/binary_size/libsupersize/caspian/function_signature.cc b/tools/binary_size/libsupersize/viewer/caspian/function_signature.cc
similarity index 99%
rename from tools/binary_size/libsupersize/caspian/function_signature.cc
rename to tools/binary_size/libsupersize/viewer/caspian/function_signature.cc
index d0a2f3a8..6aabcba 100644
--- a/tools/binary_size/libsupersize/caspian/function_signature.cc
+++ b/tools/binary_size/libsupersize/viewer/caspian/function_signature.cc
@@ -15,7 +15,7 @@
 #include <tuple>
 #include <vector>
 
-#include "tools/binary_size/libsupersize/caspian/function_signature.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/function_signature.h"
 
 namespace {
 bool EndsWith(std::string_view str,
diff --git a/tools/binary_size/libsupersize/caspian/function_signature.h b/tools/binary_size/libsupersize/viewer/caspian/function_signature.h
similarity index 90%
rename from tools/binary_size/libsupersize/caspian/function_signature.h
rename to tools/binary_size/libsupersize/viewer/caspian/function_signature.h
index 78996e9..96fa6908 100644
--- a/tools/binary_size/libsupersize/caspian/function_signature.h
+++ b/tools/binary_size/libsupersize/viewer/caspian/function_signature.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef TOOLS_BINARY_SIZE_LIBSUPERSIZE_CASPIAN_FUNCTION_SIGNATURE_H_
-#define TOOLS_BINARY_SIZE_LIBSUPERSIZE_CASPIAN_FUNCTION_SIGNATURE_H_
+#ifndef TOOLS_BINARY_SIZE_LIBSUPERSIZE_VIEWER_CASPIAN_FUNCTION_SIGNATURE_H_
+#define TOOLS_BINARY_SIZE_LIBSUPERSIZE_VIEWER_CASPIAN_FUNCTION_SIGNATURE_H_
 
 #include <deque>
 #include <string>
@@ -57,4 +57,4 @@
 std::string StripTemplateArgs(std::string_view name);
 }  // namespace caspian
 
-#endif  // TOOLS_BINARY_SIZE_LIBSUPERSIZE_CASPIAN_FUNCTION_SIGNATURE_H_
+#endif  // TOOLS_BINARY_SIZE_LIBSUPERSIZE_VIEWER_CASPIAN_FUNCTION_SIGNATURE_H_
diff --git a/tools/binary_size/libsupersize/caspian/function_signature_test.cc b/tools/binary_size/libsupersize/viewer/caspian/function_signature_test.cc
similarity index 99%
rename from tools/binary_size/libsupersize/caspian/function_signature_test.cc
rename to tools/binary_size/libsupersize/viewer/caspian/function_signature_test.cc
index ae73fb18..3cad26f 100644
--- a/tools/binary_size/libsupersize/caspian/function_signature_test.cc
+++ b/tools/binary_size/libsupersize/viewer/caspian/function_signature_test.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "tools/binary_size/libsupersize/caspian/function_signature.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/function_signature.h"
 
 #include <string>
 #include <string_view>
diff --git a/tools/binary_size/libsupersize/caspian/grouped_path.cc b/tools/binary_size/libsupersize/viewer/caspian/grouped_path.cc
similarity index 96%
rename from tools/binary_size/libsupersize/caspian/grouped_path.cc
rename to tools/binary_size/libsupersize/viewer/caspian/grouped_path.cc
index 6330f885..390e952b 100644
--- a/tools/binary_size/libsupersize/caspian/grouped_path.cc
+++ b/tools/binary_size/libsupersize/viewer/caspian/grouped_path.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "tools/binary_size/libsupersize/caspian/grouped_path.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/grouped_path.h"
 
 #include <stdint.h>
 
diff --git a/tools/binary_size/libsupersize/caspian/grouped_path.h b/tools/binary_size/libsupersize/viewer/caspian/grouped_path.h
similarity index 85%
rename from tools/binary_size/libsupersize/caspian/grouped_path.h
rename to tools/binary_size/libsupersize/viewer/caspian/grouped_path.h
index 277962a5..d8341da 100644
--- a/tools/binary_size/libsupersize/caspian/grouped_path.h
+++ b/tools/binary_size/libsupersize/viewer/caspian/grouped_path.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef TOOLS_BINARY_SIZE_LIBSUPERSIZE_CASPIAN_GROUPED_PATH_H_
-#define TOOLS_BINARY_SIZE_LIBSUPERSIZE_CASPIAN_GROUPED_PATH_H_
+#ifndef TOOLS_BINARY_SIZE_LIBSUPERSIZE_VIEWER_CASPIAN_GROUPED_PATH_H_
+#define TOOLS_BINARY_SIZE_LIBSUPERSIZE_VIEWER_CASPIAN_GROUPED_PATH_H_
 
 #include <stddef.h>
 
@@ -50,11 +50,11 @@
 namespace std {
 template <>
 struct hash<caspian::GroupedPath> {
-  std::size_t operator()(const caspian::GroupedPath& grouped_path) const
-      noexcept {
+  std::size_t operator()(
+      const caspian::GroupedPath& grouped_path) const noexcept {
     return std::hash<std::string_view>{}(grouped_path.group) ^
            std::hash<std::string_view>{}(grouped_path.path);
   }
 };
 }  // namespace std
-#endif  // TOOLS_BINARY_SIZE_LIBSUPERSIZE_CASPIAN_GROUPED_PATH_H_
+#endif  // TOOLS_BINARY_SIZE_LIBSUPERSIZE_VIEWER_CASPIAN_GROUPED_PATH_H_
diff --git a/tools/binary_size/libsupersize/caspian/grouped_path_test.cc b/tools/binary_size/libsupersize/viewer/caspian/grouped_path_test.cc
similarity index 95%
rename from tools/binary_size/libsupersize/caspian/grouped_path_test.cc
rename to tools/binary_size/libsupersize/viewer/caspian/grouped_path_test.cc
index 77f41ac..43bef0a 100644
--- a/tools/binary_size/libsupersize/caspian/grouped_path_test.cc
+++ b/tools/binary_size/libsupersize/viewer/caspian/grouped_path_test.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "tools/binary_size/libsupersize/caspian/grouped_path.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/grouped_path.h"
 
 #include <stdint.h>
 
 #include <vector>
 
 #include "testing/gtest/include/gtest/gtest.h"
-#include "tools/binary_size/libsupersize/caspian/model.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/model.h"
 
 namespace caspian {
 namespace {
diff --git a/tools/binary_size/libsupersize/caspian/lens.cc b/tools/binary_size/libsupersize/viewer/caspian/lens.cc
similarity index 96%
rename from tools/binary_size/libsupersize/caspian/lens.cc
rename to tools/binary_size/libsupersize/viewer/caspian/lens.cc
index 16cc2dc1f..7f238b5 100644
--- a/tools/binary_size/libsupersize/caspian/lens.cc
+++ b/tools/binary_size/libsupersize/viewer/caspian/lens.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "tools/binary_size/libsupersize/caspian/lens.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/lens.h"
 
 #include <string>
 
 #include "third_party/re2/src/re2/re2.h"
-#include "tools/binary_size/libsupersize/caspian/model.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/model.h"
 
 namespace {
 
diff --git a/tools/binary_size/libsupersize/caspian/lens.h b/tools/binary_size/libsupersize/viewer/caspian/lens.h
similarity index 83%
rename from tools/binary_size/libsupersize/caspian/lens.h
rename to tools/binary_size/libsupersize/viewer/caspian/lens.h
index f9243594..7604499 100644
--- a/tools/binary_size/libsupersize/caspian/lens.h
+++ b/tools/binary_size/libsupersize/viewer/caspian/lens.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef TOOLS_BINARY_SIZE_LIBSUPERSIZE_CASPIAN_LENS_H_
-#define TOOLS_BINARY_SIZE_LIBSUPERSIZE_CASPIAN_LENS_H_
+#ifndef TOOLS_BINARY_SIZE_LIBSUPERSIZE_VIEWER_CASPIAN_LENS_H_
+#define TOOLS_BINARY_SIZE_LIBSUPERSIZE_VIEWER_CASPIAN_LENS_H_
 
 #include <string_view>
 
@@ -42,4 +42,4 @@
 };
 }  // namespace caspian
 
-#endif  // TOOLS_BINARY_SIZE_LIBSUPERSIZE_CASPIAN_LENS_H_
+#endif  // TOOLS_BINARY_SIZE_LIBSUPERSIZE_VIEWER_CASPIAN_LENS_H_
diff --git a/tools/binary_size/libsupersize/caspian/lens_test.cc b/tools/binary_size/libsupersize/viewer/caspian/lens_test.cc
similarity index 95%
rename from tools/binary_size/libsupersize/caspian/lens_test.cc
rename to tools/binary_size/libsupersize/viewer/caspian/lens_test.cc
index d99185f..17455782 100644
--- a/tools/binary_size/libsupersize/caspian/lens_test.cc
+++ b/tools/binary_size/libsupersize/viewer/caspian/lens_test.cc
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "tools/binary_size/libsupersize/caspian/lens.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/lens.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
-#include "tools/binary_size/libsupersize/caspian/model.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/model.h"
 
 namespace caspian {
 
diff --git a/tools/binary_size/libsupersize/caspian/model.cc b/tools/binary_size/libsupersize/viewer/caspian/model.cc
similarity index 98%
rename from tools/binary_size/libsupersize/caspian/model.cc
rename to tools/binary_size/libsupersize/viewer/caspian/model.cc
index 348e89a..5a0c3d2 100644
--- a/tools/binary_size/libsupersize/caspian/model.cc
+++ b/tools/binary_size/libsupersize/viewer/caspian/model.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "tools/binary_size/libsupersize/caspian/model.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/model.h"
 
 #include <algorithm>
 #include <iostream>
@@ -11,8 +11,8 @@
 #include <tuple>
 #include <unordered_map>
 
-#include "tools/binary_size/libsupersize/caspian/file_format.h"
-#include "tools/binary_size/libsupersize/caspian/function_signature.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/file_format.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/function_signature.h"
 
 namespace caspian {
 
diff --git a/tools/binary_size/libsupersize/caspian/model.h b/tools/binary_size/libsupersize/viewer/caspian/model.h
similarity index 97%
rename from tools/binary_size/libsupersize/caspian/model.h
rename to tools/binary_size/libsupersize/viewer/caspian/model.h
index 7430a74a..c01296f 100644
--- a/tools/binary_size/libsupersize/caspian/model.h
+++ b/tools/binary_size/libsupersize/viewer/caspian/model.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef TOOLS_BINARY_SIZE_LIBSUPERSIZE_CASPIAN_MODEL_H_
-#define TOOLS_BINARY_SIZE_LIBSUPERSIZE_CASPIAN_MODEL_H_
+#ifndef TOOLS_BINARY_SIZE_LIBSUPERSIZE_VIEWER_CASPIAN_MODEL_H_
+#define TOOLS_BINARY_SIZE_LIBSUPERSIZE_VIEWER_CASPIAN_MODEL_H_
 
 #include <stdint.h>
 #include <stdlib.h>
@@ -18,7 +18,7 @@
 #include <vector>
 
 #include "third_party/jsoncpp/source/include/json/json.h"
-#include "tools/binary_size/libsupersize/caspian/grouped_path.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/grouped_path.h"
 
 // Copied from representation in tools/binary_size/libsupersize/models.py
 
@@ -380,4 +380,4 @@
 };
 
 }  // namespace caspian
-#endif  // TOOLS_BINARY_SIZE_LIBSUPERSIZE_CASPIAN_MODEL_H_
+#endif  // TOOLS_BINARY_SIZE_LIBSUPERSIZE_VIEWER_CASPIAN_MODEL_H_
diff --git a/tools/binary_size/libsupersize/caspian/tree_builder.cc b/tools/binary_size/libsupersize/viewer/caspian/tree_builder.cc
similarity index 99%
rename from tools/binary_size/libsupersize/caspian/tree_builder.cc
rename to tools/binary_size/libsupersize/viewer/caspian/tree_builder.cc
index c1b511c..1f9c29d 100644
--- a/tools/binary_size/libsupersize/caspian/tree_builder.cc
+++ b/tools/binary_size/libsupersize/viewer/caspian/tree_builder.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "tools/binary_size/libsupersize/caspian/tree_builder.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/tree_builder.h"
 
 #include <algorithm>
 #include <iostream>
diff --git a/tools/binary_size/libsupersize/caspian/tree_builder.h b/tools/binary_size/libsupersize/viewer/caspian/tree_builder.h
similarity index 86%
rename from tools/binary_size/libsupersize/caspian/tree_builder.h
rename to tools/binary_size/libsupersize/viewer/caspian/tree_builder.h
index 2a1e4cc..c4ea9e7 100644
--- a/tools/binary_size/libsupersize/caspian/tree_builder.h
+++ b/tools/binary_size/libsupersize/viewer/caspian/tree_builder.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef TOOLS_BINARY_SIZE_LIBSUPERSIZE_CASPIAN_TREE_BUILDER_H_
-#define TOOLS_BINARY_SIZE_LIBSUPERSIZE_CASPIAN_TREE_BUILDER_H_
+#ifndef TOOLS_BINARY_SIZE_LIBSUPERSIZE_VIEWER_CASPIAN_TREE_BUILDER_H_
+#define TOOLS_BINARY_SIZE_LIBSUPERSIZE_VIEWER_CASPIAN_TREE_BUILDER_H_
 
 #include <deque>
 #include <functional>
@@ -13,8 +13,8 @@
 #include <unordered_map>
 #include <vector>
 
-#include "tools/binary_size/libsupersize/caspian/lens.h"
-#include "tools/binary_size/libsupersize/caspian/model.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/lens.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/model.h"
 
 namespace caspian {
 class TreeBuilder {
@@ -68,4 +68,4 @@
   std::vector<const BaseSymbol*> symbols_;
 };  // TreeBuilder
 }  // namespace caspian
-#endif  // TOOLS_BINARY_SIZE_LIBSUPERSIZE_CASPIAN_TREE_BUILDER_H_
+#endif  // TOOLS_BINARY_SIZE_LIBSUPERSIZE_VIEWER_CASPIAN_TREE_BUILDER_H_
diff --git a/tools/binary_size/libsupersize/caspian/tree_builder_test.cc b/tools/binary_size/libsupersize/viewer/caspian/tree_builder_test.cc
similarity index 97%
rename from tools/binary_size/libsupersize/caspian/tree_builder_test.cc
rename to tools/binary_size/libsupersize/viewer/caspian/tree_builder_test.cc
index a30bc10..a7cc00a 100644
--- a/tools/binary_size/libsupersize/caspian/tree_builder_test.cc
+++ b/tools/binary_size/libsupersize/viewer/caspian/tree_builder_test.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "tools/binary_size/libsupersize/caspian/tree_builder.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/tree_builder.h"
 
 #include <stdint.h>
 
@@ -14,7 +14,7 @@
 #include <vector>
 
 #include "testing/gtest/include/gtest/gtest.h"
-#include "tools/binary_size/libsupersize/caspian/model.h"
+#include "tools/binary_size/libsupersize/viewer/caspian/model.h"
 
 namespace caspian {
 
diff --git a/tools/binary_size/libsupersize/caspian/wasmbuild.patch b/tools/binary_size/libsupersize/viewer/caspian/wasmbuild.patch
similarity index 80%
rename from tools/binary_size/libsupersize/caspian/wasmbuild.patch
rename to tools/binary_size/libsupersize/viewer/caspian/wasmbuild.patch
index c987bdbc..d1f69e21 100644
--- a/tools/binary_size/libsupersize/caspian/wasmbuild.patch
+++ b/tools/binary_size/libsupersize/viewer/caspian/wasmbuild.patch
@@ -1,8 +1,8 @@
 diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
-index 652b179ee12af..7aa64c0ffa77e 100644
+index fcc7e12834733..11d4044003cb3 100644
 --- a/build/config/BUILDCONFIG.gn
 +++ b/build/config/BUILDCONFIG.gn
-@@ -295,10 +295,11 @@ is_ios = current_os == "ios"
+@@ -299,10 +299,11 @@ is_ios = current_os == "ios"
  is_linux = current_os == "linux"
  is_mac = current_os == "mac"
  is_nacl = current_os == "nacl"
@@ -16,10 +16,10 @@
  # =============================================================================
  # TARGET DEFAULTS
 diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
-index 5de2cf037449f..ebe9076e7378c 100644
+index e49fc28c0893d..413da046c6b4c 100644
 --- a/build/config/compiler/BUILD.gn
 +++ b/build/config/compiler/BUILD.gn
-@@ -633,6 +633,20 @@ config("compiler") {
+@@ -643,6 +643,20 @@ config("compiler") {
      ldflags += [ "-stdlib=libc++" ]
    }
  
@@ -40,7 +40,7 @@
    # Add flags for link-time optimization. These flags enable
    # optimizations/transformations that require whole-program visibility at link
    # time, so they need to be applied to all translation units, and we may end up
-@@ -747,9 +761,7 @@ config("compiler") {
+@@ -758,9 +772,7 @@ config("compiler") {
    if (use_lld && !enable_call_graph_profile_sort) {
      if (is_win) {
        ldflags += [ "/call-graph-profile-sort:no" ]
@@ -51,17 +51,18 @@
        ldflags += [ "-Wl,--no-call-graph-profile-sort" ]
      }
    }
-@@ -1509,7 +1521,8 @@ config("default_warnings") {
-         cflags += [ "-Wno-null-pointer-subtraction" ]
-       }
+@@ -1523,6 +1535,10 @@ config("default_warnings") {
+         "-Wno-ignored-pragma-optimize",
+       ]
  
--      if (current_toolchain == host_toolchain || !use_xcode_clang) {
-+      if ((current_toolchain == host_toolchain || !use_xcode_clang) &&
-+          !is_wasm) {
-         # Flags Xcode 9.2 (Clang clang-900.0.39.2) does not recognize.
-         cflags += [
-           "-Wenum-compare-conditional",
-@@ -2229,6 +2242,9 @@ config("symbols") {
++      if (is_wasm) {
++        cflags -= [ "-Wenum-compare-conditional" ]
++      }
++
+       if (is_chromeos || default_toolchain == "//build/toolchain/cros:target") {
+         # TODO(https://crbug.com/1016945): Re-enable once ChromeOS toolchain is up to date
+         cflags += [ "-Wno-builtin-assume-aligned-alignment" ]
+@@ -2294,6 +2310,9 @@ config("symbols") {
  
      # All configs using /DEBUG should include this:
      configs = [ ":win_pdbaltpath" ]
@@ -72,10 +73,10 @@
      cflags = []
      if (is_mac && enable_dsyms) {
 diff --git a/build/toolchain/toolchain.gni b/build/toolchain/toolchain.gni
-index 6d8f162d82fa5..e75759ac81860 100644
+index b2d0b44b102c6..eb6de8775dff7 100644
 --- a/build/toolchain/toolchain.gni
 +++ b/build/toolchain/toolchain.gni
-@@ -58,6 +58,9 @@ if (is_apple) {
+@@ -47,6 +47,9 @@ if (is_apple) {
    shlib_extension = ".so"
  } else if (is_win) {
    shlib_extension = ".dll"
diff --git a/tools/binary_size/libsupersize/static/auth-consts.js b/tools/binary_size/libsupersize/viewer/static/auth-consts.js
similarity index 74%
rename from tools/binary_size/libsupersize/static/auth-consts.js
rename to tools/binary_size/libsupersize/viewer/static/auth-consts.js
index e7a0b23..0fe1506 100644
--- a/tools/binary_size/libsupersize/static/auth-consts.js
+++ b/tools/binary_size/libsupersize/viewer/static/auth-consts.js
@@ -5,7 +5,9 @@
 // @ts-check
 'use strict';
 
-const AUTH_CLIENT_ID = '84462612899-hsikvugfjv36k8nt8459b7at62hi9sba.apps.googleusercontent.com';
+const AUTH_CLIENT_ID = '84462612899-hsikvugfjv36k8nt8459b7at62hi9sba' +
+    '.apps.googleusercontent.com';
 const AUTH_SCOPE = 'https://www.googleapis.com/auth/devstorage.read_only';
-const AUTH_DISCOVERY_URL = 'https://www.googleapis.com/discovery/v1/apis/storage/v1/rest';
+const AUTH_DISCOVERY_URL =
+    'https://www.googleapis.com/discovery/v1/apis/storage/v1/rest';
 const STORAGE_API_ENDPOINT = 'https://storage.googleapis.com/storage/v1';
diff --git a/tools/binary_size/libsupersize/static/auth.js b/tools/binary_size/libsupersize/viewer/static/auth.js
similarity index 100%
rename from tools/binary_size/libsupersize/static/auth.js
rename to tools/binary_size/libsupersize/viewer/static/auth.js
diff --git a/tools/binary_size/libsupersize/static/favicon.ico b/tools/binary_size/libsupersize/viewer/static/favicon.ico
similarity index 100%
rename from tools/binary_size/libsupersize/static/favicon.ico
rename to tools/binary_size/libsupersize/viewer/static/favicon.ico
Binary files differ
diff --git a/tools/binary_size/libsupersize/static/index.html b/tools/binary_size/libsupersize/viewer/static/index.html
similarity index 100%
rename from tools/binary_size/libsupersize/static/index.html
rename to tools/binary_size/libsupersize/viewer/static/index.html
diff --git a/tools/binary_size/libsupersize/static/index.js b/tools/binary_size/libsupersize/viewer/static/index.js
similarity index 100%
rename from tools/binary_size/libsupersize/static/index.js
rename to tools/binary_size/libsupersize/viewer/static/index.js
diff --git a/tools/binary_size/libsupersize/static/infocard-ui.js b/tools/binary_size/libsupersize/viewer/static/infocard-ui.js
similarity index 100%
rename from tools/binary_size/libsupersize/static/infocard-ui.js
rename to tools/binary_size/libsupersize/viewer/static/infocard-ui.js
diff --git a/tools/binary_size/libsupersize/static/infocard.css b/tools/binary_size/libsupersize/viewer/static/infocard.css
similarity index 100%
rename from tools/binary_size/libsupersize/static/infocard.css
rename to tools/binary_size/libsupersize/viewer/static/infocard.css
diff --git a/tools/binary_size/libsupersize/static/main.css b/tools/binary_size/libsupersize/viewer/static/main.css
similarity index 100%
rename from tools/binary_size/libsupersize/static/main.css
rename to tools/binary_size/libsupersize/viewer/static/main.css
diff --git a/tools/binary_size/libsupersize/static/manifest.json b/tools/binary_size/libsupersize/viewer/static/manifest.json
similarity index 100%
rename from tools/binary_size/libsupersize/static/manifest.json
rename to tools/binary_size/libsupersize/viewer/static/manifest.json
diff --git a/tools/binary_size/libsupersize/static/options.css b/tools/binary_size/libsupersize/viewer/static/options.css
similarity index 100%
rename from tools/binary_size/libsupersize/static/options.css
rename to tools/binary_size/libsupersize/viewer/static/options.css
diff --git a/tools/binary_size/libsupersize/static/shared.js b/tools/binary_size/libsupersize/viewer/static/shared.js
similarity index 100%
rename from tools/binary_size/libsupersize/static/shared.js
rename to tools/binary_size/libsupersize/viewer/static/shared.js
diff --git a/tools/binary_size/libsupersize/static/splash.png b/tools/binary_size/libsupersize/viewer/static/splash.png
similarity index 100%
rename from tools/binary_size/libsupersize/static/splash.png
rename to tools/binary_size/libsupersize/viewer/static/splash.png
Binary files differ
diff --git a/tools/binary_size/libsupersize/static/start-worker.js b/tools/binary_size/libsupersize/viewer/static/start-worker.js
similarity index 98%
rename from tools/binary_size/libsupersize/static/start-worker.js
rename to tools/binary_size/libsupersize/viewer/static/start-worker.js
index 4e7c05e..579dc53 100644
--- a/tools/binary_size/libsupersize/static/start-worker.js
+++ b/tools/binary_size/libsupersize/viewer/static/start-worker.js
@@ -108,6 +108,7 @@
         window.supersize.worker.loadTree('from-url://',
           authResponse.access_token));
   } else {
-    window.supersize.treeReady = window.supersize.worker.loadTree('from-url://');
+    window.supersize.treeReady = window.supersize.worker.loadTree(
+        'from-url://');
   }
 })()
diff --git a/tools/binary_size/libsupersize/static/state.js b/tools/binary_size/libsupersize/viewer/static/state.js
similarity index 100%
rename from tools/binary_size/libsupersize/static/state.js
rename to tools/binary_size/libsupersize/viewer/static/state.js
diff --git a/tools/binary_size/libsupersize/static/tree-ui.js b/tools/binary_size/libsupersize/viewer/static/tree-ui.js
similarity index 100%
rename from tools/binary_size/libsupersize/static/tree-ui.js
rename to tools/binary_size/libsupersize/viewer/static/tree-ui.js
diff --git a/tools/binary_size/libsupersize/static/tree-worker-wasm.js b/tools/binary_size/libsupersize/viewer/static/tree-worker-wasm.js
similarity index 97%
rename from tools/binary_size/libsupersize/static/tree-worker-wasm.js
rename to tools/binary_size/libsupersize/viewer/static/tree-worker-wasm.js
index 202bc165..78fa6422 100644
--- a/tools/binary_size/libsupersize/static/tree-worker-wasm.js
+++ b/tools/binary_size/libsupersize/viewer/static/tree-worker-wasm.js
@@ -108,9 +108,9 @@
 }
 
 function parseGoogleCloudStorageUrl(url) {
-  const re = /^https:\/\/storage\.googleapis\.com\/(?<bucket>[^\/]+)\/(?<file>.+)/;
+  const re = /^https:\/\/storage\.googleapis\.com\/(?<bkt>[^\/]+)\/(?<file>.+)/;
   const match = re.exec(url);
-  const bucket = encodeURIComponent(match.groups['bucket']);
+  const bucket = encodeURIComponent(match.groups['bkt']);
   const file = encodeURIComponent(match.groups['file']);
   return {bucket, file};
 }
@@ -256,7 +256,9 @@
 }
 
 const actions = {
-  /** @param {{input:string|null,accessToken:string|null,options:string}} param0 */
+  /**
+   * @param {{input:string|null,accessToken:string|null,options:string}} param0
+   */
   load({input, accessToken, options}) {
     const {
       groupBy,
diff --git a/tools/binary_size/libsupersize/static/viewer.html b/tools/binary_size/libsupersize/viewer/static/viewer.html
similarity index 100%
rename from tools/binary_size/libsupersize/static/viewer.html
rename to tools/binary_size/libsupersize/viewer/static/viewer.html
diff --git a/tools/binary_size/libsupersize/templates/sw.js b/tools/binary_size/libsupersize/viewer/templates/sw.js
similarity index 100%
rename from tools/binary_size/libsupersize/templates/sw.js
rename to tools/binary_size/libsupersize/viewer/templates/sw.js
diff --git a/tools/binary_size/libsupersize/upload_html_viewer.py b/tools/binary_size/libsupersize/viewer/upload_html_viewer.py
similarity index 93%
rename from tools/binary_size/libsupersize/upload_html_viewer.py
rename to tools/binary_size/libsupersize/viewer/upload_html_viewer.py
index a5820a6..6e60a79 100755
--- a/tools/binary_size/libsupersize/upload_html_viewer.py
+++ b/tools/binary_size/libsupersize/viewer/upload_html_viewer.py
@@ -2,7 +2,6 @@
 # Copyright 2018 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
-
 """Update the firebase project hosting the Super Size UI."""
 
 import argparse
@@ -14,7 +13,6 @@
 import tempfile
 import uuid
 
-
 FIREBASE_PROJECT = 'chrome-supersize'
 PROD_URL = 'https://chrome-supersize.firebaseapp.com/'
 CASPIAN_FILES = [
@@ -135,11 +133,8 @@
                                      help='Deploy to prod.')
   options = parser.parse_args()
 
-  message = (
-  """This script deploys the contents of //tools/binary_size/libsupersize/static
-to firebase hosting at chrome-supersize.firebaseapp.com. Please ensure you have
-read the instructions at //tools/binary_size/libsupersize/static/README.md first
-before running this. Are you sure you want to continue?""")
+  message = (f'This script deploys the viewer to {PROD_URL}.\n'
+             'Are you sure you want to continue?')
 
   if options.deploy_mode != PROD or _Prompt(message):
     _CheckFirebaseCLI()
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 12fe343..5fc6dce 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -323,7 +323,7 @@
       'fuchsia-fyi-arm64-dbg': 'debug_bot_fuchsia_arm64',
       'fuchsia-fyi-arm64-femu': 'release_bot_fuchsia_arm64',
       'fuchsia-fyi-arm64-rel': 'release_bot_fuchsia_arm64',
-      'fuchsia-fyi-x64-asan': 'asan_bot_fuchsia',
+      'fuchsia-fyi-x64-asan': 'asan_lsan_bot_fuchsia',
       'fuchsia-fyi-x64-dbg': 'debug_bot_fuchsia',
       'fuchsia-fyi-x64-rel': 'release_bot_fuchsia',
       'fuchsia-fyi-x64-wst': 'fuchsia_workstation_bot',
@@ -1661,10 +1661,6 @@
       'arm64', 'official_optimize_goma',
     ],
 
-    'asan_bot_fuchsia': [
-      'asan', 'release_bot', 'fuchsia',
-    ],
-
     'asan_clang_fuzzer_static_v8_heap_minimal_symbols_release': [
       'asan', 'fuzzer', 'static', 'v8_heap', 'minimal_symbols', 'release_bot',
     ],
@@ -1697,6 +1693,10 @@
       'asan', 'fuzzer', 'v8_heap', 'release_bot', 'hybrid',
     ],
 
+    'asan_lsan_bot_fuchsia': [
+      'asan', 'lsan', 'release_bot', 'fuchsia',
+    ],
+
     'asan_v8_heap_debug_bot_hybrid': [
       'asan', 'v8_heap', 'debug_bot', 'hybrid',
     ],
diff --git a/tools/mb/mb_config_expectations/chromium.fyi.json b/tools/mb/mb_config_expectations/chromium.fyi.json
index 4fb7bf9..d650372 100644
--- a/tools/mb/mb_config_expectations/chromium.fyi.json
+++ b/tools/mb/mb_config_expectations/chromium.fyi.json
@@ -523,6 +523,7 @@
       "is_asan": true,
       "is_component_build": false,
       "is_debug": false,
+      "is_lsan": true,
       "target_os": "fuchsia",
       "use_goma": true
     }
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 9f62494..7c325ccc 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -31227,6 +31227,7 @@
   <int value="1609" label="OS_TELEMETRY_GETMEMORYINFO"/>
   <int value="1610" label="AUTOTESTPRIVATE_COULDALLOWCROSTINI"/>
   <int value="1611" label="WEB_AUTHENTICATION_PROXY_COMPLETE_CREATE_REQUEST"/>
+  <int value="1612" label="DEVELOPERPRIVATE_GETUSERSITESETTINGS"/>
 </enum>
 
 <enum name="ExtensionIconState">
@@ -32150,8 +32151,15 @@
   <int value="11" label="Discovery UI Dismissed By OS"/>
   <int value="12" label="Discovery UI: Connect Button Pressed"/>
   <int value="13" label="Discovery UI Dismissed By User"/>
+  <int value="14" label="Discovery UI: Learn More Pressed"/>
   <int value="121" label="Pairing Failed"/>
   <int value="122" label="Pairing Succeeded"/>
+  <int value="141"
+      label="Discovery UI: Connect Button Pressed After Learn More Pressed"/>
+  <int value="142"
+      label="Discovery UI: Dismissed By User After Learn More Pressed"/>
+  <int value="143"
+      label="Discovery UI: Dismissed By OS After Learn More Pressed"/>
   <int value="1211" label="Pairing Failed: Error UI Dismissed By OS"/>
   <int value="1212" label="Pairing Failed: Error UI Settings Button Pressed"/>
   <int value="1213" label="Pairing Failed: Error UI Dismissed By User"/>
@@ -52781,6 +52789,7 @@
   <int value="-579192400" label="disable-input-view"/>
   <int value="-577982497" label="CupsPrintersUiOverhaul:enabled"/>
   <int value="-577503348" label="GridTabSwitcherForTablets:disabled"/>
+  <int value="-576759065" label="HoldingSpaceInProgressAnimationV2:disabled"/>
   <int value="-574354898" label="PostQuantumCECPQ2:enabled"/>
   <int value="-574217217" label="kSignInProfileCreationEnterprise:enabled"/>
   <int value="-574000901" label="AVIF:enabled"/>
@@ -56130,6 +56139,7 @@
   <int value="1915028326" label="BuiltInModuleKvStorage:disabled"/>
   <int value="1915178511" label="disable-blink-features"/>
   <int value="1916637435" label="TranslateSubFrames:enabled"/>
+  <int value="1918061181" label="HoldingSpaceInProgressAnimationV2:enabled"/>
   <int value="1918984253"
       label="OmniboxUIExperimentBlueSearchLoopAndSearchQuery:disabled"/>
   <int value="1919917329" label="ImplicitRootScroller:disabled"/>
diff --git a/tools/metrics/histograms/metadata/android/histograms.xml b/tools/metrics/histograms/metadata/android/histograms.xml
index 1a4bd41..09d4795 100644
--- a/tools/metrics/histograms/metadata/android/histograms.xml
+++ b/tools/metrics/histograms/metadata/android/histograms.xml
@@ -3568,7 +3568,7 @@
 </histogram>
 
 <histogram name="Android.WebView.Callback.Counts" enum="WebViewCallbackType"
-    expires_after="2022-05-10">
+    expires_after="2022-07-11">
   <owner>ntfschr@chromium.org</owner>
   <owner>src/android_webview/OWNERS</owner>
   <summary>Records the invocation count of WebView callbacks.</summary>
@@ -4553,7 +4553,7 @@
 </histogram>
 
 <histogram name="Android.WebView.SecureCookieAction" enum="SecureCookieAction"
-    expires_after="2022-05-10">
+    expires_after="2022-07-11">
   <owner>ntfschr@chromium.org</owner>
   <owner>src/android_webview/OWNERS</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/apps/histograms.xml b/tools/metrics/histograms/metadata/apps/histograms.xml
index d0a2492..7e4cc70 100644
--- a/tools/metrics/histograms/metadata/apps/histograms.xml
+++ b/tools/metrics/histograms/metadata/apps/histograms.xml
@@ -1663,7 +1663,7 @@
 </histogram>
 
 <histogram name="Apps.AppListPageSwitcherSource"
-    enum="AppListPageSwitcherSource" expires_after="2022-05-08">
+    enum="AppListPageSwitcherSource" expires_after="2022-07-11">
 <!-- Name completed by histogram_suffixes name="TabletOrClamshellMode" -->
 
   <owner>newcomer@chromium.org</owner>
@@ -1703,7 +1703,7 @@
 </histogram>
 
 <histogram name="Apps.AppListPlayStoreQueryState"
-    enum="AppListPlayStoreQueryState" expires_after="2022-03-06">
+    enum="AppListPlayStoreQueryState" expires_after="2022-07-11">
   <owner>hejq@chromium.org</owner>
   <summary>The state of a Play Store app search request.</summary>
 </histogram>
diff --git a/tools/metrics/histograms/metadata/arc/histograms.xml b/tools/metrics/histograms/metadata/arc/histograms.xml
index 74b1434..ecaf291b 100644
--- a/tools/metrics/histograms/metadata/arc/histograms.xml
+++ b/tools/metrics/histograms/metadata/arc/histograms.xml
@@ -1381,7 +1381,7 @@
 </histogram>
 
 <histogram name="Arc.PlayStoreSearch.QueryTime" units="ms"
-    expires_after="2022-05-08">
+    expires_after="2022-07-11">
   <owner>hejq@chromium.org</owner>
   <summary>
     Time between sending an Play Store app discovery request and the storing
diff --git a/tools/metrics/histograms/metadata/background/histograms.xml b/tools/metrics/histograms/metadata/background/histograms.xml
index e15438b..14cfab3 100644
--- a/tools/metrics/histograms/metadata/background/histograms.xml
+++ b/tools/metrics/histograms/metadata/background/histograms.xml
@@ -314,7 +314,7 @@
 </histogram>
 
 <histogram name="BackgroundSync.Event.OneShotResultPattern"
-    enum="BackgroundSyncResultPattern" expires_after="2022-05-08">
+    enum="BackgroundSyncResultPattern" expires_after="2022-07-11">
   <owner>nator@chromium.org</owner>
   <owner>rayankans@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/compositing/histograms.xml b/tools/metrics/histograms/metadata/compositing/histograms.xml
index 84ad605a..40837f1 100644
--- a/tools/metrics/histograms/metadata/compositing/histograms.xml
+++ b/tools/metrics/histograms/metadata/compositing/histograms.xml
@@ -59,7 +59,7 @@
 </histogram>
 
 <histogram name="Compositing.Browser.LayersUpdateTime" units="microseconds"
-    expires_after="2022-05-08">
+    expires_after="2022-07-11">
   <owner>schenney@chromium.org</owner>
   <owner>animations-dev@chromium.org</owner>
   <summary>
@@ -75,7 +75,7 @@
 </histogram>
 
 <histogram name="Compositing.Browser.LayerTreeImpl.CalculateDrawPropertiesUs"
-    units="microseconds" expires_after="2022-05-08">
+    units="microseconds" expires_after="2022-07-11">
   <owner>schenney@chromium.org</owner>
   <owner>paint-dev@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/data/histograms.xml b/tools/metrics/histograms/metadata/data/histograms.xml
index 5e5c406..6d6b527 100644
--- a/tools/metrics/histograms/metadata/data/histograms.xml
+++ b/tools/metrics/histograms/metadata/data/histograms.xml
@@ -427,7 +427,7 @@
 </histogram>
 
 <histogram name="DataReductionProxy.UIAction" enum="DataReductionProxyUIAction"
-    expires_after="2022-05-08">
+    expires_after="2022-07-11">
   <owner>bengr@chromium.org</owner>
   <owner>mcrouse@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/event/histograms.xml b/tools/metrics/histograms/metadata/event/histograms.xml
index 30a8756..fe7f01d 100644
--- a/tools/metrics/histograms/metadata/event/histograms.xml
+++ b/tools/metrics/histograms/metadata/event/histograms.xml
@@ -1254,7 +1254,7 @@
 </histogram>
 
 <histogram name="Event.Latency.ScrollBegin.Wheel.TimeToScrollUpdateSwapBegin4"
-    units="microseconds" expires_after="2022-05-08">
+    units="microseconds" expires_after="2022-07-11">
   <owner>flackr@chromium.org</owner>
   <summary>
     Time between initial creation of a wheel event and the start of the frame
@@ -1982,7 +1982,7 @@
 </histogram>
 
 <histogram name="Event.Latency.ScrollUpdate.Wheel.TimeToScrollUpdateSwapBegin4"
-    units="microseconds" expires_after="2022-05-08">
+    units="microseconds" expires_after="2022-07-11">
   <owner>flackr@chromium.org</owner>
   <summary>
     Time between initial creation of a wheel event and start of the frame swap
diff --git a/tools/metrics/histograms/metadata/google/histograms.xml b/tools/metrics/histograms/metadata/google/histograms.xml
index 4cef3294..7180788 100644
--- a/tools/metrics/histograms/metadata/google/histograms.xml
+++ b/tools/metrics/histograms/metadata/google/histograms.xml
@@ -239,7 +239,7 @@
 </histogram>
 
 <histogram name="GoogleUpdate.UpdateErrorCode" enum="GoogleUpdateErrorCode"
-    expires_after="2022-05-08">
+    expires_after="2022-07-11">
   <owner>grt@chromium.org</owner>
   <owner>ydago@chromium.org</owner>
   <summary>The error code for a failed on-demand update check.</summary>
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml
index 0e290e112..5e0f158 100644
--- a/tools/metrics/histograms/metadata/media/histograms.xml
+++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -892,7 +892,7 @@
 </histogram>
 
 <histogram name="Media.Audio.Render.FramesRequested" units="frames"
-    expires_after="2022-05-08">
+    expires_after="2022-07-11">
   <owner>guidou@chromium.org</owner>
   <owner>olka@chromium.org</owner>
   <summary>
@@ -2034,7 +2034,7 @@
 </histogram>
 
 <histogram name="Media.EME.CdmFileIO.FileSizeKBOnFirstRead" units="KB"
-    expires_after="2022-05-07">
+    expires_after="2022-07-11">
   <owner>xhwang@chromium.org</owner>
   <owner>media-dev@chromium.org</owner>
   <summary>
@@ -2083,13 +2083,13 @@
 </histogram>
 
 <histogram name="Media.EME.CdmLoadResult" enum="CdmLoadResult"
-    expires_after="2022-05-07">
+    expires_after="2022-07-11">
   <owner>xhwang@chromium.org</owner>
   <owner>media-dev@chromium.org</owner>
   <summary>The result from an attempt to load a library CDM.</summary>
 </histogram>
 
-<histogram name="Media.EME.CdmLoadTime" units="ms" expires_after="2022-05-07">
+<histogram name="Media.EME.CdmLoadTime" units="ms" expires_after="2022-07-11">
   <owner>xhwang@chromium.org</owner>
   <owner>media-dev@chromium.org</owner>
   <summary>The time spent to load a library CDM.</summary>
@@ -2259,7 +2259,7 @@
 </histogram>
 
 <histogram name="Media.EME.OutputProtection" enum="MediaOutputProtectionStatus"
-    expires_after="2022-05-07">
+    expires_after="2022-07-11">
   <owner>xhwang@chromium.org</owner>
   <owner>media-dev@chromium.org</owner>
   <summary>
@@ -2301,7 +2301,7 @@
 </histogram>
 
 <histogram name="Media.EME.Widevine.VideoCapability.HasEmptyRobustness"
-    enum="BooleanEmpty" expires_after="2022-05-07">
+    enum="BooleanEmpty" expires_after="2022-07-11">
   <owner>xhwang@chromium.org</owner>
   <owner>media-dev@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml
index 0d1966f..cbff430 100644
--- a/tools/metrics/histograms/metadata/net/histograms.xml
+++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -203,7 +203,7 @@
 </histogram>
 
 <histogram name="Net.AlternateProtocolUsage" enum="AlternateProtocolUsage"
-    expires_after="2022-05-11">
+    expires_after="2022-07-11">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
   <summary>
@@ -3114,7 +3114,7 @@
 </histogram>
 
 <histogram name="Net.QuicNumSentClientHellos" units="units"
-    expires_after="2022-05-11">
+    expires_after="2022-07-11">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>The number of client hello messages sent.</summary>
@@ -3397,7 +3397,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.ConnectionCloseErrorCodeClient"
-    enum="QuicErrorCodes" expires_after="2022-05-11">
+    enum="QuicErrorCodes" expires_after="2022-07-11">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3417,7 +3417,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.ConnectionCloseErrorCodeServer"
-    enum="QuicErrorCodes" expires_after="2022-05-11">
+    enum="QuicErrorCodes" expires_after="2022-07-11">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -4172,7 +4172,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.PacketRetransmitsPerMille" units="permille"
-    expires_after="2022-05-11">
+    expires_after="2022-07-11">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/new_tab_page/histograms.xml b/tools/metrics/histograms/metadata/new_tab_page/histograms.xml
index c5be4bdb..616afce8 100644
--- a/tools/metrics/histograms/metadata/new_tab_page/histograms.xml
+++ b/tools/metrics/histograms/metadata/new_tab_page/histograms.xml
@@ -883,7 +883,7 @@
   </summary>
 </histogram>
 
-<histogram name="NewTabPage.LoadTime" units="ms" expires_after="2022-05-08">
+<histogram name="NewTabPage.LoadTime" units="ms" expires_after="2022-07-11">
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/omnibox/histograms.xml b/tools/metrics/histograms/metadata/omnibox/histograms.xml
index 333a987..0478574 100644
--- a/tools/metrics/histograms/metadata/omnibox/histograms.xml
+++ b/tools/metrics/histograms/metadata/omnibox/histograms.xml
@@ -37,7 +37,7 @@
 </histogram>
 
 <histogram name="Omnibox.AnswerParseSuccess" enum="BooleanSuccess"
-    expires_after="2022-05-08">
+    expires_after="2022-07-11">
   <owner>jdonnelly@chromium.org</owner>
   <owner>chrome-omnibox-team@google.com</owner>
   <summary>
@@ -79,7 +79,7 @@
 </histogram>
 
 <histogram name="Omnibox.CharTypedToRepaintLatency" units="ms"
-    expires_after="2022-05-08">
+    expires_after="2022-07-11">
   <owner>jdonnelly@chromium.org</owner>
   <owner>mpearson@chromium.org</owner>
   <owner>asvitkine@chromium.org</owner>
@@ -335,7 +335,7 @@
 </histogram>
 
 <histogram name="Omnibox.FocusToOpenTimeAnyPopupState3" units="ms"
-    expires_after="2022-05-08">
+    expires_after="2022-07-11">
   <owner>jdonnelly@chromium.org</owner>
   <owner>mpearson@chromium.org</owner>
   <owner>chrome-omnibox-team@google.com</owner>
@@ -1023,7 +1023,7 @@
 </histogram>
 
 <histogram name="Omnibox.SuggestRequest.Success.GoogleResponseTime" units="ms"
-    expires_after="2022-05-08">
+    expires_after="2022-07-11">
   <owner>mpearson@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
   <owner>cch@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml
index 4beaa2855..04c9085 100644
--- a/tools/metrics/histograms/metadata/others/histograms.xml
+++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -16928,7 +16928,7 @@
 </histogram>
 
 <histogram name="WebFont.LocalFontUsed" enum="BooleanUsage"
-    expires_after="2022-05-08">
+    expires_after="2022-07-11">
   <owner>hajimehoshi@chromium.org</owner>
   <owner>kenjibaheux@chromium.org</owner>
   <owner>kouhei@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/payment/histograms.xml b/tools/metrics/histograms/metadata/payment/histograms.xml
index 6489cac..e18a57b 100644
--- a/tools/metrics/histograms/metadata/payment/histograms.xml
+++ b/tools/metrics/histograms/metadata/payment/histograms.xml
@@ -37,7 +37,7 @@
 </histogram>
 
 <histogram name="PaymentRequest.CheckoutFunnel"
-    enum="PaymentRequestCheckoutFunnelSteps" expires_after="2022-05-08">
+    enum="PaymentRequestCheckoutFunnelSteps" expires_after="2022-07-11">
   <owner>rouslan@chromium.org</owner>
   <owner>web-payments-team@google.com</owner>
   <summary>
@@ -265,7 +265,7 @@
 </histogram>
 
 <histogram name="PaymentRequest.TimeToCheckout.Completed" units="ms"
-    expires_after="2022-05-08">
+    expires_after="2022-07-11">
   <owner>rouslan@chromium.org</owner>
   <owner>web-payments-team@google.com</owner>
   <summary>
@@ -286,7 +286,7 @@
 </histogram>
 
 <histogram name="PaymentRequest.TimeToCheckout.Completed.SkippedShow"
-    units="ms" expires_after="2022-05-08">
+    units="ms" expires_after="2022-07-11">
 <!-- Name completed by histogram_suffixes name="PaymentRequestCompletedInstrument" -->
 
   <owner>rouslan@chromium.org</owner>
@@ -320,7 +320,7 @@
 </histogram>
 
 <histogram name="PaymentRequest.TransactionAmount.Completed"
-    enum="PaymentRequestTransactionSize" expires_after="2022-05-08">
+    enum="PaymentRequestTransactionSize" expires_after="2022-07-11">
   <owner>rouslan@chromium.org</owner>
   <owner>web-payments-team@google.com</owner>
   <summary>
@@ -330,7 +330,7 @@
 </histogram>
 
 <histogram name="PaymentRequest.TransactionAmount.Triggered"
-    enum="PaymentRequestTransactionSize" expires_after="2022-05-08">
+    enum="PaymentRequestTransactionSize" expires_after="2022-07-11">
   <owner>rouslan@chromium.org</owner>
   <owner>web-payments-team@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
index 05ea546..4a0882e 100644
--- a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
+++ b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
@@ -1564,7 +1564,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.RT.GetCache.Time" units="ms"
-    expires_after="2022-05-08">
+    expires_after="2022-07-11">
   <owner>xinghuilu@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
@@ -1575,7 +1575,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.RT.GetCacheResult"
-    enum="SafeBrowsingRTLookupResponseVerdictType" expires_after="2022-05-08">
+    enum="SafeBrowsingRTLookupResponseVerdictType" expires_after="2022-07-11">
   <owner>xinghuilu@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
@@ -2089,7 +2089,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.V4GetHash.Network.Result"
-    enum="CombinedHttpResponseAndNetErrorCode" expires_after="2022-05-07">
+    enum="CombinedHttpResponseAndNetErrorCode" expires_after="2022-07-11">
   <owner>vakh@google.com</owner>
   <owner>kcarattini@google.com</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/sb_client/histograms.xml b/tools/metrics/histograms/metadata/sb_client/histograms.xml
index 909c3a6a..334c2f7b 100644
--- a/tools/metrics/histograms/metadata/sb_client/histograms.xml
+++ b/tools/metrics/histograms/metadata/sb_client/histograms.xml
@@ -35,7 +35,7 @@
 </variants>
 
 <histogram name="SBClientDownload.CheckDownloadStats"
-    enum="SBClientDownloadCheckDownloadStats" expires_after="2022-05-08">
+    enum="SBClientDownloadCheckDownloadStats" expires_after="2022-07-11">
   <owner>vakh@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <owner>mattm@chromium.org</owner>
@@ -769,7 +769,7 @@
 </histogram>
 
 <histogram name="SBClientPhishing.ModelDynamicUpdateSuccess"
-    enum="BooleanSuccess" expires_after="2022-05-08">
+    enum="BooleanSuccess" expires_after="2022-07-11">
   <owner>drubery@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
@@ -832,7 +832,7 @@
 </histogram>
 
 <histogram name="SBClientPhishing.PhishingDetectorResult"
-    enum="ClientSidePhishingResult" expires_after="2022-05-08">
+    enum="ClientSidePhishingResult" expires_after="2022-07-11">
   <owner>drubery@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
@@ -929,7 +929,7 @@
 </histogram>
 
 <histogram name="SBClientPhishing.ServerModelDetectsPhishing"
-    enum="BooleanIsPhishing" expires_after="2022-05-08">
+    enum="BooleanIsPhishing" expires_after="2022-07-11">
   <owner>drubery@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/sync/histograms.xml b/tools/metrics/histograms/metadata/sync/histograms.xml
index 4fc91999..4ed0b3f 100644
--- a/tools/metrics/histograms/metadata/sync/histograms.xml
+++ b/tools/metrics/histograms/metadata/sync/histograms.xml
@@ -903,6 +903,20 @@
   </summary>
 </histogram>
 
+<histogram name="Sync.ModelTypeCommitWithDepletedQuota" enum="SyncModelTypes"
+    expires_after="2022-07-04">
+  <owner>jkrcal@chromium.org</owner>
+  <owner>treib@chromium.org</owner>
+  <component>Services&gt;Sync</component>
+  <summary>
+    Recorded once per local change that gets scheduled for committing with an
+    extra long nudge delay. This happens if and only if the commit quota for
+    this data type for this user is depleted. Quota is tracked (and this metric
+    gets recorded) only for data types that can be committed via JS API of
+    extensions.
+  </summary>
+</histogram>
+
 <histogram name="Sync.ModelTypeConfigurationTime.Ephemeral{SyncModelType}"
     units="ms" expires_after="2022-03-06">
   <owner>jkrcal@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/ukm/histograms.xml b/tools/metrics/histograms/metadata/ukm/histograms.xml
index c8b6072f..0bc92e72 100644
--- a/tools/metrics/histograms/metadata/ukm/histograms.xml
+++ b/tools/metrics/histograms/metadata/ukm/histograms.xml
@@ -295,7 +295,7 @@
 </histogram>
 
 <histogram name="UKM.UnsentLogs.DroppedSize" units="bytes"
-    expires_after="2022-05-08">
+    expires_after="2022-07-11">
   <owner>rkaplow@chromium.org</owner>
   <owner>ukm-team@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/web_rtc/histograms.xml b/tools/metrics/histograms/metadata/web_rtc/histograms.xml
index 2003953..028feaa 100644
--- a/tools/metrics/histograms/metadata/web_rtc/histograms.xml
+++ b/tools/metrics/histograms/metadata/web_rtc/histograms.xml
@@ -560,7 +560,7 @@
 </histogram>
 
 <histogram name="WebRTC.Audio.DelayedPacketOutageEventsPerMinute"
-    units="events/minute" expires_after="2022-05-08">
+    units="events/minute" expires_after="2022-07-11">
   <owner>hlundin@chromium.org</owner>
   <summary>
     Counts the number of delayed packet outage events per minute. The range is
@@ -895,7 +895,7 @@
 </histogram>
 
 <histogram name="WebRTC.Audio.ReceiverDeviceDelayMs" units="ms"
-    expires_after="2022-05-08">
+    expires_after="2022-07-11">
   <owner>hlundin@chromium.org</owner>
   <summary>
     The sound card's buffering delay for the receiving side. Sampled once every
@@ -904,7 +904,7 @@
 </histogram>
 
 <histogram name="WebRTC.Audio.ReceiverJitterBufferDelayMs" units="ms"
-    expires_after="2022-05-08">
+    expires_after="2022-07-11">
   <owner>hlundin@chromium.org</owner>
   <summary>
     The jitter buffer delay for the receiving side. Sampled once every 10 ms
diff --git a/tools/typescript/definitions/chrome_timeticks.d.ts b/tools/typescript/definitions/chrome_timeticks.d.ts
new file mode 100644
index 0000000..1f4f765
--- /dev/null
+++ b/tools/typescript/definitions/chrome_timeticks.d.ts
@@ -0,0 +1,11 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/** @fileoverview Definitions for chrome.timeticks API */
+
+declare namespace chrome {
+  export namespace timeTicks {
+    function nowInMicroseconds(): BigInt;
+  }
+}
\ No newline at end of file
diff --git a/ui/accessibility/ax_computed_node_data.cc b/ui/accessibility/ax_computed_node_data.cc
index 6e15815a..e175016 100644
--- a/ui/accessibility/ax_computed_node_data.cc
+++ b/ui/accessibility/ax_computed_node_data.cc
@@ -280,9 +280,13 @@
 
   sentence_starts_ = std::vector<int32_t>();
   sentence_ends_ = std::vector<int32_t>();
-  const std::u16string& text_content = GetOrComputeTextContentUTF16();
-  if (text_content.empty())
+  if (owner_->IsLineBreak())
     return;
+  const std::u16string& text_content = GetOrComputeTextContentUTF16();
+  if (text_content.empty() ||
+      base::ContainsOnlyChars(text_content, base::kWhitespaceUTF16)) {
+    return;
+  }
 
   // Unlike in ICU, a sentence boundary is not valid in Blink if it falls within
   // some whitespace that is used to separate sentences. We therefore need to
diff --git a/ui/accessibility/ax_node_position_unittest.cc b/ui/accessibility/ax_node_position_unittest.cc
index a7368e02..2876598 100644
--- a/ui/accessibility/ax_node_position_unittest.cc
+++ b/ui/accessibility/ax_node_position_unittest.cc
@@ -388,6 +388,10 @@
   inline_box1_.role = ax::mojom::Role::kInlineTextBox;
   inline_box1_.AddState(ax::mojom::State::kEditable);
   inline_box1_.SetName("Line 1");
+  inline_box1_.AddIntListAttribute(ax::mojom::IntListAttribute::kSentenceStarts,
+                                   {0});
+  inline_box1_.AddIntListAttribute(ax::mojom::IntListAttribute::kSentenceEnds,
+                                   {6});
   inline_box1_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordStarts,
                                    std::vector<int32_t>{0, 5});
   inline_box1_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordEnds,
@@ -412,6 +416,10 @@
   inline_box2_.role = ax::mojom::Role::kInlineTextBox;
   inline_box2_.AddState(ax::mojom::State::kEditable);
   inline_box2_.SetName("Line 2");
+  inline_box2_.AddIntListAttribute(ax::mojom::IntListAttribute::kSentenceStarts,
+                                   {0});
+  inline_box2_.AddIntListAttribute(ax::mojom::IntListAttribute::kSentenceEnds,
+                                   {6});
   inline_box2_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordStarts,
                                    std::vector<int32_t>{0, 5});
   inline_box2_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordEnds,
@@ -3222,19 +3230,19 @@
                                          ax::mojom::TextAffinity::kDownstream);
   paragraph_start_position =
       paragraph_start_position->CreateNextParagraphStartPosition(
-          AXBoundaryBehavior::CrossBoundary);
+          AXBoundaryBehavior::kCrossBoundary);
   ASSERT_TRUE(paragraph_start_position->IsTextPosition());
   EXPECT_EQ(inline_text_data_b_1.id, paragraph_start_position->anchor_id());
   EXPECT_EQ(0, paragraph_start_position->text_offset());
   paragraph_start_position =
       paragraph_start_position->CreateNextParagraphStartPosition(
-          AXBoundaryBehavior::CrossBoundary);
+          AXBoundaryBehavior::kCrossBoundary);
   ASSERT_TRUE(paragraph_start_position->IsTextPosition());
   EXPECT_EQ(inline_text_data_c.id, paragraph_start_position->anchor_id());
   EXPECT_EQ(0, paragraph_start_position->text_offset());
   paragraph_start_position =
       paragraph_start_position->CreateNextParagraphStartPosition(
-          AXBoundaryBehavior::CrossBoundary);
+          AXBoundaryBehavior::kCrossBoundary);
   EXPECT_TRUE(paragraph_start_position->IsNullPosition());
 
   paragraph_start_position = AXNodePosition::CreateTextPosition(
@@ -3242,25 +3250,25 @@
       ax::mojom::TextAffinity::kDownstream);
   paragraph_start_position =
       paragraph_start_position->CreatePreviousParagraphStartPosition(
-          AXBoundaryBehavior::CrossBoundary);
+          AXBoundaryBehavior::kCrossBoundary);
   ASSERT_TRUE(paragraph_start_position->IsTextPosition());
   EXPECT_EQ(inline_text_data_c.id, paragraph_start_position->anchor_id());
   EXPECT_EQ(0, paragraph_start_position->text_offset());
   paragraph_start_position =
       paragraph_start_position->CreatePreviousParagraphStartPosition(
-          AXBoundaryBehavior::CrossBoundary);
+          AXBoundaryBehavior::kCrossBoundary);
   ASSERT_TRUE(paragraph_start_position->IsTextPosition());
   EXPECT_EQ(inline_text_data_b_1.id, paragraph_start_position->anchor_id());
   EXPECT_EQ(0, paragraph_start_position->text_offset());
   paragraph_start_position =
       paragraph_start_position->CreatePreviousParagraphStartPosition(
-          AXBoundaryBehavior::CrossBoundary);
+          AXBoundaryBehavior::kCrossBoundary);
   ASSERT_TRUE(paragraph_start_position->IsTextPosition());
   EXPECT_EQ(inline_text_data_a.id, paragraph_start_position->anchor_id());
   EXPECT_EQ(0, paragraph_start_position->text_offset());
   paragraph_start_position =
       paragraph_start_position->CreatePreviousParagraphStartPosition(
-          AXBoundaryBehavior::CrossBoundary);
+          AXBoundaryBehavior::kCrossBoundary);
   EXPECT_TRUE(paragraph_start_position->IsNullPosition());
 
   TestPositionType paragraph_end_position = AXNodePosition::CreateTextPosition(
@@ -3268,28 +3276,28 @@
       ax::mojom::TextAffinity::kDownstream);
   paragraph_end_position =
       paragraph_end_position->CreateNextParagraphEndPosition(
-          AXBoundaryBehavior::CrossBoundary);
+          AXBoundaryBehavior::kCrossBoundary);
   ASSERT_TRUE(paragraph_end_position->IsTextPosition());
   EXPECT_EQ(inline_text_data_a.id, paragraph_end_position->anchor_id());
   // "First paragraph<>".
   EXPECT_EQ(15, paragraph_end_position->text_offset());
   paragraph_end_position =
       paragraph_end_position->CreateNextParagraphEndPosition(
-          AXBoundaryBehavior::CrossBoundary);
+          AXBoundaryBehavior::kCrossBoundary);
   ASSERT_TRUE(paragraph_end_position->IsTextPosition());
   EXPECT_EQ(inline_text_data_b_3.id, paragraph_end_position->anchor_id());
   // "paragraph<>".
   EXPECT_EQ(9, paragraph_end_position->text_offset());
   paragraph_end_position =
       paragraph_end_position->CreateNextParagraphEndPosition(
-          AXBoundaryBehavior::CrossBoundary);
+          AXBoundaryBehavior::kCrossBoundary);
   ASSERT_TRUE(paragraph_end_position->IsTextPosition());
   EXPECT_EQ(inline_text_data_c.id, paragraph_end_position->anchor_id());
   // "Third paragraph<>".
   EXPECT_EQ(15, paragraph_end_position->text_offset());
   paragraph_end_position =
       paragraph_end_position->CreateNextParagraphEndPosition(
-          AXBoundaryBehavior::CrossBoundary);
+          AXBoundaryBehavior::kCrossBoundary);
   EXPECT_TRUE(paragraph_end_position->IsNullPosition());
 
   paragraph_end_position = AXNodePosition::CreateTextPosition(
@@ -3297,21 +3305,21 @@
       ax::mojom::TextAffinity::kDownstream);
   paragraph_end_position =
       paragraph_end_position->CreatePreviousParagraphEndPosition(
-          AXBoundaryBehavior::CrossBoundary);
+          AXBoundaryBehavior::kCrossBoundary);
   ASSERT_TRUE(paragraph_end_position->IsTextPosition());
   EXPECT_EQ(inline_text_data_b_3.id, paragraph_end_position->anchor_id());
   // "paragraph<>".
   EXPECT_EQ(9, paragraph_end_position->text_offset());
   paragraph_end_position =
       paragraph_end_position->CreatePreviousParagraphEndPosition(
-          AXBoundaryBehavior::CrossBoundary);
+          AXBoundaryBehavior::kCrossBoundary);
   ASSERT_TRUE(paragraph_end_position->IsTextPosition());
   EXPECT_EQ(inline_text_data_a.id, paragraph_end_position->anchor_id());
   // "First paragraph<>".
   EXPECT_EQ(15, paragraph_end_position->text_offset());
   paragraph_end_position =
       paragraph_end_position->CreatePreviousParagraphEndPosition(
-          AXBoundaryBehavior::CrossBoundary);
+          AXBoundaryBehavior::kCrossBoundary);
   EXPECT_TRUE(paragraph_end_position->IsNullPosition());
 }
 
@@ -3363,7 +3371,7 @@
       ax::mojom::TextAffinity::kDownstream);
 
   test_position = test_position->CreatePreviousParagraphEndPosition(
-      AXBoundaryBehavior::StopAtAnchorBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundary);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(root_data.id, test_position->anchor_id());
   EXPECT_EQ(5, test_position->text_offset());
@@ -4516,9 +4524,9 @@
   inline_box_data_1.SetName("One");
   inline_box_data_1.AddState(ax::mojom::State::kIgnored);
   inline_box_data_1.AddIntListAttribute(
-      ax::mojom::IntListAttribute::kWordStarts, std::vector<int32_t>{0});
+      ax::mojom::IntListAttribute::kWordStarts, {0});
   inline_box_data_1.AddIntListAttribute(ax::mojom::IntListAttribute::kWordEnds,
-                                        std::vector<int32_t>{3});
+                                        {3});
   inline_box_data_1.AddIntAttribute(ax::mojom::IntAttribute::kNextOnLineId,
                                     kInlineBox2Id);
 
@@ -4532,9 +4540,9 @@
   inline_box_data_2.role = ax::mojom::Role::kInlineTextBox;
   inline_box_data_2.SetName("Two");
   inline_box_data_2.AddIntListAttribute(
-      ax::mojom::IntListAttribute::kWordStarts, std::vector<int32_t>{0});
+      ax::mojom::IntListAttribute::kWordStarts, {0});
   inline_box_data_2.AddIntListAttribute(ax::mojom::IntListAttribute::kWordEnds,
-                                        std::vector<int32_t>{3});
+                                        {3});
   inline_box_data_2.AddIntAttribute(ax::mojom::IntAttribute::kPreviousOnLineId,
                                     kInlineBox1Id);
   inline_box_data_2.AddIntAttribute(ax::mojom::IntAttribute::kNextOnLineId,
@@ -4550,9 +4558,9 @@
   inline_box_data_3.role = ax::mojom::Role::kInlineTextBox;
   inline_box_data_3.SetName("Three");
   inline_box_data_3.AddIntListAttribute(
-      ax::mojom::IntListAttribute::kWordStarts, std::vector<int32_t>{0});
+      ax::mojom::IntListAttribute::kWordStarts, {0});
   inline_box_data_3.AddIntListAttribute(ax::mojom::IntListAttribute::kWordEnds,
-                                        std::vector<int32_t>{5});
+                                        {5});
   inline_box_data_3.AddIntAttribute(ax::mojom::IntAttribute::kPreviousOnLineId,
                                     kInlineBox2Id);
   inline_box_data_3.AddIntAttribute(ax::mojom::IntAttribute::kNextOnLineId,
@@ -4569,9 +4577,9 @@
   inline_box_data_4.SetName("Four");
   inline_box_data_4.AddState(ax::mojom::State::kIgnored);
   inline_box_data_3.AddIntListAttribute(
-      ax::mojom::IntListAttribute::kWordStarts, std::vector<int32_t>{0});
+      ax::mojom::IntListAttribute::kWordStarts, {0});
   inline_box_data_3.AddIntListAttribute(ax::mojom::IntListAttribute::kWordEnds,
-                                        std::vector<int32_t>{4});
+                                        {4});
   inline_box_data_3.AddIntAttribute(ax::mojom::IntAttribute::kPreviousOnLineId,
                                     kInlineBox3Id);
 
@@ -4593,7 +4601,7 @@
   ASSERT_FALSE(text_position->IsIgnored());
   TestPositionType test_position = text_position->CreatePositionAtTextBoundary(
       ax::mojom::TextBoundary::kWordStart, ax::mojom::MoveDirection::kForward,
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box_data_3.id, test_position->anchor_id());
@@ -4601,7 +4609,7 @@
   EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity());
   test_position = text_position->CreatePositionAtTextBoundary(
       ax::mojom::TextBoundary::kWordStart, ax::mojom::MoveDirection::kBackward,
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box_data_2.id, test_position->anchor_id());
@@ -4614,7 +4622,7 @@
   ASSERT_FALSE(text_position->IsIgnored());
   test_position = text_position->CreatePositionAtTextBoundary(
       ax::mojom::TextBoundary::kWordStart, ax::mojom::MoveDirection::kForward,
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box_data_3.id, test_position->anchor_id());
@@ -4622,7 +4630,7 @@
   EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity());
   test_position = text_position->CreatePositionAtTextBoundary(
       ax::mojom::TextBoundary::kWordStart, ax::mojom::MoveDirection::kBackward,
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box_data_2.id, test_position->anchor_id());
@@ -4781,15 +4789,15 @@
   ASSERT_NE(nullptr, null_position);
   TestPositionType test_position =
       null_position->CreatePreviousFormatStartPosition(
-          AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+          AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
   test_position = null_position->CreatePreviousFormatStartPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
   test_position = null_position->CreatePreviousFormatStartPosition(
-      AXBoundaryBehavior::StopAtAnchorBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
 }
@@ -4804,45 +4812,46 @@
 
   TestPositionType test_position =
       tree_position->CreatePreviousFormatStartPosition(
-          AXBoundaryBehavior::CrossBoundary);
+          AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTreePosition());
   EXPECT_EQ(static_text1_.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->child_index());
 
   test_position = test_position->CreatePreviousFormatStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTreePosition());
   EXPECT_EQ(check_box_.id, test_position->anchor_id());
   EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index());
 
   test_position = test_position->CreatePreviousFormatStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTreePosition());
   EXPECT_EQ(button_.id, test_position->anchor_id());
   EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index());
 
-  // StopIfAlreadyAtBoundary shouldn't move, since it's already at a boundary.
+  // kStopAtAnchorBoundaryOrIfAlreadyAtBoundary shouldn't move, since it's
+  // already at a boundary.
   test_position = test_position->CreatePreviousFormatStartPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTreePosition());
   EXPECT_EQ(button_.id, test_position->anchor_id());
   EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index());
 
-  // StopAtLastAnchorBoundary should stop at the start of the whole content
-  // while CrossBoundary should return a null position when crossing it.
+  // kStopAtLastAnchorBoundary should stop at the start of the whole content
+  // while kCrossBoundary should return a null position when crossing it.
   test_position = test_position->CreatePreviousFormatStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTreePosition());
   EXPECT_EQ(button_.id, test_position->anchor_id());
   EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index());
 
   test_position = test_position->CreatePreviousFormatStartPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
 }
@@ -4858,7 +4867,7 @@
 
   TestPositionType test_position =
       text_position->CreatePreviousFormatStartPosition(
-          AXBoundaryBehavior::CrossBoundary);
+          AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box1_.id, test_position->anchor_id());
@@ -4866,38 +4875,39 @@
   EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity());
 
   test_position = test_position->CreatePreviousFormatStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(check_box_.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->text_offset());
 
   test_position = test_position->CreatePreviousFormatStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(button_.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->text_offset());
 
-  // StopIfAlreadyAtBoundary shouldn't move, since it's already at a boundary.
+  // kStopAtAnchorBoundaryOrIfAlreadyAtBoundary shouldn't move, since it's
+  // already at a boundary.
   test_position = test_position->CreatePreviousFormatStartPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(button_.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->text_offset());
 
-  // StopAtLastAnchorBoundary should stop at the start of the whole content
-  // while CrossBoundary should return a null position when crossing it.
+  // kStopAtLastAnchorBoundary should stop at the start of the whole content
+  // while kCrossBoundary should return a null position when crossing it.
   test_position = test_position->CreatePreviousFormatStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(button_.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->text_offset());
 
   test_position = test_position->CreatePreviousFormatStartPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
 }
@@ -4906,11 +4916,11 @@
   TestPositionType null_position = AXNodePosition::CreateNullPosition();
   ASSERT_NE(nullptr, null_position);
   TestPositionType test_position = null_position->CreateNextFormatEndPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
   test_position = null_position->CreateNextFormatEndPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
 }
@@ -4924,52 +4934,53 @@
   ASSERT_TRUE(tree_position->IsTreePosition());
 
   TestPositionType test_position = tree_position->CreateNextFormatEndPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTreePosition());
   EXPECT_EQ(check_box_.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->child_index());
 
   test_position = test_position->CreateNextFormatEndPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTreePosition());
   EXPECT_EQ(inline_box1_.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->child_index());
 
   test_position = test_position->CreateNextFormatEndPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTreePosition());
   EXPECT_EQ(line_break_.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->child_index());
 
   test_position = test_position->CreateNextFormatEndPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTreePosition());
   EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->child_index());
 
-  // StopIfAlreadyAtBoundary shouldn't move, since it's already at a boundary.
+  // kStopAtAnchorBoundaryOrIfAlreadyAtBoundary shouldn't move, since it's
+  // already at a boundary.
   test_position = test_position->CreateNextFormatEndPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTreePosition());
   EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->child_index());
 
-  // StopAtLastAnchorBoundary should stop at the end of the whole content while
-  // CrossBoundary should return a null position when crossing it.
+  // kStopAtLastAnchorBoundary should stop at the end of the whole content while
+  // kCrossBoundary should return a null position when crossing it.
   test_position = test_position->CreateNextFormatEndPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTreePosition());
   EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->child_index());
 
   test_position = test_position->CreateNextFormatEndPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
 }
@@ -4984,59 +4995,60 @@
   ASSERT_TRUE(text_position->IsTextPosition());
 
   TestPositionType test_position = text_position->CreateNextFormatEndPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(button_.id, test_position->anchor_id());
   EXPECT_EQ(1, test_position->text_offset());
 
   test_position = test_position->CreateNextFormatEndPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(check_box_.id, test_position->anchor_id());
   EXPECT_EQ(1, test_position->text_offset());
 
   test_position = test_position->CreateNextFormatEndPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box1_.id, test_position->anchor_id());
   EXPECT_EQ(6, test_position->text_offset());
 
   test_position = test_position->CreateNextFormatEndPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(line_break_.id, test_position->anchor_id());
   EXPECT_EQ(1, test_position->text_offset());
 
   test_position = test_position->CreateNextFormatEndPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
   EXPECT_EQ(6, test_position->text_offset());
 
-  // StopIfAlreadyAtBoundary shouldn't move, since it's already at a boundary.
+  // kStopAtAnchorBoundaryOrIfAlreadyAtBoundary shouldn't move, since it's
+  // already at a boundary.
   test_position = test_position->CreateNextFormatEndPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
   EXPECT_EQ(6, test_position->text_offset());
 
-  // StopAtLastAnchorBoundary should stop at the end of the whole content while
-  // CrossBoundary should return a null position when crossing it.
+  // kStopAtLastAnchorBoundary should stop at the end of the whole content while
+  // kCrossBoundary should return a null position when crossing it.
   test_position = test_position->CreateNextFormatEndPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
   EXPECT_EQ(6, test_position->text_offset());
 
   test_position = test_position->CreateNextFormatEndPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
 }
@@ -5194,7 +5206,7 @@
   // is at the end of "heading 1".
   TestPositionType format_end_position =
       text_position->CreateNextFormatEndPosition(
-          AXBoundaryBehavior::StopAtLastAnchorBoundary);
+          AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, format_end_position);
   EXPECT_TRUE(format_end_position->IsTextPosition());
   EXPECT_EQ(inline_text_4.id, format_end_position->anchor_id());
@@ -5205,7 +5217,7 @@
   // Move position to end of format at "heading 1|select, option 1|<>...", which
   // is at the end of embedded object <select, option 1> (popup_button_5).
   format_end_position = format_end_position->CreateNextFormatEndPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, format_end_position);
   EXPECT_TRUE(format_end_position->IsTextPosition());
   EXPECT_EQ(popup_button_5.id, format_end_position->anchor_id());
@@ -5216,7 +5228,7 @@
   // Move position to end of format at "...|select, option 1|heading 2<>...",
   // which is at the end of "heading 2".
   format_end_position = format_end_position->CreateNextFormatEndPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, format_end_position);
   EXPECT_TRUE(format_end_position->IsTextPosition());
   EXPECT_EQ(inline_text_10.id, format_end_position->anchor_id());
@@ -5228,7 +5240,7 @@
   // "...heading 2|select, option 2|<>|select, option 3|...", which is at the
   // end of embedded object <select, option 2> (popup_button_11).
   format_end_position = format_end_position->CreateNextFormatEndPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, format_end_position);
   EXPECT_TRUE(format_end_position->IsTextPosition());
   EXPECT_EQ(popup_button_11.id, format_end_position->anchor_id());
@@ -5240,7 +5252,7 @@
   // "...heading 2|select, option 2||select, option 3|<>...", which is at the
   // end of embedded object <select, option 3> (popup_button_14).
   format_end_position = format_end_position->CreateNextFormatEndPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, format_end_position);
   EXPECT_TRUE(format_end_position->IsTextPosition());
   EXPECT_EQ(popup_button_14.id, format_end_position->anchor_id());
@@ -5251,7 +5263,7 @@
   // Move position to end of format at "...|select, option 3|more text<>", which
   // is at the end of "more text".
   format_end_position = format_end_position->CreateNextFormatEndPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, format_end_position);
   EXPECT_TRUE(format_end_position->IsTextPosition());
   EXPECT_EQ(inline_text_18.id, format_end_position->anchor_id());
@@ -5289,7 +5301,7 @@
   ASSERT_NE(nullptr, text_position);
   TestPositionType test_position =
       text_position->CreatePreviousFormatStartPosition(
-          AXBoundaryBehavior::CrossBoundary);
+          AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(text_data.id, test_position->anchor_id());
@@ -5301,7 +5313,7 @@
       ax::mojom::TextAffinity::kDownstream);
   ASSERT_NE(nullptr, text_position);
   test_position = text_position->CreateNextFormatEndPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(more_text_data.id, test_position->anchor_id());
@@ -5516,7 +5528,7 @@
     EXPECT_EQ(6, text_position->text_offset());
 
     text_position = text_position->CreateNextFormatEndPosition(
-        AXBoundaryBehavior::StopAtLastAnchorBoundary);
+        AXBoundaryBehavior::kStopAtLastAnchorBoundary);
     ASSERT_NE(nullptr, text_position);
     EXPECT_TRUE(text_position->IsTextPosition());
     EXPECT_EQ(inline_box_11.id, text_position->anchor_id());
@@ -5532,7 +5544,7 @@
     EXPECT_EQ(0, text_position->text_offset());
 
     text_position = text_position->CreatePreviousFormatStartPosition(
-        AXBoundaryBehavior::StopAtLastAnchorBoundary);
+        AXBoundaryBehavior::kStopAtLastAnchorBoundary);
     ASSERT_NE(nullptr, text_position);
     EXPECT_TRUE(text_position->IsTextPosition());
     EXPECT_EQ(inline_box_5.id, text_position->anchor_id());
@@ -5552,7 +5564,7 @@
     EXPECT_EQ(7, text_position->text_offset());
 
     text_position = text_position->CreateNextFormatEndPosition(
-        AXBoundaryBehavior::StopAtLastAnchorBoundary);
+        AXBoundaryBehavior::kStopAtLastAnchorBoundary);
     ASSERT_NE(nullptr, text_position);
     EXPECT_TRUE(text_position->IsTextPosition());
     EXPECT_EQ(inline_box_13.id, text_position->anchor_id());
@@ -5568,7 +5580,7 @@
     EXPECT_EQ(0, text_position->text_offset());
 
     text_position = text_position->CreatePreviousFormatStartPosition(
-        AXBoundaryBehavior::StopAtLastAnchorBoundary);
+        AXBoundaryBehavior::kStopAtLastAnchorBoundary);
     ASSERT_NE(nullptr, text_position);
     EXPECT_TRUE(text_position->IsTextPosition());
     EXPECT_EQ(inline_box_22.id, text_position->anchor_id());
@@ -5581,22 +5593,22 @@
   ASSERT_NE(nullptr, null_position);
   TestPositionType test_position =
       null_position->CreatePreviousPageStartPosition(
-          AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+          AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
 
   test_position = null_position->CreateNextPageStartPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
 
   test_position = null_position->CreatePreviousPageEndPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
 
   test_position = null_position->CreatePreviousPageStartPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
 }
@@ -5614,23 +5626,24 @@
   ASSERT_NE(nullptr, tree_position);
   ASSERT_TRUE(tree_position->IsTreePosition());
 
-  // StopIfAlreadyAtBoundary shouldn't move at all since it's at a boundary.
+  // kStopAtAnchorBoundaryOrIfAlreadyAtBoundary shouldn't move at all since it's
+  // at a boundary.
   TestPositionType test_position = tree_position->CreateNextPageStartPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTreePosition());
   EXPECT_EQ(page_1_data.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->child_index());
 
   test_position = tree_position->CreateNextPageStartPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTreePosition());
   EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
   EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index());
 
   test_position = tree_position->CreateNextPageStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTreePosition());
   EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
@@ -5638,36 +5651,36 @@
 
   // Test CreateNextPageEndPosition until the end of content is reached.
   test_position = tree_position->CreateNextPageEndPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTreePosition());
   EXPECT_EQ(page_1_data.id, test_position->anchor_id());
   EXPECT_EQ(1, test_position->child_index());
 
   test_position = test_position->CreateNextPageEndPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTreePosition());
   EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->child_index());
 
   test_position = test_position->CreateNextPageEndPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTreePosition());
   EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->child_index());
 
-  // StopAtLastAnchorBoundary shouldn't move past the end of the whole content.
+  // kStopAtLastAnchorBoundary shouldn't move past the end of the whole content.
   test_position = test_position->CreateNextPageStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTreePosition());
   EXPECT_EQ(page_3_text_data.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->child_index());
 
   test_position = test_position->CreateNextPageEndPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTreePosition());
   EXPECT_EQ(page_3_text_data.id, test_position->anchor_id());
@@ -5675,69 +5688,69 @@
 
   // Moving forward past the end should return a null position.
   TestPositionType null_position = test_position->CreateNextPageStartPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, null_position);
   EXPECT_TRUE(null_position->IsNullPosition());
 
   null_position = test_position->CreateNextPageEndPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, null_position);
   EXPECT_TRUE(null_position->IsNullPosition());
 
   // Now move backward through the accessibility tree.
   tree_position = test_position->CreatePreviousPageEndPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_NE(nullptr, tree_position);
   EXPECT_TRUE(tree_position->IsTreePosition());
   EXPECT_EQ(page_3_text_data.id, tree_position->anchor_id());
   EXPECT_EQ(0, tree_position->child_index());
 
   test_position = tree_position->CreatePreviousPageEndPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTreePosition());
   EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->child_index());
 
   test_position = tree_position->CreatePreviousPageEndPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTreePosition());
   EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->child_index());
 
   test_position = test_position->CreatePreviousPageStartPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTreePosition());
   EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
   EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index());
 
   test_position = test_position->CreatePreviousPageStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTreePosition());
   EXPECT_EQ(page_1_text_data.id, test_position->anchor_id());
   EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index());
 
   test_position = test_position->CreatePreviousPageStartPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTreePosition());
   EXPECT_EQ(page_1_text_data.id, test_position->anchor_id());
   EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index());
 
-  // StopAtLastAnchorBoundary shouldn't move past the start of the whole
+  // kStopAtLastAnchorBoundary shouldn't move past the start of the whole
   // content.
   test_position = test_position->CreatePreviousPageStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTreePosition());
   EXPECT_EQ(page_1_text_data.id, test_position->anchor_id());
   EXPECT_EQ(AXNodePosition::BEFORE_TEXT, test_position->child_index());
 
   test_position = test_position->CreatePreviousPageEndPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTreePosition());
   EXPECT_EQ(page_1_text_data.id, test_position->anchor_id());
@@ -5745,12 +5758,12 @@
 
   // Moving before the start should return a null position.
   null_position = test_position->CreatePreviousPageStartPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, null_position);
   EXPECT_TRUE(null_position->IsNullPosition());
 
   null_position = test_position->CreatePreviousPageEndPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, null_position);
   EXPECT_TRUE(null_position->IsNullPosition());
 }
@@ -5769,23 +5782,24 @@
   ASSERT_NE(nullptr, text_position);
   ASSERT_TRUE(text_position->IsTextPosition());
 
-  // StopIfAlreadyAtBoundary shouldn't move at all since it's at a boundary.
+  // kStopAtAnchorBoundaryOrIfAlreadyAtBoundary shouldn't move at all since it's
+  // at a boundary.
   TestPositionType test_position = text_position->CreateNextPageStartPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(page_1_text_data.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->text_offset());
 
   test_position = text_position->CreateNextPageStartPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->text_offset());
 
   test_position = text_position->CreateNextPageStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
@@ -5793,36 +5807,36 @@
 
   // Test CreateNextPageEndPosition until the end of content is reached.
   test_position = test_position->CreateNextPageEndPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
   EXPECT_EQ(19, test_position->text_offset());
 
   test_position = test_position->CreateNextPageEndPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(page_3_text_data.id, test_position->anchor_id());
   EXPECT_EQ(24, test_position->text_offset());
 
   test_position = test_position->CreateNextPageEndPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(page_3_text_data.id, test_position->anchor_id());
   EXPECT_EQ(24, test_position->text_offset());
 
-  // StopAtLastAnchorBoundary shouldn't move past the end of the whole content.
+  // kStopAtLastAnchorBoundary shouldn't move past the end of the whole content.
   test_position = test_position->CreateNextPageStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(page_3_text_data.id, test_position->anchor_id());
   EXPECT_EQ(24, test_position->text_offset());
 
   test_position = test_position->CreateNextPageEndPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(page_3_text_data.id, test_position->anchor_id());
@@ -5830,69 +5844,69 @@
 
   // Moving forward past the end should return a null position.
   TestPositionType null_position = test_position->CreateNextPageStartPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, null_position);
   EXPECT_TRUE(null_position->IsNullPosition());
 
   null_position = test_position->CreateNextPageEndPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, null_position);
   EXPECT_TRUE(null_position->IsNullPosition());
 
   // Now move backward through the accessibility tree.
   text_position = test_position->CreatePreviousPageEndPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_NE(nullptr, text_position);
   EXPECT_TRUE(text_position->IsTextPosition());
   EXPECT_EQ(page_3_text_data.id, text_position->anchor_id());
   EXPECT_EQ(24, text_position->text_offset());
 
   test_position = text_position->CreatePreviousPageEndPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
   EXPECT_EQ(19, test_position->text_offset());
 
   test_position = text_position->CreatePreviousPageEndPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
   EXPECT_EQ(19, test_position->text_offset());
 
   test_position = test_position->CreatePreviousPageStartPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(page_2_text_data.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->text_offset());
 
   test_position = test_position->CreatePreviousPageStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(page_1_text_data.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->text_offset());
 
   test_position = test_position->CreatePreviousPageStartPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(page_1_text_data.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->text_offset());
 
-  // StopAtLastAnchorBoundary shouldn't move past the start of the whole
+  // kStopAtLastAnchorBoundary shouldn't move past the start of the whole
   // content.
   test_position = test_position->CreatePreviousPageStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(page_1_text_data.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->text_offset());
 
   test_position = test_position->CreatePreviousPageEndPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(page_1_text_data.id, test_position->anchor_id());
@@ -5900,19 +5914,24 @@
 
   // Moving before the start should return a null position.
   null_position = test_position->CreatePreviousPageStartPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, null_position);
   EXPECT_TRUE(null_position->IsNullPosition());
 
   null_position = test_position->CreatePreviousPageEndPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, null_position);
   EXPECT_TRUE(null_position->IsNullPosition());
 }
 
 TEST_F(AXPositionTest, CreatePositionAtPageBoundaryWithNonPaginatedDocument) {
+  // We start from the second character in the whole content instead of the
+  // first, so that with `AXBoundaryBehavior::kCrossBoundary` we would be able
+  // to move back to the start of the page. Otherwise, if we had started from
+  // the first character, we would already be at the start of the page, and thus
+  // have gotten the null position.
   TestPositionType text_position = AXNodePosition::CreateTextPosition(
-      GetTreeID(), static_text1_.id, 0 /* text_offset */,
+      GetTreeID(), static_text1_.id, 1 /* text_offset */,
       ax::mojom::TextAffinity::kDownstream);
   ASSERT_NE(nullptr, text_position);
 
@@ -5921,7 +5940,7 @@
   // page)
   TestPositionType test_position =
       text_position->CreatePreviousPageStartPosition(
-          AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+          AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(button_.id, test_position->anchor_id());
@@ -5930,21 +5949,21 @@
   // Since there is no next page, CreateNextPageStartPosition should return a
   // null position
   test_position = text_position->CreateNextPageStartPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
 
   // Since there is no previous page, CreatePreviousPageEndPosition should
   // return a null position
   test_position = text_position->CreatePreviousPageEndPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
 
   // Since there are no distinct pages, CreateNextPageEndPosition should move
   // to the end of the whole content, as if it's one large page.
   test_position = text_position->CreateNextPageEndPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
@@ -5953,7 +5972,7 @@
   // CreatePreviousPageStartPosition should move back to the beginning of the
   // whole content.
   test_position = test_position->CreatePreviousPageStartPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(button_.id, test_position->anchor_id());
@@ -9303,11 +9322,11 @@
   TestPositionType null_position = AXNodePosition::CreateNullPosition();
   ASSERT_NE(nullptr, null_position);
   TestPositionType test_position = null_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
   test_position = null_position->CreatePreviousCharacterPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
 }
@@ -9337,14 +9356,14 @@
 
   // Test basic cases with static MaxTextOffset
   TestPositionType test_position = text_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_TRUE(test_position->IsValid());
   ASSERT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(text_data.id, test_position->anchor_id());
   EXPECT_EQ(9, test_position->text_offset());
   test_position = text_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   ASSERT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
 
@@ -9369,14 +9388,14 @@
   // Now repeat the prior tests and ensure that we can create next character
   // positions with the new, valid MaxTextOffset (8).
   test_position = text_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_TRUE(test_position->IsValid());
   ASSERT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(text_data.id, test_position->anchor_id());
   EXPECT_EQ(8, test_position->text_offset());
   test_position = text_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   ASSERT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
 
@@ -9477,25 +9496,25 @@
   ASSERT_TRUE(text_position->IsTextPosition());
 
   TestPositionType test_position = text_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box1_.id, test_position->anchor_id());
   EXPECT_EQ(4, test_position->text_offset());
   test_position = text_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box1_.id, test_position->anchor_id());
   EXPECT_EQ(5, test_position->text_offset());
   test_position = text_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::StopAtAnchorBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box1_.id, test_position->anchor_id());
   EXPECT_EQ(5, test_position->text_offset());
   test_position = text_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box1_.id, test_position->anchor_id());
@@ -9508,25 +9527,25 @@
   ASSERT_TRUE(text_position->IsTextPosition());
 
   test_position = text_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box1_.id, test_position->anchor_id());
   EXPECT_EQ(5, test_position->text_offset());
   test_position = text_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box1_.id, test_position->anchor_id());
   EXPECT_EQ(6, test_position->text_offset());
   test_position = text_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::StopAtAnchorBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box1_.id, test_position->anchor_id());
   EXPECT_EQ(6, test_position->text_offset());
   test_position = text_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box1_.id, test_position->anchor_id());
@@ -9539,25 +9558,25 @@
   ASSERT_TRUE(text_position->IsTextPosition());
 
   test_position = text_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box1_.id, test_position->anchor_id());
   EXPECT_EQ(6, test_position->text_offset());
   test_position = text_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(line_break_.id, test_position->anchor_id());
   EXPECT_EQ(1, test_position->text_offset());
   test_position = text_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::StopAtAnchorBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box1_.id, test_position->anchor_id());
   EXPECT_EQ(6, test_position->text_offset());
   test_position = text_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(line_break_.id, test_position->anchor_id());
@@ -9570,23 +9589,23 @@
   ASSERT_TRUE(text_position->IsTextPosition());
 
   test_position = text_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
   test_position = text_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
   EXPECT_EQ(6, test_position->text_offset());
   test_position = text_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::StopAtAnchorBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
   EXPECT_EQ(6, test_position->text_offset());
   test_position = text_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
@@ -9599,25 +9618,25 @@
   ASSERT_TRUE(text_position->IsTextPosition());
 
   test_position = text_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box1_.id, test_position->anchor_id());
   EXPECT_EQ(1, test_position->text_offset());
   test_position = text_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(check_box_.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->text_offset());
   test_position = text_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::StopAtAnchorBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(check_box_.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->text_offset());
   test_position = text_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box1_.id, test_position->anchor_id());
@@ -9630,7 +9649,7 @@
   ASSERT_TRUE(text_position->IsTextPosition());
 
   test_position = text_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(text_field_.id, test_position->anchor_id());
@@ -9645,7 +9664,7 @@
   ASSERT_TRUE(text_position->IsTextPosition());
 
   test_position = text_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(text_field_.id, test_position->anchor_id());
@@ -9663,25 +9682,25 @@
 
   TestPositionType test_position =
       text_position->CreatePreviousCharacterPosition(
-          AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+          AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
   EXPECT_EQ(5, test_position->text_offset());
   test_position = text_position->CreatePreviousCharacterPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
   EXPECT_EQ(4, test_position->text_offset());
   test_position = text_position->CreatePreviousCharacterPosition(
-      AXBoundaryBehavior::StopAtAnchorBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
   EXPECT_EQ(4, test_position->text_offset());
   test_position = text_position->CreatePreviousCharacterPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
@@ -9694,25 +9713,25 @@
   ASSERT_TRUE(text_position->IsTextPosition());
 
   test_position = text_position->CreatePreviousCharacterPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
   EXPECT_EQ(1, test_position->text_offset());
   test_position = text_position->CreatePreviousCharacterPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->text_offset());
   test_position = text_position->CreatePreviousCharacterPosition(
-      AXBoundaryBehavior::StopAtAnchorBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->text_offset());
   test_position = text_position->CreatePreviousCharacterPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
@@ -9725,25 +9744,25 @@
   ASSERT_TRUE(text_position->IsTextPosition());
 
   test_position = text_position->CreatePreviousCharacterPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->text_offset());
   test_position = text_position->CreatePreviousCharacterPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(line_break_.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->text_offset());
   test_position = text_position->CreatePreviousCharacterPosition(
-      AXBoundaryBehavior::StopAtAnchorBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->text_offset());
   test_position = text_position->CreatePreviousCharacterPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(line_break_.id, test_position->anchor_id());
@@ -9756,23 +9775,23 @@
   ASSERT_TRUE(text_position->IsTextPosition());
 
   test_position = text_position->CreatePreviousCharacterPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
   test_position = text_position->CreatePreviousCharacterPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box1_.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->text_offset());
   test_position = text_position->CreatePreviousCharacterPosition(
-      AXBoundaryBehavior::StopAtAnchorBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box1_.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->text_offset());
   test_position = text_position->CreatePreviousCharacterPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box1_.id, test_position->anchor_id());
@@ -9785,23 +9804,23 @@
   ASSERT_TRUE(text_position->IsTextPosition());
 
   test_position = text_position->CreatePreviousCharacterPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
   test_position = text_position->CreatePreviousCharacterPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(check_box_.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->text_offset());
   test_position = text_position->CreatePreviousCharacterPosition(
-      AXBoundaryBehavior::StopAtAnchorBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(check_box_.id, test_position->anchor_id());
   EXPECT_EQ(0, test_position->text_offset());
   test_position = text_position->CreatePreviousCharacterPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(check_box_.id, test_position->anchor_id());
@@ -9814,7 +9833,7 @@
   ASSERT_TRUE(text_position->IsTextPosition());
 
   test_position = text_position->CreatePreviousCharacterPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(text_field_.id, test_position->anchor_id());
@@ -9837,7 +9856,7 @@
        ++iter) {
     const int text_offset = *iter;
     test_position = test_position->CreateNextCharacterPosition(
-        AXBoundaryBehavior::CrossBoundary);
+        AXBoundaryBehavior::kCrossBoundary);
     ASSERT_NE(nullptr, test_position);
     EXPECT_TRUE(test_position->IsTextPosition());
 
@@ -9855,7 +9874,7 @@
       GetTreeID(), GetTree()->root()->id(), 3 /* text_offset */,
       ax::mojom::TextAffinity::kDownstream);
   test_position = test_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   ASSERT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(GetTree()->root()->id(), test_position->anchor_id());
@@ -9866,7 +9885,7 @@
       GetTreeID(), GetTree()->root()->id(), 4 /* text_offset */,
       ax::mojom::TextAffinity::kDownstream);
   test_position = test_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   ASSERT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(GetTree()->root()->id(), test_position->anchor_id());
@@ -9877,7 +9896,7 @@
       GetTreeID(), GetTree()->root()->id(), 9 /* text_offset */,
       ax::mojom::TextAffinity::kUpstream);
   test_position = test_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   ASSERT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(GetTree()->root()->id(), test_position->anchor_id());
@@ -9888,7 +9907,7 @@
       GetTreeID(), GetTree()->root()->id(), 10 /* text_offset */,
       ax::mojom::TextAffinity::kUpstream);
   test_position = test_position->CreateNextCharacterPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   ASSERT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(GetTree()->root()->id(), test_position->anchor_id());
@@ -9912,7 +9931,7 @@
        ++iter) {
     const int text_offset = *iter;
     test_position = test_position->CreatePreviousCharacterPosition(
-        AXBoundaryBehavior::CrossBoundary);
+        AXBoundaryBehavior::kCrossBoundary);
     ASSERT_NE(nullptr, test_position);
     EXPECT_TRUE(test_position->IsTextPosition());
 
@@ -9930,7 +9949,7 @@
       GetTreeID(), GetTree()->root()->id(), 3 /* text_offset */,
       ax::mojom::TextAffinity::kDownstream);
   test_position = test_position->CreatePreviousCharacterPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   ASSERT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(GetTree()->root()->id(), test_position->anchor_id());
@@ -9941,7 +9960,7 @@
       GetTreeID(), GetTree()->root()->id(), 4 /* text_offset */,
       ax::mojom::TextAffinity::kDownstream);
   test_position = test_position->CreatePreviousCharacterPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   ASSERT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(GetTree()->root()->id(), test_position->anchor_id());
@@ -9952,7 +9971,7 @@
       GetTreeID(), GetTree()->root()->id(), 9 /* text_offset */,
       ax::mojom::TextAffinity::kUpstream);
   test_position = test_position->CreatePreviousCharacterPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   ASSERT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(GetTree()->root()->id(), test_position->anchor_id());
@@ -9963,7 +9982,7 @@
       GetTreeID(), GetTree()->root()->id(), 10 /* text_offset */,
       ax::mojom::TextAffinity::kUpstream);
   test_position = test_position->CreatePreviousCharacterPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   ASSERT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(GetTree()->root()->id(), test_position->anchor_id());
@@ -9983,7 +10002,7 @@
   while (!text_position->IsNullPosition()) {
     TestPositionType moved_position =
         text_position->CreateNextCharacterPosition(
-            AXBoundaryBehavior::CrossBoundary);
+            AXBoundaryBehavior::kCrossBoundary);
     ASSERT_NE(nullptr, moved_position);
 
     text_position = std::move(moved_position);
@@ -10000,7 +10019,7 @@
   while (!text_position->IsNullPosition()) {
     TestPositionType moved_position =
         text_position->CreatePreviousCharacterPosition(
-            AXBoundaryBehavior::CrossBoundary);
+            AXBoundaryBehavior::kCrossBoundary);
     ASSERT_NE(nullptr, moved_position);
 
     text_position = std::move(moved_position);
@@ -10015,11 +10034,11 @@
   TestPositionType null_position = AXNodePosition::CreateNullPosition();
   ASSERT_NE(nullptr, null_position);
   TestPositionType test_position = null_position->CreateNextWordStartPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
   test_position = null_position->CreatePreviousWordStartPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
 }
@@ -10028,11 +10047,11 @@
   TestPositionType null_position = AXNodePosition::CreateNullPosition();
   ASSERT_NE(nullptr, null_position);
   TestPositionType test_position = null_position->CreateNextWordEndPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
   test_position = null_position->CreatePreviousWordEndPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
 }
@@ -11070,7 +11089,7 @@
 
   TestPositionType next_line_start_position =
       text_position->CreateNextLineStartPosition(
-          AXBoundaryBehavior::StopAtLastAnchorBoundary);
+          AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, next_line_start_position);
   EXPECT_TRUE(next_line_start_position->IsTextPosition());
   EXPECT_EQ(inline_box3.id, next_line_start_position->anchor_id());
@@ -11078,7 +11097,7 @@
 
   TestPositionType previous_line_start_position =
       text_position->CreatePreviousLineStartPosition(
-          AXBoundaryBehavior::StopAtLastAnchorBoundary);
+          AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, previous_line_start_position);
   EXPECT_TRUE(previous_line_start_position->IsTextPosition());
   EXPECT_EQ(inline_box1.id, previous_line_start_position->anchor_id());
@@ -11086,7 +11105,7 @@
 
   TestPositionType next_line_end_position =
       text_position->CreateNextLineEndPosition(
-          AXBoundaryBehavior::StopAtLastAnchorBoundary);
+          AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, next_line_end_position);
   EXPECT_TRUE(next_line_end_position->IsTextPosition());
   EXPECT_EQ(inline_box3.id, next_line_end_position->anchor_id());
@@ -11094,7 +11113,7 @@
 
   TestPositionType previous_line_end_position =
       text_position->CreatePreviousLineEndPosition(
-          AXBoundaryBehavior::StopAtLastAnchorBoundary);
+          AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, previous_line_end_position);
   EXPECT_TRUE(previous_line_end_position->IsTextPosition());
   EXPECT_EQ(inline_box1.id, previous_line_end_position->anchor_id());
@@ -11229,7 +11248,7 @@
 
   // "1. <f>irst item\n2. second item"
   text_position = text_position->CreateNextWordStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, text_position);
   ASSERT_TRUE(text_position->IsTextPosition());
   ASSERT_EQ(inline_box2.id, text_position->anchor_id());
@@ -11237,7 +11256,7 @@
 
   // "1. first <i>tem\n2. second item"
   text_position = text_position->CreateNextWordStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, text_position);
   ASSERT_TRUE(text_position->IsTextPosition());
   ASSERT_EQ(inline_box2.id, text_position->anchor_id());
@@ -11245,7 +11264,7 @@
 
   // "1. first item\n<2>. second item"
   text_position = text_position->CreateNextWordStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, text_position);
   ASSERT_TRUE(text_position->IsTextPosition());
   ASSERT_EQ(inline_box3.id, text_position->anchor_id());
@@ -11253,7 +11272,7 @@
 
   // "1. first item\n2. <s>econd item"
   text_position = text_position->CreateNextWordStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, text_position);
   ASSERT_TRUE(text_position->IsTextPosition());
   ASSERT_EQ(inline_box4.id, text_position->anchor_id());
@@ -11261,7 +11280,7 @@
 
   // "1. first item\n2. second <i>tem"
   text_position = text_position->CreateNextWordStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, text_position);
   ASSERT_TRUE(text_position->IsTextPosition());
   ASSERT_EQ(inline_box4.id, text_position->anchor_id());
@@ -11396,7 +11415,7 @@
 
   // "1. first item\n2. second <i>tem"
   text_position = text_position->CreatePreviousWordStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, text_position);
   ASSERT_TRUE(text_position->IsTextPosition());
   ASSERT_EQ(inline_box4.id, text_position->anchor_id());
@@ -11404,7 +11423,7 @@
 
   // "1. first item\n2. <s>econd item"
   text_position = text_position->CreatePreviousWordStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, text_position);
   ASSERT_TRUE(text_position->IsTextPosition());
   ASSERT_EQ(inline_box4.id, text_position->anchor_id());
@@ -11412,7 +11431,7 @@
 
   // "1. first item\n<2>. second item"
   text_position = text_position->CreatePreviousWordStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, text_position);
   ASSERT_TRUE(text_position->IsTextPosition());
   ASSERT_EQ(inline_box3.id, text_position->anchor_id());
@@ -11420,7 +11439,7 @@
 
   // "1. first <i>tem\n2. <s>econd item"
   text_position = text_position->CreatePreviousWordStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, text_position);
   ASSERT_TRUE(text_position->IsTextPosition());
   ASSERT_EQ(inline_box2.id, text_position->anchor_id());
@@ -11428,7 +11447,7 @@
 
   // "1. <f>irst item\n2. second item"
   text_position = text_position->CreatePreviousWordStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, text_position);
   ASSERT_TRUE(text_position->IsTextPosition());
   ASSERT_EQ(inline_box2.id, text_position->anchor_id());
@@ -11436,7 +11455,7 @@
 
   // "<1>. first item\n2. second item"
   text_position = text_position->CreatePreviousWordStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, text_position);
   ASSERT_TRUE(text_position->IsTextPosition());
   ASSERT_EQ(inline_box1.id, text_position->anchor_id());
@@ -11573,7 +11592,7 @@
       ax::mojom::TextAffinity::kDownstream);
 
   TestPositionType result_position =
-      position->CreateNextWordStartPosition(AXBoundaryBehavior::CrossBoundary);
+      position->CreateNextWordStartPosition(AXBoundaryBehavior::kCrossBoundary);
   EXPECT_TRUE(result_position->IsTextPosition());
   EXPECT_EQ(text_field_4.id, result_position->anchor_id());
   EXPECT_EQ(0, result_position->text_offset());
@@ -11582,7 +11601,7 @@
 
   position = std::move(result_position);
   result_position =
-      position->CreateNextWordStartPosition(AXBoundaryBehavior::CrossBoundary);
+      position->CreateNextWordStartPosition(AXBoundaryBehavior::kCrossBoundary);
   EXPECT_TRUE(result_position->IsTextPosition());
   EXPECT_EQ(inline_box_7.id, result_position->anchor_id());
   EXPECT_EQ(1, result_position->text_offset());
@@ -11592,7 +11611,7 @@
   // CreatePreviousWordStartPosition tests.
   position = std::move(result_position);
   result_position = position->CreatePreviousWordStartPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_TRUE(result_position->IsTextPosition());
   EXPECT_EQ(text_field_4.id, result_position->anchor_id());
   EXPECT_EQ(0, result_position->text_offset());
@@ -11601,7 +11620,7 @@
 
   position = std::move(result_position);
   result_position = position->CreatePreviousWordStartPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_TRUE(result_position->IsTextPosition());
   EXPECT_EQ(inline_box_3.id, result_position->anchor_id());
   EXPECT_EQ(0, result_position->text_offset());
@@ -11611,7 +11630,7 @@
   // CreateNextWordEndPosition tests.
   position = std::move(result_position);
   result_position =
-      position->CreateNextWordEndPosition(AXBoundaryBehavior::CrossBoundary);
+      position->CreateNextWordEndPosition(AXBoundaryBehavior::kCrossBoundary);
   EXPECT_TRUE(result_position->IsTextPosition());
   EXPECT_EQ(inline_box_3.id, result_position->anchor_id());
   EXPECT_EQ(6, result_position->text_offset());
@@ -11620,7 +11639,7 @@
 
   position = std::move(result_position);
   result_position =
-      position->CreateNextWordEndPosition(AXBoundaryBehavior::CrossBoundary);
+      position->CreateNextWordEndPosition(AXBoundaryBehavior::kCrossBoundary);
   EXPECT_TRUE(result_position->IsTextPosition());
   // The position would be on `text_field_4` instead of on `generic_container_5`
   // because the latter is ignored, and by design we prefer not to create
@@ -11632,7 +11651,7 @@
 
   position = std::move(result_position);
   result_position =
-      position->CreateNextWordEndPosition(AXBoundaryBehavior::CrossBoundary);
+      position->CreateNextWordEndPosition(AXBoundaryBehavior::kCrossBoundary);
   EXPECT_TRUE(result_position->IsTextPosition());
   EXPECT_EQ(inline_box_7.id, result_position->anchor_id());
   EXPECT_EQ(6, result_position->text_offset());
@@ -11642,7 +11661,7 @@
   // CreatePreviousWordEndPosition tests.
   position = std::move(result_position);
   result_position = position->CreatePreviousWordEndPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_TRUE(result_position->IsTextPosition());
   // The position would be on `text_field_4` instead of on `generic_container_5`
   // because the latter is ignored, and by design we prefer not to create
@@ -11654,7 +11673,7 @@
 
   position = std::move(result_position);
   result_position = position->CreatePreviousWordEndPosition(
-      AXBoundaryBehavior::CrossBoundary);
+      AXBoundaryBehavior::kCrossBoundary);
   EXPECT_TRUE(result_position->IsTextPosition());
   EXPECT_EQ(inline_box_3.id, result_position->anchor_id());
   EXPECT_EQ(6, result_position->text_offset());
@@ -11719,7 +11738,7 @@
   ASSERT_NE(nullptr, text_position);
 
   text_position = text_position->CreatePreviousFormatStartPosition(
-      AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+      AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
   ASSERT_NE(nullptr, text_position);
   EXPECT_TRUE(text_position->IsTextPosition());
   EXPECT_EQ(generic_container_12.id, text_position->anchor_id());
@@ -11741,7 +11760,7 @@
   ASSERT_NE(nullptr, text_position);
 
   text_position = text_position->CreateNextParagraphEndPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, text_position);
   EXPECT_TRUE(text_position->IsLeafTextPosition());
   EXPECT_EQ(button_14.id, text_position->anchor_id());
@@ -11846,10 +11865,14 @@
   inline_box_8.id = 8;
 
   root_1.role = ax::mojom::Role::kRootWebArea;
+  root_1.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject,
+                          true);
   root_1.child_ids = {static_text_2.id, popup_button_4.id, static_text_7.id};
 
   static_text_2.role = ax::mojom::Role::kStaticText;
   static_text_2.SetName("Hi");
+  static_text_2.AddBoolAttribute(
+      ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
   static_text_2.child_ids = {inline_box_3.id};
 
   inline_box_3.role = ax::mojom::Role::kInlineTextBox;
@@ -11868,9 +11891,13 @@
   menu_list_option_6.role = ax::mojom::Role::kMenuListOption;
   menu_list_option_6.SetName("Option");
   menu_list_option_6.SetNameFrom(ax::mojom::NameFrom::kContents);
+  menu_list_option_6.AddBoolAttribute(
+      ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
 
   static_text_7.role = ax::mojom::Role::kStaticText;
   static_text_7.SetName("3.14");
+  static_text_7.AddBoolAttribute(
+      ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
   static_text_7.child_ids = {inline_box_8.id};
 
   inline_box_8.role = ax::mojom::Role::kInlineTextBox;
@@ -11889,13 +11916,13 @@
   ASSERT_NE(nullptr, position);
 
   position = position->CreateNextParagraphStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, position);
   EXPECT_EQ(popup_button_4.id, position->anchor_id());
   EXPECT_EQ(0, position->text_offset());
 
   position = position->CreateNextParagraphStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, position);
   EXPECT_EQ(inline_box_8.id, position->anchor_id());
   EXPECT_EQ(0, position->text_offset());
@@ -11906,15 +11933,15 @@
   ASSERT_NE(nullptr, position);
 
   position = position->CreatePreviousParagraphEndPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, position);
   EXPECT_EQ(popup_button_4.id, position->anchor_id());
   // The content of this popup button should be replaced with the empty object
-  // character of length 1.
+  // replacement character of length 1.
   EXPECT_EQ(1, position->text_offset());
 
   position = position->CreatePreviousParagraphEndPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, position);
   EXPECT_EQ(inline_box_3.id, position->anchor_id());
   EXPECT_EQ(2, position->text_offset());
@@ -11932,13 +11959,13 @@
   ASSERT_NE(nullptr, position);
 
   position = position->CreateNextParagraphStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, position);
   EXPECT_EQ(menu_list_option_6.id, position->anchor_id());
   EXPECT_EQ(0, position->text_offset());
 
   position = position->CreateNextParagraphStartPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, position);
   EXPECT_EQ(inline_box_8.id, position->anchor_id());
   EXPECT_EQ(0, position->text_offset());
@@ -11949,13 +11976,13 @@
   ASSERT_NE(nullptr, position);
 
   position = position->CreatePreviousParagraphEndPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, position);
   EXPECT_EQ(menu_list_option_6.id, position->anchor_id());
-  EXPECT_EQ(1, position->text_offset());
+  EXPECT_EQ(6, position->text_offset());
 
   position = position->CreatePreviousParagraphEndPosition(
-      AXBoundaryBehavior::StopAtLastAnchorBoundary);
+      AXBoundaryBehavior::kStopAtLastAnchorBoundary);
   ASSERT_NE(nullptr, position);
   EXPECT_EQ(inline_box_3.id, position->anchor_id());
   EXPECT_EQ(2, position->text_offset());
@@ -12108,32 +12135,32 @@
         ExpandToEnclosingTextBoundaryTestParam{
             ax::mojom::TextBoundary::kCharacter,
             AXRangeExpandBehavior::kLeftFirst,
-            "TextPosition anchor_id=4 text_offset=6 affinity=downstream "
-            "annotated_text=Line 1<\n>Line 2",
-            "TextPosition anchor_id=4 text_offset=7 affinity=downstream "
-            "annotated_text=Line 1\n<L>ine 2"},
-        ExpandToEnclosingTextBoundaryTestParam{
-            ax::mojom::TextBoundary::kCharacter,
-            AXRangeExpandBehavior::kRightFirst,
             "TextPosition anchor_id=4 text_offset=7 affinity=downstream "
             "annotated_text=Line 1\n<L>ine 2",
             "TextPosition anchor_id=4 text_offset=8 affinity=downstream "
             "annotated_text=Line 1\nL<i>ne 2"},
         ExpandToEnclosingTextBoundaryTestParam{
-            ax::mojom::TextBoundary::kFormatEnd,
-            AXRangeExpandBehavior::kLeftFirst,
+            ax::mojom::TextBoundary::kCharacter,
+            AXRangeExpandBehavior::kRightFirst,
             "TextPosition anchor_id=4 text_offset=6 affinity=downstream "
             "annotated_text=Line 1<\n>Line 2",
             "TextPosition anchor_id=4 text_offset=7 affinity=downstream "
             "annotated_text=Line 1\n<L>ine 2"},
         ExpandToEnclosingTextBoundaryTestParam{
             ax::mojom::TextBoundary::kFormatEnd,
-            AXRangeExpandBehavior::kRightFirst,
-            "TextPosition anchor_id=4 text_offset=7 affinity=downstream "
+            AXRangeExpandBehavior::kLeftFirst,
+            "TextPosition anchor_id=4 text_offset=7 affinity=upstream "
             "annotated_text=Line 1\n<L>ine 2",
             "TextPosition anchor_id=4 text_offset=13 affinity=downstream "
             "annotated_text=Line 1\nLine 2<>"},
         ExpandToEnclosingTextBoundaryTestParam{
+            ax::mojom::TextBoundary::kFormatEnd,
+            AXRangeExpandBehavior::kRightFirst,
+            "TextPosition anchor_id=4 text_offset=6 affinity=downstream "
+            "annotated_text=Line 1<\n>Line 2",
+            "TextPosition anchor_id=4 text_offset=7 affinity=upstream "
+            "annotated_text=Line 1\n<L>ine 2"},
+        ExpandToEnclosingTextBoundaryTestParam{
             ax::mojom::TextBoundary::kLineEnd,
             AXRangeExpandBehavior::kLeftFirst,
             "TextPosition anchor_id=4 text_offset=6 affinity=downstream "
@@ -12150,24 +12177,24 @@
         ExpandToEnclosingTextBoundaryTestParam{
             ax::mojom::TextBoundary::kLineStart,
             AXRangeExpandBehavior::kLeftFirst,
+            "TextPosition anchor_id=4 text_offset=7 affinity=downstream "
+            "annotated_text=Line 1\n<L>ine 2",
+            "TextPosition anchor_id=4 text_offset=13 affinity=downstream "
+            "annotated_text=Line 1\nLine 2<>"},
+        ExpandToEnclosingTextBoundaryTestParam{
+            ax::mojom::TextBoundary::kLineStart,
+            AXRangeExpandBehavior::kRightFirst,
             "TextPosition anchor_id=4 text_offset=0 affinity=downstream "
             "annotated_text=<L>ine 1\nLine 2",
             "TextPosition anchor_id=4 text_offset=7 affinity=downstream "
             "annotated_text=Line 1\n<L>ine 2"},
         ExpandToEnclosingTextBoundaryTestParam{
-            ax::mojom::TextBoundary::kLineStart,
-            AXRangeExpandBehavior::kRightFirst,
-            "TextPosition anchor_id=4 text_offset=7 affinity=downstream "
-            "annotated_text=Line 1\n<L>ine 2",
-            "TextPosition anchor_id=4 text_offset=13 affinity=downstream "
-            "annotated_text=Line 1\nLine 2<>"},
-        ExpandToEnclosingTextBoundaryTestParam{
             ax::mojom::TextBoundary::kLineStartOrEnd,
             AXRangeExpandBehavior::kLeftFirst,
-            "TextPosition anchor_id=4 text_offset=0 affinity=downstream "
-            "annotated_text=<L>ine 1\nLine 2",
-            "TextPosition anchor_id=4 text_offset=6 affinity=downstream "
-            "annotated_text=Line 1<\n>Line 2"},
+            "TextPosition anchor_id=4 text_offset=7 affinity=downstream "
+            "annotated_text=Line 1\n<L>ine 2",
+            "TextPosition anchor_id=4 text_offset=13 affinity=downstream "
+            "annotated_text=Line 1\nLine 2<>"},
         ExpandToEnclosingTextBoundaryTestParam{
             ax::mojom::TextBoundary::kLineStartOrEnd,
             AXRangeExpandBehavior::kRightFirst,
@@ -12205,81 +12232,122 @@
         ExpandToEnclosingTextBoundaryTestParam{
             ax::mojom::TextBoundary::kParagraphStart,
             AXRangeExpandBehavior::kLeftFirst,
-            "TextPosition anchor_id=4 text_offset=0 affinity=downstream "
-            "annotated_text=<L>ine 1\nLine 2",
             "TextPosition anchor_id=4 text_offset=7 affinity=downstream "
-            "annotated_text=Line 1\n<L>ine 2"},
+            "annotated_text=Line 1\n<L>ine 2",
+            "TextPosition anchor_id=4 text_offset=13 affinity=downstream "
+            "annotated_text=Line 1\nLine 2<>"},
         ExpandToEnclosingTextBoundaryTestParam{
             ax::mojom::TextBoundary::kParagraphStart,
             AXRangeExpandBehavior::kRightFirst,
-            "TextPosition anchor_id=4 text_offset=7 affinity=downstream "
-            "annotated_text=Line 1\n<L>ine 2",
-            "TextPosition anchor_id=4 text_offset=13 affinity=downstream "
-            "annotated_text=Line 1\nLine 2<>"},
-        ExpandToEnclosingTextBoundaryTestParam{
-            ax::mojom::TextBoundary::kParagraphStartOrEnd,
-            AXRangeExpandBehavior::kLeftFirst,
             "TextPosition anchor_id=4 text_offset=0 affinity=downstream "
             "annotated_text=<L>ine 1\nLine 2",
-            "TextPosition anchor_id=4 text_offset=6 affinity=downstream "
-            "annotated_text=Line 1<\n>Line 2"},
-        ExpandToEnclosingTextBoundaryTestParam{
-            ax::mojom::TextBoundary::kParagraphStartOrEnd,
-            AXRangeExpandBehavior::kRightFirst,
-            "TextPosition anchor_id=4 text_offset=7 affinity=downstream "
-            "annotated_text=Line 1\n<L>ine 2",
-            "TextPosition anchor_id=4 text_offset=13 affinity=downstream "
-            "annotated_text=Line 1\nLine 2<>"},
-        // TODO(accessibility): Add tests for sentence boundary.
-        ExpandToEnclosingTextBoundaryTestParam{
-            ax::mojom::TextBoundary::kWebPage,
-            AXRangeExpandBehavior::kLeftFirst,
-            "TextPosition anchor_id=1 text_offset=0 affinity=downstream "
-            "annotated_text=<L>ine 1\nLine 2",
-            "TextPosition anchor_id=9 text_offset=6 affinity=downstream "
-            "annotated_text=Line 2<>"},
-        ExpandToEnclosingTextBoundaryTestParam{
-            ax::mojom::TextBoundary::kWebPage,
-            AXRangeExpandBehavior::kRightFirst,
-            "TextPosition anchor_id=1 text_offset=0 affinity=downstream "
-            "annotated_text=<L>ine 1\nLine 2",
-            "TextPosition anchor_id=9 text_offset=6 affinity=downstream "
-            "annotated_text=Line 2<>"},
-        ExpandToEnclosingTextBoundaryTestParam{
-            ax::mojom::TextBoundary::kWordEnd,
-            AXRangeExpandBehavior::kLeftFirst,
-            "TextPosition anchor_id=4 text_offset=6 affinity=downstream "
-            "annotated_text=Line 1<\n>Line 2",
-            "TextPosition anchor_id=4 text_offset=11 affinity=downstream "
-            "annotated_text=Line 1\nLine< >2"},
-        ExpandToEnclosingTextBoundaryTestParam{
-            ax::mojom::TextBoundary::kWordEnd,
-            AXRangeExpandBehavior::kRightFirst,
-            "TextPosition anchor_id=4 text_offset=6 affinity=downstream "
-            "annotated_text=Line 1<\n>Line 2",
-            "TextPosition anchor_id=4 text_offset=11 affinity=downstream "
-            "annotated_text=Line 1\nLine< >2"},
-        ExpandToEnclosingTextBoundaryTestParam{
-            ax::mojom::TextBoundary::kWordStart,
-            AXRangeExpandBehavior::kLeftFirst,
-            "TextPosition anchor_id=4 text_offset=5 affinity=downstream "
-            "annotated_text=Line <1>\nLine 2",
             "TextPosition anchor_id=4 text_offset=7 affinity=downstream "
             "annotated_text=Line 1\n<L>ine 2"},
         ExpandToEnclosingTextBoundaryTestParam{
-            ax::mojom::TextBoundary::kWordStart,
+            ax::mojom::TextBoundary::kParagraphStartOrEnd,
+            AXRangeExpandBehavior::kLeftFirst,
+            "TextPosition anchor_id=4 text_offset=7 affinity=downstream "
+            "annotated_text=Line 1\n<L>ine 2",
+            "TextPosition anchor_id=4 text_offset=13 affinity=downstream "
+            "annotated_text=Line 1\nLine 2<>"},
+        ExpandToEnclosingTextBoundaryTestParam{
+            ax::mojom::TextBoundary::kParagraphStartOrEnd,
             AXRangeExpandBehavior::kRightFirst,
             "TextPosition anchor_id=4 text_offset=7 affinity=downstream "
             "annotated_text=Line 1\n<L>ine 2",
+            "TextPosition anchor_id=4 text_offset=13 affinity=downstream "
+            "annotated_text=Line 1\nLine 2<>"},
+        ExpandToEnclosingTextBoundaryTestParam{
+            ax::mojom::TextBoundary::kSentenceEnd,
+            AXRangeExpandBehavior::kLeftFirst,
+            "TextPosition anchor_id=4 text_offset=6 affinity=downstream "
+            "annotated_text=Line 1<\n>Line 2",
+            "TextPosition anchor_id=4 text_offset=13 affinity=downstream "
+            "annotated_text=Line 1\nLine 2<>"},
+        ExpandToEnclosingTextBoundaryTestParam{
+            ax::mojom::TextBoundary::kSentenceEnd,
+            AXRangeExpandBehavior::kRightFirst,
+            "TextPosition anchor_id=4 text_offset=6 affinity=downstream "
+            "annotated_text=Line 1<\n>Line 2",
+            "TextPosition anchor_id=4 text_offset=13 affinity=downstream "
+            "annotated_text=Line 1\nLine 2<>"},
+        ExpandToEnclosingTextBoundaryTestParam{
+            ax::mojom::TextBoundary::kSentenceStart,
+            AXRangeExpandBehavior::kLeftFirst,
+            "TextPosition anchor_id=4 text_offset=7 affinity=downstream "
+            "annotated_text=Line 1\n<L>ine 2",
+            "TextPosition anchor_id=4 text_offset=13 affinity=downstream "
+            "annotated_text=Line 1\nLine 2<>"},
+        ExpandToEnclosingTextBoundaryTestParam{
+            ax::mojom::TextBoundary::kSentenceStart,
+            AXRangeExpandBehavior::kRightFirst,
+            "TextPosition anchor_id=4 text_offset=0 affinity=downstream "
+            "annotated_text=<L>ine 1\nLine 2",
+            "TextPosition anchor_id=4 text_offset=7 affinity=downstream "
+            "annotated_text=Line 1\n<L>ine 2"},
+        ExpandToEnclosingTextBoundaryTestParam{
+            ax::mojom::TextBoundary::kSentenceStartOrEnd,
+            AXRangeExpandBehavior::kLeftFirst,
+            "TextPosition anchor_id=4 text_offset=7 affinity=downstream "
+            "annotated_text=Line 1\n<L>ine 2",
+            "TextPosition anchor_id=4 text_offset=13 affinity=downstream "
+            "annotated_text=Line 1\nLine 2<>"},
+        ExpandToEnclosingTextBoundaryTestParam{
+            ax::mojom::TextBoundary::kSentenceStartOrEnd,
+            AXRangeExpandBehavior::kRightFirst,
+            "TextPosition anchor_id=4 text_offset=7 affinity=downstream "
+            "annotated_text=Line 1\n<L>ine 2",
+            "TextPosition anchor_id=4 text_offset=13 affinity=downstream "
+            "annotated_text=Line 1\nLine 2<>"},
+        ExpandToEnclosingTextBoundaryTestParam{
+            ax::mojom::TextBoundary::kWebPage,
+            AXRangeExpandBehavior::kLeftFirst,
+            "TextPosition anchor_id=1 text_offset=0 affinity=downstream "
+            "annotated_text=<L>ine 1\nLine 2",
+            "TextPosition anchor_id=9 text_offset=6 affinity=downstream "
+            "annotated_text=Line 2<>"},
+        ExpandToEnclosingTextBoundaryTestParam{
+            ax::mojom::TextBoundary::kWebPage,
+            AXRangeExpandBehavior::kRightFirst,
+            "TextPosition anchor_id=1 text_offset=0 affinity=downstream "
+            "annotated_text=<L>ine 1\nLine 2",
+            "TextPosition anchor_id=9 text_offset=6 affinity=downstream "
+            "annotated_text=Line 2<>"},
+        ExpandToEnclosingTextBoundaryTestParam{
+            ax::mojom::TextBoundary::kWordEnd,
+            AXRangeExpandBehavior::kLeftFirst,
+            "TextPosition anchor_id=4 text_offset=6 affinity=downstream "
+            "annotated_text=Line 1<\n>Line 2",
+            "TextPosition anchor_id=4 text_offset=11 affinity=downstream "
+            "annotated_text=Line 1\nLine< >2"},
+        ExpandToEnclosingTextBoundaryTestParam{
+            ax::mojom::TextBoundary::kWordEnd,
+            AXRangeExpandBehavior::kRightFirst,
+            "TextPosition anchor_id=4 text_offset=6 affinity=downstream "
+            "annotated_text=Line 1<\n>Line 2",
+            "TextPosition anchor_id=4 text_offset=11 affinity=downstream "
+            "annotated_text=Line 1\nLine< >2"},
+        ExpandToEnclosingTextBoundaryTestParam{
+            ax::mojom::TextBoundary::kWordStart,
+            AXRangeExpandBehavior::kLeftFirst,
+            "TextPosition anchor_id=4 text_offset=7 affinity=downstream "
+            "annotated_text=Line 1\n<L>ine 2",
             "TextPosition anchor_id=4 text_offset=12 affinity=downstream "
             "annotated_text=Line 1\nLine <2>"},
         ExpandToEnclosingTextBoundaryTestParam{
-            ax::mojom::TextBoundary::kWordStartOrEnd,
-            AXRangeExpandBehavior::kLeftFirst,
+            ax::mojom::TextBoundary::kWordStart,
+            AXRangeExpandBehavior::kRightFirst,
             "TextPosition anchor_id=4 text_offset=5 affinity=downstream "
             "annotated_text=Line <1>\nLine 2",
-            "TextPosition anchor_id=4 text_offset=6 affinity=downstream "
-            "annotated_text=Line 1<\n>Line 2"},
+            "TextPosition anchor_id=4 text_offset=7 affinity=downstream "
+            "annotated_text=Line 1\n<L>ine 2"},
+        ExpandToEnclosingTextBoundaryTestParam{
+            ax::mojom::TextBoundary::kWordStartOrEnd,
+            AXRangeExpandBehavior::kLeftFirst,
+            "TextPosition anchor_id=4 text_offset=7 affinity=downstream "
+            "annotated_text=Line 1\n<L>ine 2",
+            "TextPosition anchor_id=4 text_offset=11 affinity=downstream "
+            "annotated_text=Line 1\nLine< >2"},
         ExpandToEnclosingTextBoundaryTestParam{
             ax::mojom::TextBoundary::kWordStartOrEnd,
             AXRangeExpandBehavior::kRightFirst,
@@ -12288,7 +12356,7 @@
             "TextPosition anchor_id=4 text_offset=11 affinity=downstream "
             "annotated_text=Line 1\nLine< >2"}));
 
-// Only test with AXBoundaryBehavior::CrossBoundary for now.
+// Only test with AXBoundaryBehavior::kCrossBoundary for now.
 // TODO(accessibility): Add more tests for other boundary behaviors if needed.
 INSTANTIATE_TEST_SUITE_P(
     CreatePositionAtTextBoundary,
@@ -12297,165 +12365,1028 @@
         CreatePositionAtTextBoundaryTestParam{
             ax::mojom::TextBoundary::kCharacter,
             ax::mojom::MoveDirection::kBackward,
-            AXBoundaryBehavior::CrossBoundary,
+            AXBoundaryBehavior::kCrossBoundary,
             "TextPosition anchor_id=7 text_offset=0 affinity=downstream "
             "annotated_text=<\n>"},
         CreatePositionAtTextBoundaryTestParam{
             ax::mojom::TextBoundary::kCharacter,
             ax::mojom::MoveDirection::kForward,
-            AXBoundaryBehavior::CrossBoundary,
+            AXBoundaryBehavior::kCrossBoundary,
             "TextPosition anchor_id=8 text_offset=1 affinity=downstream "
             "annotated_text=L<i>ne 2"},
         CreatePositionAtTextBoundaryTestParam{
             ax::mojom::TextBoundary::kFormatStart,
             ax::mojom::MoveDirection::kBackward,
-            AXBoundaryBehavior::CrossBoundary,
+            AXBoundaryBehavior::kCrossBoundary,
             "TextPosition anchor_id=7 text_offset=0 affinity=downstream "
             "annotated_text=<\n>"},
         CreatePositionAtTextBoundaryTestParam{
             ax::mojom::TextBoundary::kFormatEnd,
             ax::mojom::MoveDirection::kForward,
-            AXBoundaryBehavior::CrossBoundary,
+            AXBoundaryBehavior::kCrossBoundary,
             "TextPosition anchor_id=8 text_offset=6 affinity=downstream "
             "annotated_text=Line 2<>"},
         CreatePositionAtTextBoundaryTestParam{
             ax::mojom::TextBoundary::kLineEnd,
             ax::mojom::MoveDirection::kBackward,
-            AXBoundaryBehavior::CrossBoundary,
+            AXBoundaryBehavior::kCrossBoundary,
             "TextPosition anchor_id=7 text_offset=0 affinity=downstream "
             "annotated_text=<\n>"},
         CreatePositionAtTextBoundaryTestParam{
             ax::mojom::TextBoundary::kLineEnd,
             ax::mojom::MoveDirection::kForward,
-            AXBoundaryBehavior::CrossBoundary,
+            AXBoundaryBehavior::kCrossBoundary,
             "TextPosition anchor_id=8 text_offset=6 affinity=downstream "
             "annotated_text=Line 2<>"},
         CreatePositionAtTextBoundaryTestParam{
             ax::mojom::TextBoundary::kLineStart,
             ax::mojom::MoveDirection::kBackward,
-            AXBoundaryBehavior::CrossBoundary,
+            AXBoundaryBehavior::kCrossBoundary,
             "TextPosition anchor_id=6 text_offset=0 affinity=downstream "
             "annotated_text=<L>ine 1"},
         CreatePositionAtTextBoundaryTestParam{
             ax::mojom::TextBoundary::kLineStart,
             ax::mojom::MoveDirection::kForward,
-            AXBoundaryBehavior::CrossBoundary, "NullPosition"},
+            AXBoundaryBehavior::kCrossBoundary, "NullPosition"},
         CreatePositionAtTextBoundaryTestParam{
             ax::mojom::TextBoundary::kLineStartOrEnd,
             ax::mojom::MoveDirection::kBackward,
-            AXBoundaryBehavior::CrossBoundary,
+            AXBoundaryBehavior::kCrossBoundary,
             "TextPosition anchor_id=6 text_offset=0 affinity=downstream "
             "annotated_text=<L>ine 1"},
         CreatePositionAtTextBoundaryTestParam{
             ax::mojom::TextBoundary::kLineStartOrEnd,
             ax::mojom::MoveDirection::kForward,
-            AXBoundaryBehavior::CrossBoundary,
+            AXBoundaryBehavior::kCrossBoundary,
             "TextPosition anchor_id=8 text_offset=6 affinity=downstream "
             "annotated_text=Line 2<>"},
         CreatePositionAtTextBoundaryTestParam{
             ax::mojom::TextBoundary::kObject,
             ax::mojom::MoveDirection::kBackward,
-            AXBoundaryBehavior::CrossBoundary,
+            AXBoundaryBehavior::kCrossBoundary,
             "TextPosition anchor_id=8 text_offset=0 affinity=downstream "
             "annotated_text=<L>ine 2"},
         CreatePositionAtTextBoundaryTestParam{
             ax::mojom::TextBoundary::kObject,
             ax::mojom::MoveDirection::kForward,
-            AXBoundaryBehavior::CrossBoundary,
+            AXBoundaryBehavior::kCrossBoundary,
             "TextPosition anchor_id=8 text_offset=6 affinity=downstream "
             "annotated_text=Line 2<>"},
         CreatePositionAtTextBoundaryTestParam{
             ax::mojom::TextBoundary::kParagraphEnd,
             ax::mojom::MoveDirection::kBackward,
-            AXBoundaryBehavior::CrossBoundary,
+            AXBoundaryBehavior::kCrossBoundary,
             "TextPosition anchor_id=6 text_offset=6 affinity=downstream "
             "annotated_text=Line 1<>"},
         CreatePositionAtTextBoundaryTestParam{
             ax::mojom::TextBoundary::kParagraphEnd,
             ax::mojom::MoveDirection::kForward,
-            AXBoundaryBehavior::CrossBoundary,
+            AXBoundaryBehavior::kCrossBoundary,
             "TextPosition anchor_id=8 text_offset=6 affinity=downstream "
             "annotated_text=Line 2<>"},
         CreatePositionAtTextBoundaryTestParam{
             ax::mojom::TextBoundary::kParagraphStart,
             ax::mojom::MoveDirection::kBackward,
-            AXBoundaryBehavior::CrossBoundary,
+            AXBoundaryBehavior::kCrossBoundary,
             "TextPosition anchor_id=6 text_offset=0 affinity=downstream "
             "annotated_text=<L>ine 1"},
         CreatePositionAtTextBoundaryTestParam{
             ax::mojom::TextBoundary::kParagraphStart,
             ax::mojom::MoveDirection::kForward,
-            AXBoundaryBehavior::CrossBoundary, "NullPosition"},
+            AXBoundaryBehavior::kCrossBoundary, "NullPosition"},
         CreatePositionAtTextBoundaryTestParam{
             ax::mojom::TextBoundary::kParagraphStartOrEnd,
             ax::mojom::MoveDirection::kBackward,
-            AXBoundaryBehavior::CrossBoundary,
+            AXBoundaryBehavior::kCrossBoundary,
             "TextPosition anchor_id=6 text_offset=0 affinity=downstream "
             "annotated_text=<L>ine 1"},
         CreatePositionAtTextBoundaryTestParam{
             ax::mojom::TextBoundary::kParagraphStartOrEnd,
             ax::mojom::MoveDirection::kForward,
-            AXBoundaryBehavior::CrossBoundary,
+            AXBoundaryBehavior::kCrossBoundary,
             "TextPosition anchor_id=8 text_offset=6 affinity=downstream "
             "annotated_text=Line 2<>"},
-        // TODO(accessibility): Add tests for sentence boundary.
+        CreatePositionAtTextBoundaryTestParam{
+            ax::mojom::TextBoundary::kSentenceEnd,
+            ax::mojom::MoveDirection::kBackward,
+            AXBoundaryBehavior::kCrossBoundary,
+            "TextPosition anchor_id=6 text_offset=6 affinity=downstream "
+            "annotated_text=Line 1<>"},
+        CreatePositionAtTextBoundaryTestParam{
+            ax::mojom::TextBoundary::kSentenceEnd,
+            ax::mojom::MoveDirection::kForward,
+            AXBoundaryBehavior::kCrossBoundary,
+            "TextPosition anchor_id=8 text_offset=6 affinity=downstream "
+            "annotated_text=Line 2<>"},
+        CreatePositionAtTextBoundaryTestParam{
+            ax::mojom::TextBoundary::kSentenceStart,
+            ax::mojom::MoveDirection::kBackward,
+            AXBoundaryBehavior::kCrossBoundary,
+            "TextPosition anchor_id=6 text_offset=0 affinity=downstream "
+            "annotated_text=<L>ine 1"},
+        CreatePositionAtTextBoundaryTestParam{
+            ax::mojom::TextBoundary::kSentenceStart,
+            ax::mojom::MoveDirection::kForward,
+            AXBoundaryBehavior::kCrossBoundary, "NullPosition"},
+        CreatePositionAtTextBoundaryTestParam{
+            ax::mojom::TextBoundary::kSentenceStartOrEnd,
+            ax::mojom::MoveDirection::kBackward,
+            AXBoundaryBehavior::kCrossBoundary,
+            "TextPosition anchor_id=6 text_offset=0 affinity=downstream "
+            "annotated_text=<L>ine 1"},
+        CreatePositionAtTextBoundaryTestParam{
+            ax::mojom::TextBoundary::kSentenceStartOrEnd,
+            ax::mojom::MoveDirection::kForward,
+            AXBoundaryBehavior::kCrossBoundary,
+            "TextPosition anchor_id=8 text_offset=6 affinity=downstream "
+            "annotated_text=Line 2<>"},
         CreatePositionAtTextBoundaryTestParam{
             ax::mojom::TextBoundary::kWebPage,
             ax::mojom::MoveDirection::kBackward,
-            AXBoundaryBehavior::CrossBoundary,
+            AXBoundaryBehavior::kCrossBoundary,
             "TextPosition anchor_id=1 text_offset=0 affinity=downstream "
             "annotated_text=<L>ine 1\nLine 2"},
         CreatePositionAtTextBoundaryTestParam{
             ax::mojom::TextBoundary::kWebPage,
             ax::mojom::MoveDirection::kForward,
-            AXBoundaryBehavior::CrossBoundary,
+            AXBoundaryBehavior::kCrossBoundary,
             "TextPosition anchor_id=9 text_offset=6 affinity=downstream "
             "annotated_text=Line 2<>"},
         CreatePositionAtTextBoundaryTestParam{
             ax::mojom::TextBoundary::kWordEnd,
             ax::mojom::MoveDirection::kBackward,
-            AXBoundaryBehavior::CrossBoundary,
+            AXBoundaryBehavior::kCrossBoundary,
             "TextPosition anchor_id=6 text_offset=6 affinity=downstream "
             "annotated_text=Line 1<>"},
         CreatePositionAtTextBoundaryTestParam{
             ax::mojom::TextBoundary::kWordEnd,
             ax::mojom::MoveDirection::kForward,
-            AXBoundaryBehavior::CrossBoundary,
+            AXBoundaryBehavior::kCrossBoundary,
             "TextPosition anchor_id=8 text_offset=4 affinity=downstream "
             "annotated_text=Line< >2"},
         CreatePositionAtTextBoundaryTestParam{
             ax::mojom::TextBoundary::kWordStart,
             ax::mojom::MoveDirection::kBackward,
-            AXBoundaryBehavior::CrossBoundary,
+            AXBoundaryBehavior::kCrossBoundary,
             "TextPosition anchor_id=6 text_offset=5 affinity=downstream "
             "annotated_text=Line <1>"},
         CreatePositionAtTextBoundaryTestParam{
             ax::mojom::TextBoundary::kWordStart,
             ax::mojom::MoveDirection::kForward,
-            AXBoundaryBehavior::CrossBoundary,
+            AXBoundaryBehavior::kCrossBoundary,
             "TextPosition anchor_id=8 text_offset=5 affinity=downstream "
             "annotated_text=Line <2>"},
         CreatePositionAtTextBoundaryTestParam{
             ax::mojom::TextBoundary::kWordStartOrEnd,
             ax::mojom::MoveDirection::kBackward,
-            AXBoundaryBehavior::CrossBoundary,
+            AXBoundaryBehavior::kCrossBoundary,
             "TextPosition anchor_id=6 text_offset=5 affinity=downstream "
             "annotated_text=Line <1>"},
         CreatePositionAtTextBoundaryTestParam{
             ax::mojom::TextBoundary::kWordStartOrEnd,
             ax::mojom::MoveDirection::kForward,
-            AXBoundaryBehavior::CrossBoundary,
+            AXBoundaryBehavior::kCrossBoundary,
             "TextPosition anchor_id=8 text_offset=4 affinity=downstream "
             "annotated_text=Line< >2"}));
 
 INSTANTIATE_TEST_SUITE_P(
+    CreateNextSentenceStartPositionWithBoundaryBehaviorCrossBoundary,
+    AXPositionTextNavigationTestWithParam,
+    ::testing::Values(
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceStartPosition(
+                  AXBoundaryBehavior::kCrossBoundary);
+            }),
+            ROOT_ID,
+            0 /* text_offset */,
+            {"TextPosition anchor_id=1 text_offset=7 "
+             "affinity=downstream annotated_text=Line 1\n<L>ine 2",
+             "NullPosition"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceStartPosition(
+                  AXBoundaryBehavior::kCrossBoundary);
+            }),
+            TEXT_FIELD_ID,
+            0 /* text_offset */,
+            {"TextPosition anchor_id=4 text_offset=7 "
+             "affinity=downstream annotated_text=Line 1\n<L>ine 2",
+             "NullPosition"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceStartPosition(
+                  AXBoundaryBehavior::kCrossBoundary);
+            }),
+            STATIC_TEXT1_ID,
+            1 /* text_offset */,
+            {"TextPosition anchor_id=9 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 2",
+             "NullPosition"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceStartPosition(
+                  AXBoundaryBehavior::kCrossBoundary);
+            }),
+            INLINE_BOX2_ID,
+            4 /* text_offset */,
+            {"NullPosition"}}));
+
+INSTANTIATE_TEST_SUITE_P(
+    CreateNextSentenceStartPositionWithBoundaryBehaviorStopAtAnchorBoundary,
+    AXPositionTextNavigationTestWithParam,
+    ::testing::Values(
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceStartPosition(
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
+            }),
+            ROOT_ID,
+            0 /* text_offset */,
+            {"TextPosition anchor_id=1 text_offset=7 "
+             "affinity=downstream annotated_text=Line 1\n<L>ine 2",
+             "TextPosition anchor_id=1 text_offset=13 "
+             "affinity=downstream annotated_text=Line 1\nLine 2<>",
+             "TextPosition anchor_id=1 text_offset=13 "
+             "affinity=downstream annotated_text=Line 1\nLine 2<>"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceStartPosition(
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
+            }),
+            TEXT_FIELD_ID,
+            0 /* text_offset */,
+            {"TextPosition anchor_id=4 text_offset=7 "
+             "affinity=downstream annotated_text=Line 1\n<L>ine 2",
+             "TextPosition anchor_id=4 text_offset=13 "
+             "affinity=downstream annotated_text=Line 1\nLine 2<>",
+             "TextPosition anchor_id=4 text_offset=13 "
+             "affinity=downstream annotated_text=Line 1\nLine 2<>"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceStartPosition(
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
+            }),
+            STATIC_TEXT1_ID,
+            1 /* text_offset */,
+            {"TextPosition anchor_id=5 text_offset=6 "
+             "affinity=downstream annotated_text=Line 1<>",
+             "TextPosition anchor_id=5 text_offset=6 "
+             "affinity=downstream annotated_text=Line 1<>"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceStartPosition(
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
+            }),
+            INLINE_BOX2_ID,
+            4 /* text_offset */,
+            {"TextPosition anchor_id=9 text_offset=6 "
+             "affinity=downstream annotated_text=Line 2<>",
+             "TextPosition anchor_id=9 text_offset=6 "
+             "affinity=downstream annotated_text=Line 2<>"}}));
+
+INSTANTIATE_TEST_SUITE_P(
+    CreateNextSentenceStartPositionWithBoundaryBehaviorStopAtAnchorBoundaryOrIfAlreadyAtBoundary,
+    AXPositionTextNavigationTestWithParam,
+    ::testing::Values(
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceStartPosition(
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
+            }),
+            ROOT_ID,
+            0 /* text_offset */,
+            {"TextPosition anchor_id=1 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1\nLine 2",
+             "TextPosition anchor_id=1 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1\nLine 2"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceStartPosition(
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
+            }),
+            TEXT_FIELD_ID,
+            0 /* text_offset */,
+            {"TextPosition anchor_id=4 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1\nLine 2",
+             "TextPosition anchor_id=4 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1\nLine 2"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceStartPosition(
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
+            }),
+            STATIC_TEXT1_ID,
+            1 /* text_offset */,
+            {"TextPosition anchor_id=5 text_offset=6 affinity=downstream "
+             "annotated_text=Line 1<>",
+             "TextPosition anchor_id=5 text_offset=6 affinity=downstream "
+             "annotated_text=Line 1<>"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceStartPosition(
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
+            }),
+            INLINE_BOX2_ID,
+            4 /* text_offset */,
+            {"TextPosition anchor_id=9 text_offset=6 "
+             "affinity=downstream annotated_text=Line 2<>",
+             "TextPosition anchor_id=9 text_offset=6 "
+             "affinity=downstream annotated_text=Line 2<>"}}));
+
+INSTANTIATE_TEST_SUITE_P(
+    CreateNextSentenceStartPositionWithBoundaryBehaviorStopAtLastAnchorBoundary,
+    AXPositionTextNavigationTestWithParam,
+    ::testing::Values(
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceStartPosition(
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
+            }),
+            ROOT_ID,
+            0 /* text_offset */,
+            {"TextPosition anchor_id=1 text_offset=7 "
+             "affinity=downstream annotated_text=Line 1\n<L>ine 2",
+             "TextPosition anchor_id=1 text_offset=13 "
+             "affinity=downstream annotated_text=Line 1\nLine 2<>",
+             "TextPosition anchor_id=1 text_offset=13 "
+             "affinity=downstream annotated_text=Line 1\nLine 2<>"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceStartPosition(
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
+            }),
+            TEXT_FIELD_ID,
+            0 /* text_offset */,
+            {"TextPosition anchor_id=4 text_offset=7 "
+             "affinity=downstream annotated_text=Line 1\n<L>ine 2",
+             "TextPosition anchor_id=4 text_offset=13 "
+             "affinity=downstream annotated_text=Line 1\nLine 2<>",
+             "TextPosition anchor_id=4 text_offset=13 "
+             "affinity=downstream annotated_text=Line 1\nLine 2<>"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceStartPosition(
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
+            }),
+            STATIC_TEXT1_ID,
+            1 /* text_offset */,
+            {"TextPosition anchor_id=9 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 2",
+             "TextPosition anchor_id=9 text_offset=6 "
+             "affinity=downstream annotated_text=Line 2<>",
+             "TextPosition anchor_id=9 text_offset=6 "
+             "affinity=downstream annotated_text=Line 2<>"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceStartPosition(
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
+            }),
+            INLINE_BOX2_ID,
+            4 /* text_offset */,
+            {"TextPosition anchor_id=9 text_offset=6 "
+             "affinity=downstream annotated_text=Line 2<>",
+             "TextPosition anchor_id=9 text_offset=6 "
+             "affinity=downstream annotated_text=Line 2<>"}}));
+
+INSTANTIATE_TEST_SUITE_P(
+    CreatePreviousSentenceStartPositionWithBoundaryBehaviorCrossBoundary,
+    AXPositionTextNavigationTestWithParam,
+    ::testing::Values(
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceStartPosition(
+                  AXBoundaryBehavior::kCrossBoundary);
+            }),
+            ROOT_ID,
+            13 /* text_offset at end of root. */,
+            {"TextPosition anchor_id=1 text_offset=7 "
+             "affinity=downstream annotated_text=Line 1\n<L>ine 2",
+             "TextPosition anchor_id=1 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1\nLine 2",
+             "NullPosition"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceStartPosition(
+                  AXBoundaryBehavior::kCrossBoundary);
+            }),
+            TEXT_FIELD_ID,
+            13 /* text_offset at end of text field */,
+            {"TextPosition anchor_id=4 text_offset=7 "
+             "affinity=downstream annotated_text=Line 1\n<L>ine 2",
+             "TextPosition anchor_id=4 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1\nLine 2",
+             "NullPosition"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceStartPosition(
+                  AXBoundaryBehavior::kCrossBoundary);
+            }),
+            STATIC_TEXT1_ID,
+            5 /* text_offset */,
+            {"TextPosition anchor_id=5 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1",
+             "NullPosition"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceStartPosition(
+                  AXBoundaryBehavior::kCrossBoundary);
+            }),
+            INLINE_BOX2_ID,
+            4 /* text_offset */,
+            {"TextPosition anchor_id=9 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 2",
+             "TextPosition anchor_id=6 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1",
+             "NullPosition"}}));
+
+INSTANTIATE_TEST_SUITE_P(
+    CreatePreviousSentenceStartPositionWithBoundaryBehaviorStopAtAnchorBoundary,
+    AXPositionTextNavigationTestWithParam,
+    ::testing::Values(
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceStartPosition(
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
+            }),
+            ROOT_ID,
+            13 /* text_offset at end of root. */,
+            {"TextPosition anchor_id=1 text_offset=7 "
+             "affinity=downstream annotated_text=Line 1\n<L>ine 2",
+             "TextPosition anchor_id=1 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1\nLine 2",
+             "TextPosition anchor_id=1 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1\nLine 2"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceStartPosition(
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
+            }),
+            TEXT_FIELD_ID,
+            13 /* text_offset at end of text field */,
+            {"TextPosition anchor_id=4 text_offset=7 "
+             "affinity=downstream annotated_text=Line 1\n<L>ine 2",
+             "TextPosition anchor_id=4 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1\nLine 2",
+             "TextPosition anchor_id=4 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1\nLine 2"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceStartPosition(
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
+            }),
+            STATIC_TEXT1_ID,
+            5 /* text_offset */,
+            {"TextPosition anchor_id=5 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1",
+             "TextPosition anchor_id=5 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceStartPosition(
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
+            }),
+            INLINE_BOX2_ID,
+            4 /* text_offset */,
+            {"TextPosition anchor_id=9 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 2",
+             "TextPosition anchor_id=9 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 2"}}));
+
+INSTANTIATE_TEST_SUITE_P(
+    CreatePreviousSentenceStartPositionWithBoundaryBehaviorStopAtAnchorBoundaryOrIfAlreadyAtBoundary,
+    AXPositionTextNavigationTestWithParam,
+    ::testing::Values(
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceStartPosition(
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
+            }),
+            ROOT_ID,
+            13 /* text_offset at end of root. */,
+            {"TextPosition anchor_id=1 text_offset=7 "
+             "affinity=downstream annotated_text=Line 1\n<L>ine 2",
+             "TextPosition anchor_id=1 text_offset=7 "
+             "affinity=downstream annotated_text=Line 1\n<L>ine 2"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceStartPosition(
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
+            }),
+            TEXT_FIELD_ID,
+            13 /* text_offset at end of text field */,
+            {"TextPosition anchor_id=4 text_offset=7 "
+             "affinity=downstream annotated_text=Line 1\n<L>ine 2",
+             "TextPosition anchor_id=4 text_offset=7 "
+             "affinity=downstream annotated_text=Line 1\n<L>ine 2"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceStartPosition(
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
+            }),
+            STATIC_TEXT1_ID,
+            5 /* text_offset */,
+            {"TextPosition anchor_id=5 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1",
+             "TextPosition anchor_id=5 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceStartPosition(
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
+            }),
+            INLINE_BOX2_ID,
+            4 /* text_offset */,
+            {"TextPosition anchor_id=9 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 2",
+             "TextPosition anchor_id=9 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 2"}}));
+
+INSTANTIATE_TEST_SUITE_P(
+    CreatePreviousSentenceStartPositionWithBoundaryBehaviorStopAtLastAnchorBoundary,
+    AXPositionTextNavigationTestWithParam,
+    ::testing::Values(
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceStartPosition(
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
+            }),
+            ROOT_ID,
+            13 /* text_offset */,
+            {"TextPosition anchor_id=1 text_offset=7 "
+             "affinity=downstream annotated_text=Line 1\n<L>ine 2",
+             "TextPosition anchor_id=1 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1\nLine 2",
+             "TextPosition anchor_id=1 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1\nLine 2"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceStartPosition(
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
+            }),
+            TEXT_FIELD_ID,
+            13 /* text_offset */,
+            {"TextPosition anchor_id=4 text_offset=7 "
+             "affinity=downstream annotated_text=Line 1\n<L>ine 2",
+             "TextPosition anchor_id=4 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1\nLine 2",
+             "TextPosition anchor_id=4 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1\nLine 2"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceStartPosition(
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
+            }),
+            STATIC_TEXT1_ID,
+            5 /* text_offset */,
+            {"TextPosition anchor_id=5 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1",
+             "TextPosition anchor_id=5 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceStartPosition(
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
+            }),
+            INLINE_BOX2_ID,
+            4 /* text_offset */,
+            {"TextPosition anchor_id=9 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 2",
+             "TextPosition anchor_id=6 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1",
+             "TextPosition anchor_id=6 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1"}}));
+
+INSTANTIATE_TEST_SUITE_P(
+    CreateNextSentenceEndPositionWithBoundaryBehaviorCrossBoundary,
+    AXPositionTextNavigationTestWithParam,
+    ::testing::Values(
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceEndPosition(
+                  AXBoundaryBehavior::kCrossBoundary);
+            }),
+            ROOT_ID,
+            0 /* text_offset */,
+            {"TextPosition anchor_id=1 text_offset=6 "
+             "affinity=downstream annotated_text=Line 1<\n>Line 2",
+             "TextPosition anchor_id=1 text_offset=13 "
+             "affinity=downstream annotated_text=Line 1\nLine 2<>",
+             "NullPosition"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceEndPosition(
+                  AXBoundaryBehavior::kCrossBoundary);
+            }),
+            TEXT_FIELD_ID,
+            0 /* text_offset */,
+            {"TextPosition anchor_id=4 text_offset=6 "
+             "affinity=downstream annotated_text=Line 1<\n>Line 2",
+             "TextPosition anchor_id=4 text_offset=13 "
+             "affinity=downstream annotated_text=Line 1\nLine 2<>",
+             "NullPosition"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceEndPosition(
+                  AXBoundaryBehavior::kCrossBoundary);
+            }),
+            STATIC_TEXT1_ID,
+            1 /* text_offset */,
+            {"TextPosition anchor_id=5 text_offset=6 "
+             "affinity=downstream annotated_text=Line 1<>",
+             "TextPosition anchor_id=9 text_offset=6 "
+             "affinity=downstream annotated_text=Line 2<>",
+             "NullPosition"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceEndPosition(
+                  AXBoundaryBehavior::kCrossBoundary);
+            }),
+            INLINE_BOX2_ID,
+            4 /* text_offset */,
+            {"TextPosition anchor_id=9 text_offset=6 "
+             "affinity=downstream annotated_text=Line 2<>",
+             "NullPosition"}}));
+
+INSTANTIATE_TEST_SUITE_P(
+    CreateNextSentenceEndPositionWithBoundaryBehaviorStopAtAnchorBoundary,
+    AXPositionTextNavigationTestWithParam,
+    ::testing::Values(
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceEndPosition(
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
+            }),
+            ROOT_ID,
+            0 /* text_offset */,
+            {"TextPosition anchor_id=1 text_offset=6 "
+             "affinity=downstream annotated_text=Line 1<\n>Line 2",
+             "TextPosition anchor_id=1 text_offset=13 "
+             "affinity=downstream annotated_text=Line 1\nLine 2<>",
+             "TextPosition anchor_id=1 text_offset=13 "
+             "affinity=downstream annotated_text=Line 1\nLine 2<>"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceEndPosition(
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
+            }),
+            TEXT_FIELD_ID,
+            0 /* text_offset */,
+            {"TextPosition anchor_id=4 text_offset=6 "
+             "affinity=downstream annotated_text=Line 1<\n>Line 2",
+             "TextPosition anchor_id=4 text_offset=13 "
+             "affinity=downstream annotated_text=Line 1\nLine 2<>",
+             "TextPosition anchor_id=4 text_offset=13 "
+             "affinity=downstream annotated_text=Line 1\nLine 2<>"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceEndPosition(
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
+            }),
+            STATIC_TEXT1_ID,
+            1 /* text_offset */,
+            {"TextPosition anchor_id=5 text_offset=6 "
+             "affinity=downstream annotated_text=Line 1<>",
+             "TextPosition anchor_id=5 text_offset=6 "
+             "affinity=downstream annotated_text=Line 1<>"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceEndPosition(
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
+            }),
+            INLINE_BOX2_ID,
+            4 /* text_offset */,
+            {"TextPosition anchor_id=9 text_offset=6 "
+             "affinity=downstream annotated_text=Line 2<>",
+             "TextPosition anchor_id=9 text_offset=6 "
+             "affinity=downstream annotated_text=Line 2<>"}}));
+
+INSTANTIATE_TEST_SUITE_P(
+    CreateNextSentenceEndPositionWithBoundaryBehaviorStopAtAnchorBoundaryOrIfAlreadyAtBoundary,
+    AXPositionTextNavigationTestWithParam,
+    ::testing::Values(
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceEndPosition(
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
+            }),
+            ROOT_ID,
+            0 /* text_offset */,
+            {"TextPosition anchor_id=1 text_offset=6 "
+             "affinity=downstream annotated_text=Line 1<\n>Line 2",
+             "TextPosition anchor_id=1 text_offset=6 "
+             "affinity=downstream annotated_text=Line 1<\n>Line 2"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceEndPosition(
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
+            }),
+            TEXT_FIELD_ID,
+            0 /* text_offset */,
+            {"TextPosition anchor_id=4 text_offset=6 "
+             "affinity=downstream annotated_text=Line 1<\n>Line 2",
+             "TextPosition anchor_id=4 text_offset=6 "
+             "affinity=downstream annotated_text=Line 1<\n>Line 2"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceEndPosition(
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
+            }),
+            STATIC_TEXT1_ID,
+            1 /* text_offset */,
+            {"TextPosition anchor_id=5 text_offset=6 "
+             "affinity=downstream annotated_text=Line 1<>",
+             "TextPosition anchor_id=5 text_offset=6 "
+             "affinity=downstream annotated_text=Line 1<>"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceEndPosition(
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
+            }),
+            INLINE_BOX2_ID,
+            4 /* text_offset */,
+            {"TextPosition anchor_id=9 text_offset=6 "
+             "affinity=downstream annotated_text=Line 2<>",
+             "TextPosition anchor_id=9 text_offset=6 "
+             "affinity=downstream annotated_text=Line 2<>"}}));
+
+INSTANTIATE_TEST_SUITE_P(
+    CreateNextSentenceEndPositionWithBoundaryBehaviorStopAtLastAnchorBoundary,
+    AXPositionTextNavigationTestWithParam,
+    ::testing::Values(
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceEndPosition(
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
+            }),
+            ROOT_ID,
+            0 /* text_offset */,
+            {"TextPosition anchor_id=1 text_offset=6 "
+             "affinity=downstream annotated_text=Line 1<\n>Line 2",
+             "TextPosition anchor_id=1 text_offset=13 "
+             "affinity=downstream annotated_text=Line 1\nLine 2<>",
+             "TextPosition anchor_id=1 text_offset=13 "
+             "affinity=downstream annotated_text=Line 1\nLine 2<>"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceEndPosition(
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
+            }),
+            TEXT_FIELD_ID,
+            0 /* text_offset */,
+            {"TextPosition anchor_id=4 text_offset=6 "
+             "affinity=downstream annotated_text=Line 1<\n>Line 2",
+             "TextPosition anchor_id=4 text_offset=13 "
+             "affinity=downstream annotated_text=Line 1\nLine 2<>",
+             "TextPosition anchor_id=4 text_offset=13 "
+             "affinity=downstream annotated_text=Line 1\nLine 2<>"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceEndPosition(
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
+            }),
+            STATIC_TEXT1_ID,
+            1 /* text_offset */,
+            {"TextPosition anchor_id=5 text_offset=6 "
+             "affinity=downstream annotated_text=Line 1<>",
+             "TextPosition anchor_id=9 text_offset=6 "
+             "affinity=downstream annotated_text=Line 2<>",
+             "TextPosition anchor_id=9 text_offset=6 "
+             "affinity=downstream annotated_text=Line 2<>"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreateNextSentenceEndPosition(
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
+            }),
+            INLINE_BOX2_ID,
+            4 /* text_offset */,
+            {"TextPosition anchor_id=9 text_offset=6 "
+             "affinity=downstream annotated_text=Line 2<>",
+             "TextPosition anchor_id=9 text_offset=6 "
+             "affinity=downstream annotated_text=Line 2<>"}}));
+
+INSTANTIATE_TEST_SUITE_P(
+    CreatePreviousSentenceEndPositionWithBoundaryBehaviorCrossBoundary,
+    AXPositionTextNavigationTestWithParam,
+    ::testing::Values(
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceEndPosition(
+                  AXBoundaryBehavior::kCrossBoundary);
+            }),
+            ROOT_ID,
+            13 /* text_offset at end of root. */,
+            {"TextPosition anchor_id=1 text_offset=6 "
+             "affinity=downstream annotated_text=Line 1<\n>Line 2",
+             "NullPosition"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceEndPosition(
+                  AXBoundaryBehavior::kCrossBoundary);
+            }),
+            TEXT_FIELD_ID,
+            13 /* text_offset at end of text field */,
+            {"TextPosition anchor_id=4 text_offset=6 "
+             "affinity=downstream annotated_text=Line 1<\n>Line 2",
+             "NullPosition"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceEndPosition(
+                  AXBoundaryBehavior::kCrossBoundary);
+            }),
+            STATIC_TEXT1_ID,
+            5 /* text_offset */,
+            {"NullPosition"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceEndPosition(
+                  AXBoundaryBehavior::kCrossBoundary);
+            }),
+            INLINE_BOX2_ID,
+            4 /* text_offset */,
+            {"TextPosition anchor_id=6 text_offset=6 affinity=downstream "
+             "annotated_text=Line 1<>",
+             "NullPosition"}}));
+
+INSTANTIATE_TEST_SUITE_P(
+    CreatePreviousSentenceEndPositionWithBoundaryBehaviorStopAtAnchorBoundary,
+    AXPositionTextNavigationTestWithParam,
+    ::testing::Values(
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceEndPosition(
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
+            }),
+            ROOT_ID,
+            13 /* text_offset at end of root. */,
+            {"TextPosition anchor_id=1 text_offset=6 "
+             "affinity=downstream annotated_text=Line 1<\n>Line 2",
+             "TextPosition anchor_id=1 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1\nLine 2",
+             "TextPosition anchor_id=1 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1\nLine 2"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceEndPosition(
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
+            }),
+            TEXT_FIELD_ID,
+            13 /* text_offset at end of text field */,
+            {"TextPosition anchor_id=4 text_offset=6 "
+             "affinity=downstream annotated_text=Line 1<\n>Line 2",
+             "TextPosition anchor_id=4 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1\nLine 2",
+             "TextPosition anchor_id=4 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1\nLine 2"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceEndPosition(
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
+            }),
+            STATIC_TEXT1_ID,
+            5 /* text_offset */,
+            {"TextPosition anchor_id=5 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1",
+             "TextPosition anchor_id=5 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceEndPosition(
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
+            }),
+            INLINE_BOX2_ID,
+            4 /* text_offset */,
+            {"TextPosition anchor_id=9 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 2",
+             "TextPosition anchor_id=9 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 2"}}));
+
+INSTANTIATE_TEST_SUITE_P(
+    CreatePreviousSentenceEndPositionWithBoundaryBehaviorStopAtAnchorBoundaryOrIfAlreadyAtBoundary,
+    AXPositionTextNavigationTestWithParam,
+    ::testing::Values(
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceEndPosition(
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
+            }),
+            ROOT_ID,
+            13 /* text_offset at end of root. */,
+            {"TextPosition anchor_id=1 text_offset=13 "
+             "affinity=downstream annotated_text=Line 1\nLine 2<>",
+             "TextPosition anchor_id=1 text_offset=13 "
+             "affinity=downstream annotated_text=Line 1\nLine 2<>"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceEndPosition(
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
+            }),
+            TEXT_FIELD_ID,
+            13 /* text_offset at end of text field */,
+            {"TextPosition anchor_id=4 text_offset=13 "
+             "affinity=downstream annotated_text=Line 1\nLine 2<>",
+             "TextPosition anchor_id=4 text_offset=13 "
+             "affinity=downstream annotated_text=Line 1\nLine 2<>"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceEndPosition(
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
+            }),
+            STATIC_TEXT1_ID,
+            5 /* text_offset */,
+            {"TextPosition anchor_id=5 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1",
+             "TextPosition anchor_id=5 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceEndPosition(
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
+            }),
+            INLINE_BOX2_ID,
+            4 /* text_offset */,
+            {"TextPosition anchor_id=9 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 2",
+             "TextPosition anchor_id=9 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 2"}}));
+
+INSTANTIATE_TEST_SUITE_P(
+    CreatePreviousSentenceEndPositionWithBoundaryBehaviorStopAtLastAnchorBoundary,
+    AXPositionTextNavigationTestWithParam,
+    ::testing::Values(
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceEndPosition(
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
+            }),
+            ROOT_ID,
+            13 /* text_offset at end of root. */,
+            {"TextPosition anchor_id=1 text_offset=6 "
+             "affinity=downstream annotated_text=Line 1<\n>Line 2",
+             "TextPosition anchor_id=1 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1\nLine 2",
+             "TextPosition anchor_id=1 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1\nLine 2"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceEndPosition(
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
+            }),
+            TEXT_FIELD_ID,
+            13 /* text_offset at end of text field */,
+            {"TextPosition anchor_id=4 text_offset=6 "
+             "affinity=downstream annotated_text=Line 1<\n>Line 2",
+             "TextPosition anchor_id=2 text_offset=0 "
+             "affinity=downstream annotated_text=<>",
+             "TextPosition anchor_id=2 text_offset=0 "
+             "affinity=downstream annotated_text=<>"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceEndPosition(
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
+            }),
+            STATIC_TEXT1_ID,
+            5 /* text_offset */,
+            {"TextPosition anchor_id=2 text_offset=0 "
+             "affinity=downstream annotated_text=<>",
+             "TextPosition anchor_id=2 text_offset=0 "
+             "affinity=downstream annotated_text=<>"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousSentenceEndPosition(
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
+            }),
+            INLINE_BOX2_ID,
+            4 /* text_offset */,
+            {"TextPosition anchor_id=6 text_offset=6 affinity=downstream "
+             "annotated_text=Line 1<>",
+             "TextPosition anchor_id=2 text_offset=0 "
+             "affinity=downstream annotated_text=<>"}}));
+
+INSTANTIATE_TEST_SUITE_P(
     CreateNextWordStartPositionWithBoundaryBehaviorCrossBoundary,
     AXPositionTextNavigationTestWithParam,
     ::testing::Values(
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordStartPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             ROOT_ID,
             0 /* text_offset */,
@@ -12469,7 +13400,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordStartPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             TEXT_FIELD_ID,
             0 /* text_offset */,
@@ -12483,7 +13414,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordStartPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             STATIC_TEXT1_ID,
             1 /* text_offset */,
@@ -12497,7 +13428,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordStartPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -12512,7 +13443,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordStartPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             ROOT_ID,
             0 /* text_offset */,
@@ -12527,7 +13458,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordStartPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             TEXT_FIELD_ID,
             0 /* text_offset */,
@@ -12542,7 +13473,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordStartPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             STATIC_TEXT1_ID,
             1 /* text_offset */,
@@ -12553,7 +13484,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordStartPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -12563,13 +13494,14 @@
              "affinity=downstream annotated_text=Line 2<>"}}));
 
 INSTANTIATE_TEST_SUITE_P(
-    CreateNextWordStartPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary,
+    CreateNextWordStartPositionWithBoundaryBehaviorStopAtAnchorBoundaryOrIfAlreadyAtBoundary,
     AXPositionTextNavigationTestWithParam,
     ::testing::Values(
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordStartPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             ROOT_ID,
             0 /* text_offset */,
@@ -12580,7 +13512,8 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordStartPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             TEXT_FIELD_ID,
             0 /* text_offset */,
@@ -12591,7 +13524,8 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordStartPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             STATIC_TEXT1_ID,
             1 /* text_offset */,
@@ -12602,7 +13536,8 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordStartPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -12618,7 +13553,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordStartPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             ROOT_ID,
             0 /* text_offset */,
@@ -12635,7 +13570,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordStartPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             TEXT_FIELD_ID,
             0 /* text_offset */,
@@ -12652,7 +13587,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordStartPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             STATIC_TEXT1_ID,
             1 /* text_offset */,
@@ -12669,7 +13604,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordStartPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -12687,7 +13622,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousWordStartPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             ROOT_ID,
             13 /* text_offset at end of root. */,
@@ -12703,7 +13638,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousWordStartPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             TEXT_FIELD_ID,
             13 /* text_offset at end of text field */,
@@ -12719,7 +13654,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousWordStartPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             STATIC_TEXT1_ID,
             5 /* text_offset */,
@@ -12729,7 +13664,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousWordStartPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -12748,7 +13683,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousWordStartPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             ROOT_ID,
             13 /* text_offset at end of root. */,
@@ -12765,7 +13700,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousWordStartPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             TEXT_FIELD_ID,
             13 /* text_offset at end of text field */,
@@ -12782,7 +13717,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousWordStartPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             STATIC_TEXT1_ID,
             5 /* text_offset */,
@@ -12793,7 +13728,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousWordStartPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -12803,13 +13738,14 @@
              "affinity=downstream annotated_text=<L>ine 2"}}));
 
 INSTANTIATE_TEST_SUITE_P(
-    CreatePreviousWordStartPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary,
+    CreatePreviousWordStartPositionWithBoundaryBehaviorStopAtAnchorBoundaryOrIfAlreadyAtBoundary,
     AXPositionTextNavigationTestWithParam,
     ::testing::Values(
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousWordStartPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             ROOT_ID,
             13 /* text_offset at end of root. */,
@@ -12820,7 +13756,8 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousWordStartPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             TEXT_FIELD_ID,
             13 /* text_offset at end of text field */,
@@ -12831,7 +13768,8 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousWordStartPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             STATIC_TEXT1_ID,
             5 /* text_offset */,
@@ -12840,7 +13778,8 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousWordStartPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -12856,7 +13795,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousWordStartPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             ROOT_ID,
             13 /* text_offset */,
@@ -12873,7 +13812,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousWordStartPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             TEXT_FIELD_ID,
             13 /* text_offset */,
@@ -12890,7 +13829,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousWordStartPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             STATIC_TEXT1_ID,
             5 /* text_offset */,
@@ -12901,7 +13840,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousWordStartPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -12921,7 +13860,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordEndPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             ROOT_ID,
             0 /* text_offset */,
@@ -12937,7 +13876,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordEndPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             TEXT_FIELD_ID,
             0 /* text_offset */,
@@ -12953,7 +13892,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordEndPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             STATIC_TEXT1_ID,
             1 /* text_offset */,
@@ -12969,7 +13908,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordEndPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -12984,7 +13923,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordEndPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             ROOT_ID,
             0 /* text_offset */,
@@ -13001,7 +13940,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordEndPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             TEXT_FIELD_ID,
             0 /* text_offset */,
@@ -13018,7 +13957,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordEndPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             STATIC_TEXT1_ID,
             1 /* text_offset */,
@@ -13031,7 +13970,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordEndPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -13041,13 +13980,14 @@
              "affinity=downstream annotated_text=Line 2<>"}}));
 
 INSTANTIATE_TEST_SUITE_P(
-    CreateNextWordEndPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary,
+    CreateNextWordEndPositionWithBoundaryBehaviorStopAtAnchorBoundaryOrIfAlreadyAtBoundary,
     AXPositionTextNavigationTestWithParam,
     ::testing::Values(
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             ROOT_ID,
             0 /* text_offset */,
@@ -13058,7 +13998,8 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             TEXT_FIELD_ID,
             0 /* text_offset */,
@@ -13069,7 +14010,8 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             STATIC_TEXT1_ID,
             1 /* text_offset */,
@@ -13080,7 +14022,8 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -13094,7 +14037,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordEndPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             ROOT_ID,
             0 /* text_offset */,
@@ -13111,7 +14054,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordEndPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             TEXT_FIELD_ID,
             0 /* text_offset */,
@@ -13128,7 +14071,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordEndPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             STATIC_TEXT1_ID,
             1 /* text_offset */,
@@ -13145,7 +14088,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextWordEndPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -13161,7 +14104,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousWordEndPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             ROOT_ID,
             13 /* text_offset at end of root. */,
@@ -13175,7 +14118,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousWordEndPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             TEXT_FIELD_ID,
             13 /* text_offset at end of text field */,
@@ -13189,7 +14132,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousWordEndPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             STATIC_TEXT1_ID,
             5 /* text_offset */,
@@ -13199,12 +14142,12 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousWordEndPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
-            {"TextPosition anchor_id=6 text_offset=6 "
-             "affinity=downstream annotated_text=Line 1<>",
+            {"TextPosition anchor_id=6 text_offset=6 affinity=downstream "
+             "annotated_text=Line 1<>",
              "TextPosition anchor_id=6 text_offset=4 "
              "affinity=downstream annotated_text=Line< >1",
              "NullPosition"}}));
@@ -13216,107 +14159,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousWordEndPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
-            }),
-            ROOT_ID,
-            13 /* text_offset at end of root. */,
-            {
-                "TextPosition anchor_id=1 text_offset=11 "
-                "affinity=downstream annotated_text=Line 1\nLine< >2",
-                "TextPosition anchor_id=1 text_offset=6 "
-                "affinity=downstream annotated_text=Line 1<\n>Line 2",
-                "TextPosition anchor_id=1 text_offset=4 "
-                "affinity=downstream annotated_text=Line< >1\nLine 2",
-                "TextPosition anchor_id=1 text_offset=0 "
-                "affinity=downstream annotated_text=<L>ine 1\nLine 2",
-            }},
-        TextNavigationTestParam{
-            base::BindRepeating([](const TestPositionType& position) {
-              return position->CreatePreviousWordEndPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
-            }),
-            TEXT_FIELD_ID,
-            13 /* text_offset at end of text field */,
-            {"TextPosition anchor_id=4 text_offset=11 "
-             "affinity=downstream annotated_text=Line 1\nLine< >2",
-             "TextPosition anchor_id=4 text_offset=6 "
-             "affinity=downstream annotated_text=Line 1<\n>Line 2",
-             "TextPosition anchor_id=4 text_offset=4 "
-             "affinity=downstream annotated_text=Line< >1\nLine 2",
-             "TextPosition anchor_id=4 text_offset=0 "
-             "affinity=downstream annotated_text=<L>ine 1\nLine 2"}},
-        TextNavigationTestParam{
-            base::BindRepeating([](const TestPositionType& position) {
-              return position->CreatePreviousWordEndPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
-            }),
-            STATIC_TEXT1_ID,
-            5 /* text_offset */,
-            {"TextPosition anchor_id=5 text_offset=4 "
-             "affinity=downstream annotated_text=Line< >1",
-             "TextPosition anchor_id=5 text_offset=0 "
-             "affinity=downstream annotated_text=<L>ine 1"}},
-        TextNavigationTestParam{
-            base::BindRepeating([](const TestPositionType& position) {
-              return position->CreatePreviousWordEndPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
-            }),
-            INLINE_BOX2_ID,
-            4 /* text_offset */,
-            {"TextPosition anchor_id=9 text_offset=0 "
-             "affinity=downstream annotated_text=<L>ine 2"}}));
-
-INSTANTIATE_TEST_SUITE_P(
-    CreatePreviousWordEndPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary,
-    AXPositionTextNavigationTestWithParam,
-    ::testing::Values(
-        TextNavigationTestParam{
-            base::BindRepeating([](const TestPositionType& position) {
-              return position->CreatePreviousWordEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
-            }),
-            ROOT_ID,
-            13 /* text_offset at end of root. */,
-            {"TextPosition anchor_id=1 text_offset=13 "
-             "affinity=downstream annotated_text=Line 1\nLine 2<>"}},
-        TextNavigationTestParam{
-            base::BindRepeating([](const TestPositionType& position) {
-              return position->CreatePreviousWordEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
-            }),
-            TEXT_FIELD_ID,
-            13 /* text_offset at end of text field */,
-            {"TextPosition anchor_id=4 text_offset=13 "
-             "affinity=downstream annotated_text=Line 1\nLine 2<>"}},
-        TextNavigationTestParam{
-            base::BindRepeating([](const TestPositionType& position) {
-              return position->CreatePreviousWordEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
-            }),
-            STATIC_TEXT1_ID,
-            5 /* text_offset */,
-            {"TextPosition anchor_id=5 text_offset=4 "
-             "affinity=downstream annotated_text=Line< >1",
-             "TextPosition anchor_id=5 text_offset=4 "
-             "affinity=downstream annotated_text=Line< >1"}},
-        TextNavigationTestParam{
-            base::BindRepeating([](const TestPositionType& position) {
-              return position->CreatePreviousWordEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
-            }),
-            INLINE_BOX2_ID,
-            4 /* text_offset */,
-            {"TextPosition anchor_id=9 text_offset=4 "
-             "affinity=downstream annotated_text=Line< >2"}}));
-
-INSTANTIATE_TEST_SUITE_P(
-    CreatePreviousWordEndPositionWithBoundaryBehaviorStopAtLastAnchorBoundary,
-    AXPositionTextNavigationTestWithParam,
-    ::testing::Values(
-        TextNavigationTestParam{
-            base::BindRepeating([](const TestPositionType& position) {
-              return position->CreatePreviousWordEndPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             ROOT_ID,
             13 /* text_offset at end of root. */,
@@ -13333,7 +14176,111 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousWordEndPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
+            }),
+            TEXT_FIELD_ID,
+            13 /* text_offset at end of text field */,
+            {"TextPosition anchor_id=4 text_offset=11 "
+             "affinity=downstream annotated_text=Line 1\nLine< >2",
+             "TextPosition anchor_id=4 text_offset=6 "
+             "affinity=downstream annotated_text=Line 1<\n>Line 2",
+             "TextPosition anchor_id=4 text_offset=4 "
+             "affinity=downstream annotated_text=Line< >1\nLine 2",
+             "TextPosition anchor_id=4 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1\nLine 2"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousWordEndPosition(
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
+            }),
+            STATIC_TEXT1_ID,
+            5 /* text_offset */,
+            {"TextPosition anchor_id=5 text_offset=4 "
+             "affinity=downstream annotated_text=Line< >1",
+             "TextPosition anchor_id=5 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousWordEndPosition(
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
+            }),
+            INLINE_BOX2_ID,
+            4 /* text_offset */,
+            {"TextPosition anchor_id=9 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 2"}}));
+
+INSTANTIATE_TEST_SUITE_P(
+    CreatePreviousWordEndPositionWithBoundaryBehaviorStopAtAnchorBoundaryOrIfAlreadyAtBoundary,
+    AXPositionTextNavigationTestWithParam,
+    ::testing::Values(
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousWordEndPosition(
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
+            }),
+            ROOT_ID,
+            13 /* text_offset at end of root. */,
+            {"TextPosition anchor_id=1 text_offset=13 "
+             "affinity=downstream annotated_text=Line 1\nLine 2<>"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousWordEndPosition(
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
+            }),
+            TEXT_FIELD_ID,
+            13 /* text_offset at end of text field */,
+            {"TextPosition anchor_id=4 text_offset=13 "
+             "affinity=downstream annotated_text=Line 1\nLine 2<>"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousWordEndPosition(
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
+            }),
+            STATIC_TEXT1_ID,
+            5 /* text_offset */,
+            {"TextPosition anchor_id=5 text_offset=4 "
+             "affinity=downstream annotated_text=Line< >1",
+             "TextPosition anchor_id=5 text_offset=4 "
+             "affinity=downstream annotated_text=Line< >1"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousWordEndPosition(
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
+            }),
+            INLINE_BOX2_ID,
+            4 /* text_offset */,
+            {"TextPosition anchor_id=9 text_offset=4 "
+             "affinity=downstream annotated_text=Line< >2"}}));
+
+INSTANTIATE_TEST_SUITE_P(
+    CreatePreviousWordEndPositionWithBoundaryBehaviorStopAtLastAnchorBoundary,
+    AXPositionTextNavigationTestWithParam,
+    ::testing::Values(
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousWordEndPosition(
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
+            }),
+            ROOT_ID,
+            13 /* text_offset at end of root. */,
+            {"TextPosition anchor_id=1 text_offset=11 "
+             "affinity=downstream annotated_text=Line 1\nLine< >2",
+             "TextPosition anchor_id=1 text_offset=6 "
+             "affinity=downstream annotated_text=Line 1<\n>Line 2",
+             "TextPosition anchor_id=1 text_offset=4 "
+             "affinity=downstream annotated_text=Line< >1\nLine 2",
+             "TextPosition anchor_id=1 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1\nLine 2",
+             "TextPosition anchor_id=1 text_offset=0 "
+             "affinity=downstream annotated_text=<L>ine 1\nLine 2"}},
+        TextNavigationTestParam{
+            base::BindRepeating([](const TestPositionType& position) {
+              return position->CreatePreviousWordEndPosition(
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             TEXT_FIELD_ID,
             13 /* text_offset at end of text field */,
@@ -13350,7 +14297,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousWordEndPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             STATIC_TEXT1_ID,
             5 /* text_offset */,
@@ -13363,12 +14310,12 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousWordEndPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
-            {"TextPosition anchor_id=6 text_offset=6 "
-             "affinity=downstream annotated_text=Line 1<>",
+            {"TextPosition anchor_id=6 text_offset=6 affinity=downstream "
+             "annotated_text=Line 1<>",
              "TextPosition anchor_id=6 text_offset=4 "
              "affinity=downstream annotated_text=Line< >1",
              "TextPosition anchor_id=2 text_offset=0 "
@@ -13383,7 +14330,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineStartPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             ROOT_ID,
             0 /* text_offset */,
@@ -13393,7 +14340,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineStartPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             TEXT_FIELD_ID,
             0 /* text_offset */,
@@ -13403,7 +14350,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineStartPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             STATIC_TEXT1_ID,
             1 /* text_offset */,
@@ -13413,7 +14360,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineStartPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -13426,7 +14373,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineStartPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             ROOT_ID,
             0 /* text_offset */,
@@ -13437,7 +14384,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineStartPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             TEXT_FIELD_ID,
             0 /* text_offset */,
@@ -13448,7 +14395,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineStartPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             STATIC_TEXT1_ID,
             1 /* text_offset */,
@@ -13457,7 +14404,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineStartPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -13465,13 +14412,14 @@
              "affinity=downstream annotated_text=Line 2<>"}}));
 
 INSTANTIATE_TEST_SUITE_P(
-    CreateNextLineStartPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary,
+    CreateNextLineStartPositionWithBoundaryBehaviorStopAtAnchorBoundaryOrIfAlreadyAtBoundary,
     AXPositionTextNavigationTestWithParam,
     ::testing::Values(
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineStartPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             ROOT_ID,
             0 /* text_offset */,
@@ -13482,7 +14430,8 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineStartPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             TEXT_FIELD_ID,
             0 /* text_offset */,
@@ -13493,22 +14442,25 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineStartPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             STATIC_TEXT1_ID,
             1 /* text_offset */,
-            {"TextPosition anchor_id=9 text_offset=0 "
-             "affinity=downstream annotated_text=<L>ine 2",
-             "TextPosition anchor_id=9 text_offset=0 "
-             "affinity=downstream annotated_text=<L>ine 2"}},
+            {"TextPosition anchor_id=5 text_offset=6 affinity=downstream "
+             "annotated_text=Line 1<>",
+             "TextPosition anchor_id=5 text_offset=6 affinity=downstream "
+             "annotated_text=Line 1<>"}},
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineStartPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
-            {"NullPosition"}}));
+            {"TextPosition anchor_id=9 text_offset=6 affinity=downstream "
+             "annotated_text=Line 2<>"}}));
 
 INSTANTIATE_TEST_SUITE_P(
     CreateNextLineStartPositionWithBoundaryBehaviorStopAtLastAnchorBoundary,
@@ -13517,7 +14469,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineStartPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             ROOT_ID,
             0 /* text_offset */,
@@ -13530,7 +14482,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineStartPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             TEXT_FIELD_ID,
             0 /* text_offset */,
@@ -13543,7 +14495,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineStartPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             STATIC_TEXT1_ID,
             1 /* text_offset */,
@@ -13556,7 +14508,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineStartPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -13572,7 +14524,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineStartPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             ROOT_ID,
             13 /* text_offset at the end of root. */,
@@ -13584,7 +14536,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineStartPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             TEXT_FIELD_ID,
             13 /* text_offset at end of text field */,
@@ -13596,7 +14548,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineStartPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             STATIC_TEXT1_ID,
             5 /* text_offset */,
@@ -13606,7 +14558,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineStartPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -13623,7 +14575,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineStartPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             ROOT_ID,
             13 /* text_offset at the end of root. */,
@@ -13636,7 +14588,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineStartPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             TEXT_FIELD_ID,
             13 /* text_offset at end of text field */,
@@ -13649,7 +14601,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineStartPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             STATIC_TEXT1_ID,
             5 /* text_offset */,
@@ -13660,7 +14612,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineStartPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -13670,13 +14622,14 @@
              "affinity=downstream annotated_text=<L>ine 2"}}));
 
 INSTANTIATE_TEST_SUITE_P(
-    CreatePreviousLineStartPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary,
+    CreatePreviousLineStartPositionWithBoundaryBehaviorStopAtAnchorBoundaryOrIfAlreadyAtBoundary,
     AXPositionTextNavigationTestWithParam,
     ::testing::Values(
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineStartPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             ROOT_ID,
             13 /* text_offset at the end of root. */,
@@ -13687,7 +14640,8 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineStartPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             TEXT_FIELD_ID,
             13 /* text_offset at end of text field */,
@@ -13698,7 +14652,8 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineStartPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             STATIC_TEXT1_ID,
             5 /* text_offset */,
@@ -13709,7 +14664,8 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineStartPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -13725,7 +14681,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineStartPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             ROOT_ID,
             13 /* text_offset at the end of root. */,
@@ -13738,7 +14694,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineStartPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             TEXT_FIELD_ID,
             13 /* text_offset at end of text field */,
@@ -13751,7 +14707,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineStartPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             STATIC_TEXT1_ID,
             5 /* text_offset */,
@@ -13762,7 +14718,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineStartPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -13780,7 +14736,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineEndPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             ROOT_ID,
             0 /* text_offset */,
@@ -13792,7 +14748,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineEndPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             TEXT_FIELD_ID,
             0 /* text_offset */,
@@ -13804,7 +14760,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineEndPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             STATIC_TEXT1_ID,
             1 /* text_offset */,
@@ -13816,7 +14772,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineEndPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -13831,7 +14787,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineEndPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             ROOT_ID,
             0 /* text_offset */,
@@ -13844,7 +14800,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineEndPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             TEXT_FIELD_ID,
             0 /* text_offset */,
@@ -13857,7 +14813,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineEndPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             STATIC_TEXT1_ID,
             1 /* text_offset */,
@@ -13868,7 +14824,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineEndPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -13878,13 +14834,14 @@
              "affinity=downstream annotated_text=Line 2<>"}}));
 
 INSTANTIATE_TEST_SUITE_P(
-    CreateNextLineEndPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary,
+    CreateNextLineEndPositionWithBoundaryBehaviorStopAtAnchorBoundaryOrIfAlreadyAtBoundary,
     AXPositionTextNavigationTestWithParam,
     ::testing::Values(
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             ROOT_ID,
             0 /* text_offset */,
@@ -13895,7 +14852,8 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             TEXT_FIELD_ID,
             0 /* text_offset */,
@@ -13906,7 +14864,8 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             STATIC_TEXT1_ID,
             1 /* text_offset */,
@@ -13917,7 +14876,8 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -13933,7 +14893,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineEndPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             ROOT_ID,
             0 /* text_offset */,
@@ -13946,7 +14906,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineEndPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             TEXT_FIELD_ID,
             0 /* text_offset */,
@@ -13959,7 +14919,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineEndPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             STATIC_TEXT1_ID,
             1 /* text_offset */,
@@ -13972,7 +14932,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextLineEndPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -13988,7 +14948,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineEndPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             ROOT_ID,
             13 /* text_offset at end of root. */,
@@ -13998,7 +14958,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineEndPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             TEXT_FIELD_ID,
             13 /* text_offset at end of text field */,
@@ -14008,7 +14968,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineEndPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             ROOT_ID,
             5 /* text_offset on the last character of "Line 1". */,
@@ -14016,7 +14976,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineEndPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             TEXT_FIELD_ID,
             5 /* text_offset on the last character of "Line 1". */,
@@ -14024,7 +14984,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineEndPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -14034,7 +14994,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineEndPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             INLINE_BOX2_ID,
             0 /* text_offset */,
@@ -14049,7 +15009,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineEndPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             ROOT_ID,
             13 /* text_offset at end of root. */,
@@ -14060,7 +15020,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineEndPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             TEXT_FIELD_ID,
             13 /* text_offset at end of text field */,
@@ -14071,7 +15031,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineEndPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             ROOT_ID,
             5 /* text_offset on the last character of "Line 1". */,
@@ -14082,7 +15042,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineEndPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             TEXT_FIELD_ID,
             5 /* text_offset on the last character of "Line 1". */,
@@ -14093,7 +15053,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineEndPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -14104,7 +15064,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineEndPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             INLINE_BOX2_ID,
             0 /* text_offset */,
@@ -14114,13 +15074,14 @@
              "affinity=downstream annotated_text=<L>ine 2"}}));
 
 INSTANTIATE_TEST_SUITE_P(
-    CreatePreviousLineEndPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary,
+    CreatePreviousLineEndPositionWithBoundaryBehaviorStopAtAnchorBoundaryOrIfAlreadyAtBoundary,
     AXPositionTextNavigationTestWithParam,
     ::testing::Values(
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             ROOT_ID,
             12 /* text_offset one before the end of root. */,
@@ -14131,7 +15092,8 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             TEXT_FIELD_ID,
             12 /* text_offset one before the end of text field */,
@@ -14142,33 +15104,39 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             INLINE_BOX1_ID,
             2 /* text_offset */,
-            {"NullPosition"}},
+            {"TextPosition anchor_id=6 text_offset=0 affinity=downstream "
+             "annotated_text=<L>ine 1",
+             "TextPosition anchor_id=6 text_offset=0 affinity=downstream "
+             "annotated_text=<L>ine 1"}},
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
-            {"TextPosition anchor_id=6 text_offset=6 "
-             "affinity=downstream annotated_text=Line 1<>",
-             "TextPosition anchor_id=6 text_offset=6 "
-             "affinity=downstream annotated_text=Line 1<>"}},
+            {"TextPosition anchor_id=9 text_offset=0 affinity=downstream "
+             "annotated_text=<L>ine 2",
+             "TextPosition anchor_id=9 text_offset=0 affinity=downstream "
+             "annotated_text=<L>ine 2"}},
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             INLINE_BOX2_ID,
             0 /* text_offset */,
-            {"TextPosition anchor_id=6 text_offset=6 "
-             "affinity=downstream annotated_text=Line 1<>",
-             "TextPosition anchor_id=6 text_offset=6 "
-             "affinity=downstream annotated_text=Line 1<>"}}));
+            {"TextPosition anchor_id=9 text_offset=0 affinity=downstream "
+             "annotated_text=<L>ine 2",
+             "TextPosition anchor_id=9 text_offset=0 affinity=downstream "
+             "annotated_text=<L>ine 2"}}));
 
 INSTANTIATE_TEST_SUITE_P(
     CreatePreviousLineEndPositionWithBoundaryBehaviorStopAtLastAnchorBoundary,
@@ -14177,7 +15145,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineEndPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             ROOT_ID,
             13 /* text_offset at end of root. */,
@@ -14190,7 +15158,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineEndPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             TEXT_FIELD_ID,
             13 /* text_offset at end of text field */,
@@ -14203,7 +15171,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineEndPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             ROOT_ID,
             5 /* text_offset on the last character of "Line 1". */,
@@ -14214,7 +15182,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineEndPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             TEXT_FIELD_ID,
             5 /* text_offset on the last character of "Line 1". */,
@@ -14225,7 +15193,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineEndPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -14238,7 +15206,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousLineEndPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             INLINE_BOX2_ID,
             0 /* text_offset */,
@@ -14256,7 +15224,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphStartPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             ROOT_ID,
             0 /* text_offset */,
@@ -14265,7 +15233,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphStartPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             TEXT_FIELD_ID,
             0 /* text_offset */,
@@ -14274,7 +15242,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphStartPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             STATIC_TEXT1_ID,
             1 /* text_offset */,
@@ -14283,7 +15251,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphStartPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -14296,7 +15264,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphStartPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             ROOT_ID,
             0 /* text_offset */,
@@ -14307,7 +15275,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphStartPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             TEXT_FIELD_ID,
             0 /* text_offset */,
@@ -14318,7 +15286,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphStartPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             STATIC_TEXT1_ID,
             1 /* text_offset */,
@@ -14327,7 +15295,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphStartPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -14335,13 +15303,14 @@
              "affinity=downstream annotated_text=Line 2<>"}}));
 
 INSTANTIATE_TEST_SUITE_P(
-    CreateNextParagraphStartPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary,
+    CreateNextParagraphStartPositionWithBoundaryBehaviorStopAtAnchorBoundaryOrIfAlreadyAtBoundary,
     AXPositionTextNavigationTestWithParam,
     ::testing::Values(
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphStartPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             ROOT_ID,
             0 /* text_offset */,
@@ -14352,7 +15321,8 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphStartPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             TEXT_FIELD_ID,
             0 /* text_offset */,
@@ -14363,22 +15333,25 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphStartPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             STATIC_TEXT1_ID,
             1 /* text_offset */,
-            {"TextPosition anchor_id=9 text_offset=0 "
-             "affinity=downstream annotated_text=<L>ine 2",
-             "TextPosition anchor_id=9 text_offset=0 "
-             "affinity=downstream annotated_text=<L>ine 2"}},
+            {"TextPosition anchor_id=5 text_offset=6 affinity=downstream "
+             "annotated_text=Line 1<>",
+             "TextPosition anchor_id=5 text_offset=6 affinity=downstream "
+             "annotated_text=Line 1<>"}},
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphStartPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
-            {"NullPosition"}}));
+            {"TextPosition anchor_id=9 text_offset=6 affinity=downstream "
+             "annotated_text=Line 2<>"}}));
 
 INSTANTIATE_TEST_SUITE_P(
     CreateNextParagraphStartPositionWithBoundaryBehaviorStopAtLastAnchorBoundary,
@@ -14387,7 +15360,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphStartPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             ROOT_ID,
             0 /* text_offset */,
@@ -14400,7 +15373,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphStartPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             TEXT_FIELD_ID,
             0 /* text_offset */,
@@ -14413,7 +15386,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphStartPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             STATIC_TEXT1_ID,
             1 /* text_offset */,
@@ -14426,7 +15399,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphStartPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -14442,7 +15415,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphStartPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             ROOT_ID,
             13 /* text_offset at the end of root. */,
@@ -14454,7 +15427,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphStartPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             TEXT_FIELD_ID,
             13 /* text_offset at end of text field */,
@@ -14466,7 +15439,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphStartPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             STATIC_TEXT1_ID,
             5 /* text_offset */,
@@ -14476,7 +15449,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphStartPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -14493,7 +15466,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphStartPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             ROOT_ID,
             13 /* text_offset at the end of root. */,
@@ -14506,7 +15479,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphStartPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             TEXT_FIELD_ID,
             13 /* text_offset at end of text field */,
@@ -14519,7 +15492,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphStartPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             STATIC_TEXT1_ID,
             5 /* text_offset */,
@@ -14530,7 +15503,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphStartPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -14540,13 +15513,14 @@
              "affinity=downstream annotated_text=<L>ine 2"}}));
 
 INSTANTIATE_TEST_SUITE_P(
-    CreatePreviousParagraphStartPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary,
+    CreatePreviousParagraphStartPositionWithBoundaryBehaviorStopAtAnchorBoundaryOrIfAlreadyAtBoundary,
     AXPositionTextNavigationTestWithParam,
     ::testing::Values(
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphStartPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             ROOT_ID,
             13 /* text_offset at the end of root. */,
@@ -14557,7 +15531,8 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphStartPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             TEXT_FIELD_ID,
             13 /* text_offset at end of text field */,
@@ -14568,7 +15543,8 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphStartPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             STATIC_TEXT1_ID,
             5 /* text_offset */,
@@ -14579,7 +15555,8 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphStartPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -14595,7 +15572,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphStartPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             ROOT_ID,
             13 /* text_offset at the end of root. */,
@@ -14610,7 +15587,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphStartPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             TEXT_FIELD_ID,
             13 /* text_offset at end of text field */,
@@ -14623,7 +15600,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphStartPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             STATIC_TEXT1_ID,
             5 /* text_offset */,
@@ -14634,7 +15611,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphStartPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -14652,7 +15629,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphEndPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             ROOT_ID,
             0 /* text_offset */,
@@ -14664,7 +15641,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphEndPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             TEXT_FIELD_ID,
             0 /* text_offset */,
@@ -14676,7 +15653,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphEndPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             STATIC_TEXT1_ID,
             1 /* text_offset */,
@@ -14688,7 +15665,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphEndPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -14703,7 +15680,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphEndPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             ROOT_ID,
             0 /* text_offset */,
@@ -14718,7 +15695,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphEndPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             TEXT_FIELD_ID,
             0 /* text_offset */,
@@ -14733,7 +15710,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphEndPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             STATIC_TEXT1_ID,
             1 /* text_offset */,
@@ -14744,7 +15721,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphEndPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -14754,13 +15731,14 @@
              "affinity=downstream annotated_text=Line 2<>"}}));
 
 INSTANTIATE_TEST_SUITE_P(
-    CreateNextParagraphEndPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary,
+    CreateNextParagraphEndPositionWithBoundaryBehaviorStopAtAnchorBoundaryOrIfAlreadyAtBoundary,
     AXPositionTextNavigationTestWithParam,
     ::testing::Values(
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             ROOT_ID,
             0 /* text_offset */,
@@ -14776,18 +15754,20 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             TEXT_FIELD_ID,
             5 /* text_offset */,
             {"TextPosition anchor_id=4 text_offset=6 "
              "affinity=downstream annotated_text=Line 1<\n>Line 2",
-             "TextPosition anchor_id=4 text_offset=13 "
-             "affinity=downstream annotated_text=Line 1\nLine 2<>"}},
+             "TextPosition anchor_id=4 text_offset=6 affinity=downstream "
+             "annotated_text=Line 1<\n>Line 2"}},
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             STATIC_TEXT1_ID,
             1 /* text_offset */,
@@ -14798,7 +15778,8 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -14809,25 +15790,27 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             LINE_BREAK_ID,
             0 /* text_offset */,
-            {"TextPosition anchor_id=9 text_offset=6 "
-             "affinity=downstream annotated_text=Line 2<>",
-             "TextPosition anchor_id=9 text_offset=6 "
-             "affinity=downstream annotated_text=Line 2<>"}},
+            {"TextPosition anchor_id=7 text_offset=1 affinity=downstream "
+             "annotated_text=\n<>",
+             "TextPosition anchor_id=7 text_offset=1 affinity=downstream "
+             "annotated_text=\n<>"}},
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             LINE_BREAK_ID,
             1 /* text_offset */,
-            {"TextPosition anchor_id=9 text_offset=6 "
-             "affinity=downstream annotated_text=Line 2<>",
-             "TextPosition anchor_id=9 text_offset=6 "
-             "affinity=downstream annotated_text=Line 2<>"}}));
+            {"TextPosition anchor_id=7 text_offset=1 affinity=downstream "
+             "annotated_text=\n<>",
+             "TextPosition anchor_id=7 text_offset=1 affinity=downstream "
+             "annotated_text=\n<>"}}));
 
 INSTANTIATE_TEST_SUITE_P(
     CreateNextParagraphEndPositionWithBoundaryBehaviorStopAtLastAnchorBoundary,
@@ -14836,7 +15819,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphEndPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             ROOT_ID,
             0 /* text_offset */,
@@ -14849,7 +15832,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphEndPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             TEXT_FIELD_ID,
             0 /* text_offset */,
@@ -14862,7 +15845,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphEndPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             STATIC_TEXT1_ID,
             1 /* text_offset */,
@@ -14875,7 +15858,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreateNextParagraphEndPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -14891,7 +15874,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphEndPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             ROOT_ID,
             13 /* text_offset at end of root. */,
@@ -14903,7 +15886,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphEndPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             TEXT_FIELD_ID,
             13 /* text_offset at end of text field */,
@@ -14915,7 +15898,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphEndPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             ROOT_ID,
             5 /* text_offset on the last character of "Line 1". */,
@@ -14925,7 +15908,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphEndPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             TEXT_FIELD_ID,
             5 /* text_offset on the last character of "Line 1". */,
@@ -14935,7 +15918,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphEndPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -14947,7 +15930,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphEndPosition(
-                  AXBoundaryBehavior::CrossBoundary);
+                  AXBoundaryBehavior::kCrossBoundary);
             }),
             INLINE_BOX2_ID,
             0 /* text_offset */,
@@ -14964,7 +15947,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphEndPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             ROOT_ID,
             13 /* text_offset at end of root. */,
@@ -14977,7 +15960,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphEndPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             TEXT_FIELD_ID,
             13 /* text_offset at end of text field */,
@@ -14990,7 +15973,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphEndPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             ROOT_ID,
             5 /* text_offset on the last character of "Line 1". */,
@@ -15001,7 +15984,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphEndPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             TEXT_FIELD_ID,
             5 /* text_offset on the last character of "Line 1". */,
@@ -15012,7 +15995,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphEndPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -15023,7 +16006,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphEndPosition(
-                  AXBoundaryBehavior::StopAtAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtAnchorBoundary);
             }),
             INLINE_BOX2_ID,
             0 /* text_offset */,
@@ -15033,13 +16016,14 @@
              "annotated_text=<L>ine 2"}}));
 
 INSTANTIATE_TEST_SUITE_P(
-    CreatePreviousParagraphEndPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary,
+    CreatePreviousParagraphEndPositionWithBoundaryBehaviorStopAtAnchorBoundaryOrIfAlreadyAtBoundary,
     AXPositionTextNavigationTestWithParam,
     ::testing::Values(
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             ROOT_ID,
             12 /* text_offset one before the end of root. */,
@@ -15050,7 +16034,8 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             TEXT_FIELD_ID,
             12 /* text_offset one before the end of text field */,
@@ -15061,58 +16046,63 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             INLINE_BOX1_ID,
             2 /* text_offset */,
-            {"TextPosition anchor_id=3 text_offset=0 "
-             "affinity=downstream annotated_text=<>",
-             "TextPosition anchor_id=3 text_offset=0 "
-             "affinity=downstream annotated_text=<>"}},
+            {"TextPosition anchor_id=6 text_offset=0 affinity=downstream "
+             "annotated_text=<L>ine 1",
+             "TextPosition anchor_id=6 text_offset=0 affinity=downstream "
+             "annotated_text=<L>ine 1"}},
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
-            {"TextPosition anchor_id=6 text_offset=6 "
-             "affinity=downstream annotated_text=Line 1<>",
-             "TextPosition anchor_id=6 text_offset=6 "
-             "affinity=downstream annotated_text=Line 1<>"}},
+            {"TextPosition anchor_id=9 text_offset=0 affinity=downstream "
+             "annotated_text=<L>ine 2",
+             "TextPosition anchor_id=9 text_offset=0 affinity=downstream "
+             "annotated_text=<L>ine 2"}},
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             INLINE_BOX2_ID,
             0 /* text_offset */,
-            {"TextPosition anchor_id=6 text_offset=6 "
-             "affinity=downstream annotated_text=Line 1<>",
-             "TextPosition anchor_id=6 text_offset=6 "
-             "affinity=downstream annotated_text=Line 1<>"}},
+            {"TextPosition anchor_id=9 text_offset=0 affinity=downstream "
+             "annotated_text=<L>ine 2",
+             "TextPosition anchor_id=9 text_offset=0 affinity=downstream "
+             "annotated_text=<L>ine 2"}},
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             LINE_BREAK_ID,
             0 /* text_offset */,
-            {"TextPosition anchor_id=6 text_offset=6 "
-             "affinity=downstream annotated_text=Line 1<>",
-             "TextPosition anchor_id=6 text_offset=6 "
-             "affinity=downstream annotated_text=Line 1<>"}},
+            {"TextPosition anchor_id=7 text_offset=0 affinity=downstream "
+             "annotated_text=<\n>",
+             "TextPosition anchor_id=7 text_offset=0 affinity=downstream "
+             "annotated_text=<\n>"}},
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphEndPosition(
-                  AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary);
             }),
             LINE_BREAK_ID,
             1 /* text_offset */,
-            {"TextPosition anchor_id=6 text_offset=6 "
-             "affinity=downstream annotated_text=Line 1<>",
-             "TextPosition anchor_id=6 text_offset=6 "
-             "affinity=downstream annotated_text=Line 1<>"}}));
+            {"TextPosition anchor_id=7 text_offset=0 affinity=downstream "
+             "annotated_text=<\n>",
+             "TextPosition anchor_id=7 text_offset=0 affinity=downstream "
+             "annotated_text=<\n>"}}));
 
 INSTANTIATE_TEST_SUITE_P(
     CreatePreviousParagraphEndPositionWithBoundaryBehaviorStopAtLastAnchorBoundary,
@@ -15121,7 +16111,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphEndPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             ROOT_ID,
             13 /* text_offset at end of root. */,
@@ -15134,7 +16124,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphEndPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             TEXT_FIELD_ID,
             13 /* text_offset at end of text field */,
@@ -15147,7 +16137,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphEndPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             ROOT_ID,
             5 /* text_offset on the last character of "Line 1". */,
@@ -15158,7 +16148,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphEndPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             TEXT_FIELD_ID,
             5 /* text_offset on the last character of "Line 1". */,
@@ -15169,7 +16159,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphEndPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             INLINE_BOX2_ID,
             4 /* text_offset */,
@@ -15182,7 +16172,7 @@
         TextNavigationTestParam{
             base::BindRepeating([](const TestPositionType& position) {
               return position->CreatePreviousParagraphEndPosition(
-                  AXBoundaryBehavior::StopAtLastAnchorBoundary);
+                  AXBoundaryBehavior::kStopAtLastAnchorBoundary);
             }),
             INLINE_BOX2_ID,
             0 /* text_offset */,
diff --git a/ui/accessibility/ax_position.h b/ui/accessibility/ax_position.h
index 4e1ca6b..38753d9 100644
--- a/ui/accessibility/ax_position.h
+++ b/ui/accessibility/ax_position.h
@@ -47,13 +47,30 @@
 enum class AXPositionKind { NULL_POSITION, TREE_POSITION, TEXT_POSITION };
 
 // Defines how creating the next or previous position should behave whenever we
-// are at or are crossing a boundary, such as at the start of an anchor, a word
-// or a line.
+// are at or are crossing a text boundary, (such as the start of a word or the
+// end of a sentence), or whenever we are crossing the initial position's
+// anchor. Note that the "anchor" is the node to which an AXPosition is attached
+// to. It is provided when a position is created.
 enum class AXBoundaryBehavior {
-  CrossBoundary,
-  StopAtAnchorBoundary,
-  StopIfAlreadyAtBoundary,
-  StopAtLastAnchorBoundary
+  // Crosses all boundaries. If the bounds of the current window-like container,
+  // such as the current webpage, have been reached, returns a null position.
+  kCrossBoundary,
+  // Stops if the current anchor is crossed, regardless of how the resulting
+  // position has been computed. For example, even though in order to find the
+  // next or previous word start in a text field we need to descend to the leaf
+  // equivalent position, this behavior will only stop when the bounds of the
+  // original anchor, i.e. the text field, have been crossed.
+  kStopAtAnchorBoundary,
+  // Stops if the current anchor is crossed or if we are already at the
+  // requested boundary. For an example of the former, imagine a position inside
+  // a text field and the resulting position outside it. For an example of the
+  // latter, say we are moving to the previous word start position when we are
+  // already at the start of a word.
+  kStopAtAnchorBoundaryOrIfAlreadyAtBoundary,
+  // Stops if we have reached the start or the end of of a window-like
+  // container, such as a webpage, a PDF, a dialog, the browser's UI (AKA
+  // Views), or the whole desktop.
+  kStopAtLastAnchorBoundary
 };
 
 // Describes in further detail what type of boundary a current position is on.
@@ -198,7 +215,8 @@
       base::RepeatingCallback<bool(const AXPositionInstance&)>;
 
   using BoundaryTextOffsetsFunc =
-      base::RepeatingCallback<std::vector<int32_t>(const AXPositionInstance&)>;
+      base::RepeatingCallback<const std::vector<int32_t>&(
+          const AXPositionInstance&)>;
 
   static const int BEFORE_TEXT = -1;
   static const int INVALID_INDEX = -2;
@@ -343,7 +361,7 @@
       }
     }
 
-    if (!IsTextPosition() || text_offset_ > MaxTextOffset())
+    if (!IsTextPosition() || text_offset_ < 0 || text_offset_ > MaxTextOffset())
       return str;
 
     const std::u16string& text = GetText();
@@ -558,7 +576,18 @@
   }
 
   bool AtStartOfWord() const {
-    AXPositionInstance text_position = AsLeafTextPosition();
+    AXPositionInstance text_position;
+    if (!AtEndOfAnchor()) {
+      // We could get a leaf text position at the end of its anchor, where word
+      // start offsets would surely not be present. In such cases, we need to
+      // normalize to the start of the next leaf anchor. We avoid making this
+      // change when we are at the end of our anchor because this could
+      // effectively shift the position forward.
+      text_position = AsLeafTextPositionBeforeCharacter();
+    } else {
+      text_position = AsLeafTextPosition();
+    }
+
     switch (text_position->kind_) {
       case AXPositionKind::NULL_POSITION:
         return false;
@@ -566,7 +595,7 @@
         NOTREACHED();
         return false;
       case AXPositionKind::TEXT_POSITION: {
-        const std::vector<int32_t> word_starts =
+        const std::vector<int32_t>& word_starts =
             text_position->GetWordStartOffsets();
         return base::Contains(word_starts,
                               int32_t{text_position->text_offset_});
@@ -575,7 +604,18 @@
   }
 
   bool AtEndOfWord() const {
-    AXPositionInstance text_position = AsLeafTextPosition();
+    AXPositionInstance text_position;
+    if (!AtStartOfAnchor()) {
+      // We could get a leaf text position at the start of its anchor, where
+      // word end offsets would surely not be present. In such cases, we need to
+      // normalize to the end of the previous leaf anchor. We avoid making this
+      // change when we are at the start of our anchor because this could
+      // effectively shift the position backward.
+      text_position = AsLeafTextPositionAfterCharacter();
+    } else {
+      text_position = AsLeafTextPosition();
+    }
+
     switch (text_position->kind_) {
       case AXPositionKind::NULL_POSITION:
         return false;
@@ -583,13 +623,71 @@
         NOTREACHED();
         return false;
       case AXPositionKind::TEXT_POSITION: {
-        const std::vector<int32_t> word_ends =
+        const std::vector<int32_t>& word_ends =
             text_position->GetWordEndOffsets();
         return base::Contains(word_ends, int32_t{text_position->text_offset_});
       }
     }
   }
 
+  bool AtStartOfSentence() const {
+    AXPositionInstance text_position;
+    if (!AtEndOfAnchor()) {
+      // We could get a leaf text position at the end of its anchor, where
+      // sentence start offsets would surely not be present. In such cases, we
+      // need to normalize to the start of the next leaf anchor. We avoid making
+      // this change when we are at the end of our anchor because this could
+      // effectively shift the position forward.
+      text_position = AsLeafTextPositionBeforeCharacter();
+    } else {
+      text_position = AsLeafTextPosition();
+    }
+
+    switch (text_position->kind_) {
+      case AXPositionKind::NULL_POSITION:
+        return false;
+      case AXPositionKind::TREE_POSITION:
+        NOTREACHED();
+        return false;
+      case AXPositionKind::TEXT_POSITION: {
+        const std::vector<int32_t>& sentence_starts =
+            text_position->GetAnchor()->GetIntListAttribute(
+                ax::mojom::IntListAttribute::kSentenceStarts);
+        return base::Contains(sentence_starts,
+                              int32_t{text_position->text_offset_});
+      }
+    }
+  }
+
+  bool AtEndOfSentence() const {
+    AXPositionInstance text_position;
+    if (!AtStartOfAnchor()) {
+      // We could get a leaf text position at the start of its anchor, where
+      // sentence end offsets would surely not be present. In such cases, we
+      // need to normalize to the end of the previous leaf anchor. We avoid
+      // making this change when we are at the start of our anchor because this
+      // could effectively shift the position backward.
+      text_position = AsLeafTextPositionAfterCharacter();
+    } else {
+      text_position = AsLeafTextPosition();
+    }
+
+    switch (text_position->kind_) {
+      case AXPositionKind::NULL_POSITION:
+        return false;
+      case AXPositionKind::TREE_POSITION:
+        NOTREACHED();
+        return false;
+      case AXPositionKind::TEXT_POSITION: {
+        const std::vector<int32_t>& sentence_ends =
+            text_position->GetAnchor()->GetIntListAttribute(
+                ax::mojom::IntListAttribute::kSentenceEnds);
+        return base::Contains(sentence_ends,
+                              int32_t{text_position->text_offset_});
+      }
+    }
+  }
+
   bool AtStartOfLine() const {
     AXPositionInstance text_position = AsLeafTextPosition();
     switch (text_position->kind_) {
@@ -1606,40 +1704,50 @@
   // text boundary, and creates an AXRange that spans from the former to the
   // latter. The resulting AXRange is always a forward range: its anchor always
   // comes before its focus in document order. The resulting AXRange is bounded
-  // by the anchor of this position, i.e. the AXBoundaryBehavior is set to
-  // StopAtAnchorBoundary. The exception is ax::mojom::TextBoundary::kWebPage,
-  // where this behavior won't make sense. This behavior is based on current
-  // platform needs and might be relaxed if necessary in the future.
+  // by the anchor of this position and the requested boundary type, i.e. the
+  // AXBoundaryBehavior is set to
+  // `AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary`. The
+  // exception is `ax::mojom::TextBoundary::kWebPage`, where this behavior won't
+  // make sense. This behavior is based on current platform needs and might be
+  // relaxed if necessary in the future.
   //
-  // Please note that |expand_behavior| should have no effect for
-  // ax::mojom::TextBoundary::kObject and ax::mojom::TextBoundary::kWebPage
+  // Observe that `expand_behavior` has an effect only when this position is
+  // between text units, e.g. between words, lines, paragraphs, etc. Also,
+  // please note that `expand_behavior` should have no effect for
+  // `ax::mojom::TextBoundary::kObject` and `ax::mojom::TextBoundary::kWebPage`
   // because the range should be the same regardless if we first move left or
   // right.
   AXRangeType ExpandToEnclosingTextBoundary(
       ax::mojom::TextBoundary boundary,
       AXRangeExpandBehavior expand_behavior) const {
-    AXBoundaryBehavior boundary_behavior =
-        AXBoundaryBehavior::StopAtAnchorBoundary;
-    if (boundary == ax::mojom::TextBoundary::kWebPage)
-      boundary_behavior = AXBoundaryBehavior::CrossBoundary;
+    AXBoundaryBehavior left_boundary_behavior =
+        AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary;
+    AXBoundaryBehavior right_boundary_behavior =
+        AXBoundaryBehavior::kStopAtAnchorBoundary;
+    if (boundary == ax::mojom::TextBoundary::kWebPage) {
+      left_boundary_behavior = AXBoundaryBehavior::kCrossBoundary;
+      right_boundary_behavior = AXBoundaryBehavior::kCrossBoundary;
+    }
 
     switch (expand_behavior) {
       case AXRangeExpandBehavior::kLeftFirst: {
         AXPositionInstance left_position = CreatePositionAtTextBoundary(
-            boundary, ax::mojom::MoveDirection::kBackward, boundary_behavior);
+            boundary, ax::mojom::MoveDirection::kBackward,
+            left_boundary_behavior);
         AXPositionInstance right_position =
             left_position->CreatePositionAtTextBoundary(
                 boundary, ax::mojom::MoveDirection::kForward,
-                boundary_behavior);
+                right_boundary_behavior);
         return AXRangeType(std::move(left_position), std::move(right_position));
       }
       case AXRangeExpandBehavior::kRightFirst: {
         AXPositionInstance right_position = CreatePositionAtTextBoundary(
-            boundary, ax::mojom::MoveDirection::kForward, boundary_behavior);
+            boundary, ax::mojom::MoveDirection::kForward,
+            left_boundary_behavior);
         AXPositionInstance left_position =
             right_position->CreatePositionAtTextBoundary(
                 boundary, ax::mojom::MoveDirection::kBackward,
-                boundary_behavior);
+                right_boundary_behavior);
         return AXRangeType(std::move(left_position), std::move(right_position));
       }
     }
@@ -1898,19 +2006,55 @@
         break;
 
       case ax::mojom::TextBoundary::kSentenceEnd:
-        NOTREACHED() << "Sentence boundaries are not yet supported.";
-        return CreateNullPosition();
+        switch (direction) {
+          case ax::mojom::MoveDirection::kNone:
+            NOTREACHED();
+            break;
+          case ax::mojom::MoveDirection::kBackward:
+            resulting_position =
+                CreatePreviousSentenceEndPosition(boundary_behavior);
+            break;
+          case ax::mojom::MoveDirection::kForward:
+            resulting_position =
+                CreateNextSentenceEndPosition(boundary_behavior);
+            break;
+        }
+        break;
 
       case ax::mojom::TextBoundary::kSentenceStart:
-        NOTREACHED() << "Sentence boundaries are not yet supported.";
-        return CreateNullPosition();
+        switch (direction) {
+          case ax::mojom::MoveDirection::kNone:
+            NOTREACHED();
+            break;
+          case ax::mojom::MoveDirection::kBackward:
+            resulting_position =
+                CreatePreviousSentenceStartPosition(boundary_behavior);
+            break;
+          case ax::mojom::MoveDirection::kForward:
+            resulting_position =
+                CreateNextSentenceStartPosition(boundary_behavior);
+            break;
+        }
+        break;
 
       case ax::mojom::TextBoundary::kSentenceStartOrEnd:
-        NOTREACHED() << "Sentence boundaries are not yet supported.";
-        return CreateNullPosition();
+        switch (direction) {
+          case ax::mojom::MoveDirection::kNone:
+            NOTREACHED();
+            break;
+          case ax::mojom::MoveDirection::kBackward:
+            resulting_position =
+                CreatePreviousSentenceStartPosition(boundary_behavior);
+            break;
+          case ax::mojom::MoveDirection::kForward:
+            resulting_position =
+                CreateNextSentenceEndPosition(boundary_behavior);
+            break;
+        }
+        break;
 
       case ax::mojom::TextBoundary::kWebPage:
-        DCHECK_EQ(boundary_behavior, AXBoundaryBehavior::CrossBoundary)
+        DCHECK_EQ(boundary_behavior, AXBoundaryBehavior::kCrossBoundary)
             << "We can't reach the start of the whole contents if we are "
                "disallowed from crossing boundaries.";
         switch (direction) {
@@ -2499,17 +2643,18 @@
   // See also http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries
   AXPositionInstance CreateNextCharacterPosition(
       AXBoundaryBehavior boundary_behavior) const {
-    if (boundary_behavior == AXBoundaryBehavior::StopAtAnchorBoundary &&
+    if ((boundary_behavior == AXBoundaryBehavior::kStopAtAnchorBoundary ||
+         boundary_behavior ==
+             AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary) &&
         AtEndOfAnchor()) {
       return Clone();
     }
 
     AXPositionInstance text_position = AsLeafTextPositionBeforeCharacter();
     if (text_position->IsNullPosition()) {
-      if (boundary_behavior == AXBoundaryBehavior::StopIfAlreadyAtBoundary ||
-          boundary_behavior == AXBoundaryBehavior::StopAtLastAnchorBoundary) {
+      if (boundary_behavior != AXBoundaryBehavior::kCrossBoundary)
         text_position = Clone();
-      }
+
       return text_position;
     }
 
@@ -2525,7 +2670,8 @@
     // positions that have the same affinity, since
     // `AsLeafTextPositionBeforeCharacter` resets the affinity to downstream,
     // while the original affinity might have been upstream.
-    if (boundary_behavior == AXBoundaryBehavior::StopIfAlreadyAtBoundary &&
+    if (boundary_behavior ==
+            AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary &&
         (AtEndOfAnchor() || *text_position == *CloneWithDownstreamAffinity())) {
       return Clone();
     }
@@ -2551,9 +2697,9 @@
     if (GetAnchor() == common_anchor) {
       text_position = text_position->CreateAncestorPosition(
           common_anchor, ax::mojom::MoveDirection::kForward);
-    } else if (boundary_behavior == AXBoundaryBehavior::StopAtAnchorBoundary) {
+    } else if (boundary_behavior == AXBoundaryBehavior::kStopAtAnchorBoundary) {
       // If the next character position crosses the current anchor boundary
-      // with StopAtAnchorBoundary, snap to the end of the current anchor.
+      // with kStopAtAnchorBoundary, snap to the end of the current anchor.
       return CreatePositionAtEndOfAnchor();
     }
 
@@ -2575,17 +2721,18 @@
   // grapheme cluster.
   AXPositionInstance CreatePreviousCharacterPosition(
       AXBoundaryBehavior boundary_behavior) const {
-    if (boundary_behavior == AXBoundaryBehavior::StopAtAnchorBoundary &&
+    if ((boundary_behavior == AXBoundaryBehavior::kStopAtAnchorBoundary ||
+         boundary_behavior ==
+             AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary) &&
         AtStartOfAnchor()) {
       return Clone();
     }
 
     AXPositionInstance text_position = AsLeafTextPositionAfterCharacter();
     if (text_position->IsNullPosition()) {
-      if (boundary_behavior == AXBoundaryBehavior::StopIfAlreadyAtBoundary ||
-          boundary_behavior == AXBoundaryBehavior::StopAtLastAnchorBoundary) {
+      if (boundary_behavior != AXBoundaryBehavior::kCrossBoundary)
         text_position = Clone();
-      }
+
       return text_position;
     }
 
@@ -2600,7 +2747,8 @@
     // our current anchor. We also need to ignore any differences that might be
     // due to the affinity, because that should not be a determining factor as
     // to whether we would stop if we are already at boundary or not.
-    if (boundary_behavior == AXBoundaryBehavior::StopIfAlreadyAtBoundary &&
+    if (boundary_behavior ==
+            AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary &&
         (AtStartOfAnchor() || *text_position == *CloneWithUpstreamAffinity() ||
          *text_position == *CloneWithDownstreamAffinity())) {
       return Clone();
@@ -2625,7 +2773,7 @@
     if (GetAnchor() == common_anchor) {
       text_position = text_position->CreateAncestorPosition(
           common_anchor, ax::mojom::MoveDirection::kBackward);
-    } else if (boundary_behavior == AXBoundaryBehavior::StopAtAnchorBoundary) {
+    } else if (boundary_behavior == AXBoundaryBehavior::kStopAtAnchorBoundary) {
       // If the previous character position crosses the current anchor boundary
       // with StopAtAnchorBoundary, snap to the start of the current anchor.
       return CreatePositionAtStartOfAnchor();
@@ -2839,18 +2987,30 @@
       BoundaryConditionPredicate at_end_condition,
       BoundaryTextOffsetsFunc get_start_offsets =
           BoundaryTextOffsetsFunc()) const {
-    AXPositionInstance text_position = AsLeafTextPosition();
+    AXPositionInstance text_position;
+    if (!AtEndOfAnchor()) {
+      // We could get a leaf text position at the end of its anchor, where
+      // boundary start offsets would surely not be present. In such cases, we
+      // need to normalize to the start of the next leaf anchor. We avoid making
+      // this change when we are at the end of our anchor because this could
+      // effectively shift the position forward.
+      text_position = AsLeafTextPositionBeforeCharacter();
+    } else {
+      text_position = AsLeafTextPosition();
+    }
+
     if (text_position->IsNullPosition())
       return text_position;
 
-    if (boundary_behavior != AXBoundaryBehavior::StopIfAlreadyAtBoundary) {
+    if (boundary_behavior !=
+        AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary) {
       text_position =
           text_position->CreateAdjacentLeafTextPosition(move_direction);
       if (text_position->IsNullPosition()) {
         // There is no adjacent position to move to; in such case, CrossBoundary
         // behavior shall return a null position, while any other behavior shall
         // fallback to return the initial position.
-        if (boundary_behavior == AXBoundaryBehavior::CrossBoundary)
+        if (boundary_behavior == AXBoundaryBehavior::kCrossBoundary)
           return text_position;
         return Clone();
       }
@@ -2883,7 +3043,10 @@
         }
 
         if (next_position->IsNullPosition()) {
-          if (boundary_behavior == AXBoundaryBehavior::StopAtAnchorBoundary) {
+          if (boundary_behavior == AXBoundaryBehavior::kStopAtAnchorBoundary ||
+              boundary_behavior ==
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary) {
             switch (move_direction) {
               case ax::mojom::MoveDirection::kNone:
                 NOTREACHED();
@@ -2898,7 +3061,7 @@
           }
 
           if (boundary_behavior ==
-              AXBoundaryBehavior::StopAtLastAnchorBoundary) {
+              AXBoundaryBehavior::kStopAtLastAnchorBoundary) {
             // We can't simply return the following position; break and after
             // this loop we'll try to do some adjustments to text_position.
             switch (move_direction) {
@@ -2934,7 +3097,10 @@
     if (GetAnchor() == common_anchor) {
       text_position =
           text_position->CreateAncestorPosition(common_anchor, move_direction);
-    } else if (boundary_behavior == AXBoundaryBehavior::StopAtAnchorBoundary) {
+    } else if (boundary_behavior == AXBoundaryBehavior::kStopAtAnchorBoundary ||
+               boundary_behavior ==
+                   AXBoundaryBehavior::
+                       kStopAtAnchorBoundaryOrIfAlreadyAtBoundary) {
       switch (move_direction) {
         case ax::mojom::MoveDirection::kNone:
           NOTREACHED();
@@ -2955,14 +3121,13 @@
       text_position = text_position->AsTreePosition();
     AXPositionInstance unignored_position = text_position->AsUnignoredPosition(
         AXPositionAdjustmentBehavior::kMoveForward);
-    // If there are no unignored positions in |move_direction| then
-    // `text_position` is anchored in ignored content at the end of the whole
-    // content. For StopAtLastAnchorBoundary, try to adjust in the opposite
-    // direction to return a position within the whole content just before
-    // crossing into the ignored content. This will be the last unignored anchor
-    // boundary.
+    // If there are no unignored positions then `text_position` is anchored in
+    // ignored content at the end of the whole content. For
+    // `kStopAtLastAnchorBoundary`, try to adjust in the opposite direction to
+    // return a position within the whole content just before crossing into the
+    // ignored content. This will be the last unignored anchor boundary.
     if (unignored_position->IsNullPosition() &&
-        boundary_behavior == AXBoundaryBehavior::StopAtLastAnchorBoundary) {
+        boundary_behavior == AXBoundaryBehavior::kStopAtLastAnchorBoundary) {
       unignored_position = text_position->AsUnignoredPosition(
           AXPositionAdjustmentBehavior::kMoveBackward);
     }
@@ -2976,18 +3141,30 @@
       BoundaryConditionPredicate at_end_condition,
       BoundaryTextOffsetsFunc get_end_offsets =
           BoundaryTextOffsetsFunc()) const {
-    AXPositionInstance text_position = AsLeafTextPosition();
+    AXPositionInstance text_position;
+    if (!AtStartOfAnchor()) {
+      // We could get a leaf text position at the start of its anchor, where
+      // boundary end offsets would surely not be present. In such cases, we
+      // need to normalize to the end of the previous leaf anchor. We avoid
+      // making this change when we are at the start of our anchor because this
+      // could effectively shift the position backward.
+      text_position = AsLeafTextPositionAfterCharacter();
+    } else {
+      text_position = AsLeafTextPosition();
+    }
+
     if (text_position->IsNullPosition())
       return text_position;
 
-    if (boundary_behavior != AXBoundaryBehavior::StopIfAlreadyAtBoundary) {
+    if (boundary_behavior !=
+        AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary) {
       text_position =
           text_position->CreateAdjacentLeafTextPosition(move_direction);
       if (text_position->IsNullPosition()) {
         // There is no adjacent position to move to; in such case, CrossBoundary
         // behavior shall return a null position, while any other behavior shall
         // fallback to return the initial position.
-        if (boundary_behavior == AXBoundaryBehavior::CrossBoundary)
+        if (boundary_behavior == AXBoundaryBehavior::kCrossBoundary)
           return text_position;
         return Clone();
       }
@@ -3023,7 +3200,10 @@
         }
 
         if (next_position->IsNullPosition()) {
-          if (boundary_behavior == AXBoundaryBehavior::StopAtAnchorBoundary) {
+          if (boundary_behavior == AXBoundaryBehavior::kStopAtAnchorBoundary ||
+              boundary_behavior ==
+                  AXBoundaryBehavior::
+                      kStopAtAnchorBoundaryOrIfAlreadyAtBoundary) {
             switch (move_direction) {
               case ax::mojom::MoveDirection::kNone:
                 NOTREACHED();
@@ -3038,7 +3218,7 @@
           }
 
           if (boundary_behavior ==
-              AXBoundaryBehavior::StopAtLastAnchorBoundary) {
+              AXBoundaryBehavior::kStopAtLastAnchorBoundary) {
             // We can't simply return the following position; break and after
             // this loop we'll try to do some adjustments to text_position.
             switch (move_direction) {
@@ -3074,7 +3254,10 @@
     if (GetAnchor() == common_anchor) {
       text_position =
           text_position->CreateAncestorPosition(common_anchor, move_direction);
-    } else if (boundary_behavior == AXBoundaryBehavior::StopAtAnchorBoundary) {
+    } else if (boundary_behavior == AXBoundaryBehavior::kStopAtAnchorBoundary ||
+               boundary_behavior ==
+                   AXBoundaryBehavior::
+                       kStopAtAnchorBoundaryOrIfAlreadyAtBoundary) {
       switch (move_direction) {
         case ax::mojom::MoveDirection::kNone:
           NOTREACHED();
@@ -3101,7 +3284,7 @@
           text_position->CloneWithDownstreamAffinity();
       if (downstream_position->AtStartOfAnchor() ||
           downstream_position->AtEndOfAnchor() ||
-          !at_start_condition.Run(downstream_position)) {
+          !downstream_position->AtStartOfLine()) {
         text_position->affinity_ = ax::mojom::TextAffinity::kDownstream;
       }
     }
@@ -3110,21 +3293,54 @@
       text_position = text_position->AsTreePosition();
     AXPositionInstance unignored_position = text_position->AsUnignoredPosition(
         AXPositionAdjustmentBehavior::kMoveBackward);
-    // If there are no unignored positions in |move_direction| then
-    // |text_position| is anchored in ignored content at the start or end
-    // of the whole content.
-    // For StopAtLastAnchorBoundary, try to adjust in the opposite direction
-    // to return a position within the whole content just before crossing into
-    // the ignored content. This will be the last unignored anchor boundary.
+    // If there are no unignored positions then `text_position` is anchored in
+    // ignored content at the start or end of the whole content. For
+    // `kStopAtLastAnchorBoundary`, try to adjust in the opposite direction to
+    // return a position within the whole content just before crossing into the
+    // ignored content. This will be the last unignored anchor boundary.
     if (unignored_position->IsNullPosition() &&
-        boundary_behavior == AXBoundaryBehavior::StopAtLastAnchorBoundary) {
+        boundary_behavior == AXBoundaryBehavior::kStopAtLastAnchorBoundary) {
       unignored_position = text_position->AsUnignoredPosition(
           AXPositionAdjustmentBehavior::kMoveForward);
     }
     return unignored_position;
   }
 
-  // TODO(nektar): Add sentence navigation methods.
+  AXPositionInstance CreateNextSentenceStartPosition(
+      AXBoundaryBehavior boundary_behavior) const {
+    return CreateBoundaryStartPosition(
+        boundary_behavior, ax::mojom::MoveDirection::kForward,
+        base::BindRepeating(&AtStartOfSentencePredicate),
+        base::BindRepeating(&AtEndOfSentencePredicate),
+        base::BindRepeating(&GetSentenceStartOffsetsFunc));
+  }
+
+  AXPositionInstance CreatePreviousSentenceStartPosition(
+      AXBoundaryBehavior boundary_behavior) const {
+    return CreateBoundaryStartPosition(
+        boundary_behavior, ax::mojom::MoveDirection::kBackward,
+        base::BindRepeating(&AtStartOfSentencePredicate),
+        base::BindRepeating(&AtEndOfSentencePredicate),
+        base::BindRepeating(&GetSentenceStartOffsetsFunc));
+  }
+
+  AXPositionInstance CreateNextSentenceEndPosition(
+      AXBoundaryBehavior boundary_behavior) const {
+    return CreateBoundaryEndPosition(
+        boundary_behavior, ax::mojom::MoveDirection::kForward,
+        base::BindRepeating(&AtStartOfSentencePredicate),
+        base::BindRepeating(&AtEndOfSentencePredicate),
+        base::BindRepeating(&GetSentenceEndOffsetsFunc));
+  }
+
+  AXPositionInstance CreatePreviousSentenceEndPosition(
+      AXBoundaryBehavior boundary_behavior) const {
+    return CreateBoundaryEndPosition(
+        boundary_behavior, ax::mojom::MoveDirection::kBackward,
+        base::BindRepeating(&AtStartOfSentencePredicate),
+        base::BindRepeating(&AtEndOfSentencePredicate),
+        base::BindRepeating(&GetSentenceEndOffsetsFunc));
+  }
 
   // Uses depth-first pre-order traversal.
   AXPositionInstance CreateNextAnchorPosition() const {
@@ -3649,13 +3865,13 @@
     if (GetAnchor()->IsCollapsedMenuListPopUpButton())
       return true;
 
-    // All anchor nodes that are empty leaf nodes or have only ignored
-    // descendants should be treated as empty objects. Empty leaf nodes do not
-    // expose their descendants to platform accessibility APIs, but may have
-    // unignored descendants. They do not have any text content, however, hence
-    // they are still empty from our perspective. For example, an empty text
-    // field may still have an unignored generic container inside it.
-    if (AnchorUnignoredChildCount() && !GetAnchor()->IsEmptyLeaf())
+    // All anchor nodes that are empty leaf nodes should be treated as empty
+    // objects. Empty leaf nodes do not expose their descendants to platform
+    // accessibility APIs, but may have unignored descendants. They do not have
+    // any inner text, hence they are empty from our perspective. For example,
+    // an empty text field may still have an unignored generic container inside
+    // it.
+    if (!GetAnchor()->IsEmptyLeaf())
       return false;
 
     // <embed> and <object> elements with non empty children should not be
@@ -4092,34 +4308,55 @@
     return current_anchor_text_attributes;
   }
 
-  std::vector<int32_t> GetWordStartOffsets() const {
-    if (IsNullPosition())
-      return std::vector<int32_t>();
+  const std::vector<int32_t>& GetWordStartOffsets() const {
+    if (IsNullPosition()) {
+      static const base::NoDestructor<std::vector<int32_t>> empty_word_starts;
+      return *empty_word_starts;
+    }
     DCHECK(GetAnchor());
-    // Embedded object replacement characters are not represented in the
-    // "kWordStarts" attribute so we need to special case them here.
-    if (IsEmptyObjectReplacedByCharacter())
-      return {0};
+
+    // An embedded object replacement character is exposed in a node's text
+    // representation when a control, such as a text field, is empty. Since the
+    // control has no text, no word start offsets are present in the
+    // `ax::mojom::IntListAttribute::kWordStarts` attribute, so we need to
+    // special case them here.
+    if (IsEmptyObjectReplacedByCharacter()) {
+      // Using braces ensures that the vector will contain the given value, and
+      // not create a vector of size 0.
+      static const base::NoDestructor<std::vector<int32_t>>
+          embedded_word_starts{{0}};
+      return *embedded_word_starts;
+    }
 
     return GetAnchor()->GetIntListAttribute(
         ax::mojom::IntListAttribute::kWordStarts);
   }
 
-  std::vector<int32_t> GetWordEndOffsets() const {
-    if (IsNullPosition())
-      return std::vector<int32_t>();
+  const std::vector<int32_t>& GetWordEndOffsets() const {
+    if (IsNullPosition()) {
+      static const base::NoDestructor<std::vector<int32_t>> empty_word_ends;
+      return *empty_word_ends;
+    }
     DCHECK(GetAnchor());
 
-    // Embedded object replacement characters are not represented in the
-    // "kWordEnds" attribute so we need to special case them here.
+    // An embedded object replacement character is exposed in a node's text
+    // representation when a control, such as a text field, is empty. Since the
+    // control has no text, no word end offsets are present in the
+    // `ax::mojom::IntListAttribute::kWordEnds` attribute, so we need to special
+    // case them here.
     //
     // Since the whole text exposed inside of an embedded object is of
     // length 1 (the embedded object replacement character), the word end offset
-    // is positioned at 1. Because we want to treat the embedded object
-    // replacement characters as ordinary characters, it wouldn't be consistent
-    // to assume they have no length and return 0 instead of 1.
-    if (IsEmptyObjectReplacedByCharacter())
-      return {1};
+    // is positioned at 1. Because we want to treat embedded object replacement
+    // characters as ordinary characters, it wouldn't be consistent to assume
+    // they have no length and return 0 instead of 1.
+    if (IsEmptyObjectReplacedByCharacter()) {
+      // Using braces ensures that the vector will contain the given value, and
+      // not create a vector of size 1.
+      static const base::NoDestructor<std::vector<int32_t>> embedded_word_ends{
+          {1}};
+      return *embedded_word_ends;
+    }
 
     return GetAnchor()->GetIntListAttribute(
         ax::mojom::IntListAttribute::kWordEnds);
@@ -4441,6 +4678,22 @@
     return position->AtEndOfLine();
   }
 
+  static bool AtStartOfSentencePredicate(const AXPositionInstance& position) {
+    // Sentence boundaries should be at specific text offsets that are "visible"
+    // to assistive software, hence not ignored. Ignored nodes are often used
+    // for additional layout information, such as line and paragraph boundaries.
+    // Their text is not currently processed.
+    return !position->IsIgnored() && position->AtStartOfSentence();
+  }
+
+  static bool AtEndOfSentencePredicate(const AXPositionInstance& position) {
+    // Sentence boundaries should be at specific text offsets that are "visible"
+    // to assistive software, hence not ignored. Ignored nodes are often used
+    // for additional layout information, such as line and paragraph boundaries.
+    // Their text is not currently processed.
+    return !position->IsIgnored() && position->AtEndOfSentence();
+  }
+
   static bool AtStartOfFormatPredicate(const AXPositionInstance& position) {
     return position->AtStartOfFormat();
   }
@@ -4666,12 +4919,35 @@
     return false;
   }
 
-  static std::vector<int32_t> GetWordStartOffsetsFunc(
+  static const std::vector<int32_t>& GetSentenceStartOffsetsFunc(
+      const AXPositionInstance& position) {
+    if (position->IsNullPosition()) {
+      static const base::NoDestructor<std::vector<int32_t>>
+          empty_sentence_starts;
+      return *empty_sentence_starts;
+    }
+    DCHECK(position->GetAnchor());
+    return position->GetAnchor()->GetIntListAttribute(
+        ax::mojom::IntListAttribute::kSentenceStarts);
+  }
+
+  static const std::vector<int32_t>& GetSentenceEndOffsetsFunc(
+      const AXPositionInstance& position) {
+    if (position->IsNullPosition()) {
+      static const base::NoDestructor<std::vector<int32_t>> empty_sentence_ends;
+      return *empty_sentence_ends;
+    }
+    DCHECK(position->GetAnchor());
+    return position->GetAnchor()->GetIntListAttribute(
+        ax::mojom::IntListAttribute::kSentenceEnds);
+  }
+
+  static const std::vector<int32_t>& GetWordStartOffsetsFunc(
       const AXPositionInstance& position) {
     return position->GetWordStartOffsets();
   }
 
-  static std::vector<int32_t> GetWordEndOffsetsFunc(
+  static const std::vector<int32_t>& GetWordEndOffsetsFunc(
       const AXPositionInstance& position) {
     return position->GetWordEndOffsets();
   }
@@ -4757,7 +5033,7 @@
       return Clone();
 
     AXPositionInstance text_position = AsTextPosition();
-    const std::vector<int32_t> boundary_offsets =
+    const std::vector<int32_t>& boundary_offsets =
         get_offsets.Run(text_position);
     if (boundary_offsets.empty())
       return text_position;
@@ -4812,7 +5088,7 @@
       return Clone();
 
     AXPositionInstance text_position = AsTextPosition();
-    const std::vector<int32_t> boundary_offsets =
+    const std::vector<int32_t>& boundary_offsets =
         get_offsets.Run(text_position);
     switch (move_direction) {
       case ax::mojom::MoveDirection::kNone:
@@ -4845,15 +5121,16 @@
   //
   // This method is the first step for CreateBoundary[Start|End]Position to
   // guarantee that the resulting position when using a boundary behavior other
-  // than `AXBoundaryBehavior::StopIfAlreadyAtBoundary` is not equivalent to the
-  // initial position. That's why ignored positions are also skipped. Otherwise,
-  // if a boundary is present on an ignored position, the search for the next or
-  // previous boundary would stop prematurely. Note that if there are multiple
-  // adjacent ignored positions and all of them create a boundary, we'll skip
-  // them all on purpose. For example, adjacent ignored paragraph boundaries
-  // could be created by using multiple aria-hidden divs next to one another.
-  // These should not contribute more than one paragraph boundary to the tree's
-  // text representation, otherwise this will create user confusion.
+  // than `AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary` is
+  // not equivalent to the initial position. That's why ignored positions are
+  // also skipped. Otherwise, if a boundary is present on an ignored position,
+  // the search for the next or previous boundary would stop prematurely. Note
+  // that if there are multiple adjacent ignored positions and all of them
+  // create a boundary, we'll skip them all on purpose. For example, adjacent
+  // ignored paragraph boundaries could be created by using multiple aria-hidden
+  // divs next to one another. These should not contribute more than one
+  // paragraph boundary to the tree's text representation, otherwise this will
+  // create user confusion.
   //
   // Note that using the `CompareTo` method with text positions does not take
   // into account position affinity or the order of their anchors in the tree:
diff --git a/ui/accessibility/ax_relative_bounds.cc b/ui/accessibility/ax_relative_bounds.cc
index a6ee80c..34651cf 100644
--- a/ui/accessibility/ax_relative_bounds.cc
+++ b/ui/accessibility/ax_relative_bounds.cc
@@ -4,6 +4,7 @@
 
 #include "ui/accessibility/ax_relative_bounds.h"
 
+#include "base/memory/values_equivalent.h"
 #include "base/strings/string_number_conversions.h"
 #include "ui/accessibility/ax_enum_util.h"
 #include "ui/gfx/geometry/transform.h"
@@ -41,11 +42,7 @@
     return false;
   if (bounds != other.bounds)
     return false;
-  if (!transform && !other.transform)
-    return true;
-  if ((transform && !other.transform) || (!transform && other.transform))
-    return false;
-  return *transform == *other.transform;
+  return base::ValuesEquivalent(transform, other.transform);
 }
 
 bool AXRelativeBounds::operator!=(const AXRelativeBounds& other) const {
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc b/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
index 909dcac..e2c5a8e3 100644
--- a/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
@@ -1300,8 +1300,7 @@
   AXNodeData root;
   root.id = 1;
   root.role = ax::mojom::Role::kTextField;
-  root.AddStringAttribute(ax::mojom::StringAttribute::kValue,
-                          "A decently long string \xE2\x98\xBA with an emoji.");
+  root.SetValue("A decently long string \xE2\x98\xBA with an emoji.");
   Init(root);
 
   AtkObject* root_obj(GetRootAtkObject());
@@ -1519,7 +1518,8 @@
 }
 
 #if ATK_CHECK_VERSION(2, 10, 0)
-TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkTextParagraphGranularity) {
+TEST_F(AXPlatformNodeAuraLinuxTest, DISABLED_TestAtkTextParagraphGranularity) {
+  // TODO(nektar): Enable navigating by paragraphs in plain text.
   AXNodeData root;
   root.id = 1;
   root.role = ax::mojom::Role::kTextField;
diff --git a/ui/accessibility/platform/ax_platform_node_base.cc b/ui/accessibility/platform/ax_platform_node_base.cc
index 08eccae..16c04eb 100644
--- a/ui/accessibility/platform/ax_platform_node_base.cc
+++ b/ui/accessibility/platform/ax_platform_node_base.cc
@@ -2012,17 +2012,27 @@
     ax::mojom::MoveDirection direction,
     ax::mojom::TextAffinity affinity) const {
   DCHECK_NE(boundary, ax::mojom::TextBoundary::kNone);
-  if (boundary != ax::mojom::TextBoundary::kSentenceStart) {
-    absl::optional<int> boundary_offset =
-        GetDelegate()->FindTextBoundary(boundary, offset, direction, affinity);
-    if (boundary_offset.has_value())
-      return *boundary_offset;
+  if (!delegate_)
+    return offset;  // Unable to compute text boundary.
+
+  const AXPosition position = delegate_->CreateTextPositionAt(offset, affinity);
+  // On Windows and Linux ATK, searching for a text boundary should always stop
+  // at the boundary of the current object.
+  auto boundary_behavior = AXBoundaryBehavior::kStopAtAnchorBoundary;
+  // On Windows and Linux ATK, it is standard text navigation behavior to stop
+  // if we are searching in the backwards direction and the current position is
+  // already at the required text boundary.
+  if (direction == ax::mojom::MoveDirection::kBackward) {
+    boundary_behavior =
+        AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary;
   }
 
-  std::vector<int32_t> unused_line_start_offsets;
-  return static_cast<int>(
-      FindAccessibleTextBoundary(GetHypertext(), unused_line_start_offsets,
-                                 boundary, offset, direction, affinity));
+  const AXPosition boundary_position = position->CreatePositionAtTextBoundary(
+      boundary, direction, boundary_behavior);
+  if (boundary_position->IsNullPosition())
+    return -1;
+  DCHECK_GE(boundary_position->text_offset(), 0);
+  return boundary_position->text_offset();
 }
 
 AXPlatformNodeBase* AXPlatformNodeBase::NearestLeafToPoint(
diff --git a/ui/accessibility/platform/ax_platform_node_base.h b/ui/accessibility/platform/ax_platform_node_base.h
index a536a2b..d40d89d 100644
--- a/ui/accessibility/platform/ax_platform_node_base.h
+++ b/ui/accessibility/platform/ax_platform_node_base.h
@@ -15,6 +15,7 @@
 #include "build/build_config.h"
 #include "ui/accessibility/ax_enums.mojom-forward.h"
 #include "ui/accessibility/ax_node.h"
+#include "ui/accessibility/ax_node_position.h"
 #include "ui/accessibility/ax_text_attributes.h"
 #include "ui/accessibility/platform/ax_platform_node.h"
 #include "ui/accessibility/platform/ax_platform_node_delegate.h"
@@ -60,6 +61,8 @@
 
 class AX_EXPORT AXPlatformNodeBase : public AXPlatformNode {
  public:
+  using AXPosition = AXNodePosition::AXPositionInstance;
+
   ~AXPlatformNodeBase() override;
   AXPlatformNodeBase(const AXPlatformNodeBase&) = delete;
   AXPlatformNodeBase& operator=(const AXPlatformNodeBase&) = delete;
@@ -349,6 +352,7 @@
   // This method finds text boundaries in the text used for platform text APIs.
   // Implementations may use side-channel data such as line or word indices to
   // produce appropriate results.
+  // Returns -1 if the requested boundary has not been found.
   virtual int FindTextBoundary(ax::mojom::TextBoundary boundary,
                                int offset,
                                ax::mojom::MoveDirection direction,
diff --git a/ui/accessibility/platform/ax_platform_node_delegate.h b/ui/accessibility/platform/ax_platform_node_delegate.h
index dbbf9a6..758f2a6 100644
--- a/ui/accessibility/platform/ax_platform_node_delegate.h
+++ b/ui/accessibility/platform/ax_platform_node_delegate.h
@@ -484,21 +484,6 @@
 
   virtual const AXUniqueId& GetUniqueId() const = 0;
 
-  // Finds the previous or next offset from the provided offset, that matches
-  // the provided boundary type.
-  //
-  // This method finds text boundaries in the text used for platform text APIs.
-  // Implementations may use side-channel data such as line or word indices to
-  // produce appropriate results. It may optionally return no value, indicating
-  // that the delegate does not have all the information required to calculate
-  // this value and it is the responsibility of the AXPlatformNode itself to
-  // to calculate it.
-  virtual absl::optional<int> FindTextBoundary(
-      ax::mojom::TextBoundary boundary,
-      int offset,
-      ax::mojom::MoveDirection direction,
-      ax::mojom::TextAffinity affinity) const = 0;
-
   // Return a vector of all the descendants of this delegate's node. This method
   // is only meaningful for Windows UIA.
   virtual const std::vector<gfx::NativeViewAccessible>
diff --git a/ui/accessibility/platform/ax_platform_node_delegate_base.cc b/ui/accessibility/platform/ax_platform_node_delegate_base.cc
index 5b901c90..8df112d 100644
--- a/ui/accessibility/platform/ax_platform_node_delegate_base.cc
+++ b/ui/accessibility/platform/ax_platform_node_delegate_base.cc
@@ -265,7 +265,6 @@
 AXNodePosition::AXPositionInstance AXPlatformNodeDelegateBase::CreatePositionAt(
     int offset,
     ax::mojom::TextAffinity affinity) const {
-  NOTIMPLEMENTED();
   return AXNodePosition::CreateNullPosition();
 }
 
@@ -273,7 +272,6 @@
 AXPlatformNodeDelegateBase::CreateTextPositionAt(
     int offset,
     ax::mojom::TextAffinity affinity) const {
-  NOTIMPLEMENTED();
   return AXNodePosition::CreateNullPosition();
 }
 
@@ -939,14 +937,6 @@
   return *dummy_unique_id;
 }
 
-absl::optional<int> AXPlatformNodeDelegateBase::FindTextBoundary(
-    ax::mojom::TextBoundary boundary,
-    int offset,
-    ax::mojom::MoveDirection direction,
-    ax::mojom::TextAffinity affinity) const {
-  return absl::nullopt;
-}
-
 const std::vector<gfx::NativeViewAccessible>
 AXPlatformNodeDelegateBase::GetUIADirectChildrenInRange(
     ui::AXPlatformNodeDelegate* start,
diff --git a/ui/accessibility/platform/ax_platform_node_delegate_base.h b/ui/accessibility/platform/ax_platform_node_delegate_base.h
index b1cdb3a0..617ac42f 100644
--- a/ui/accessibility/platform/ax_platform_node_delegate_base.h
+++ b/ui/accessibility/platform/ax_platform_node_delegate_base.h
@@ -269,12 +269,6 @@
 
   const AXUniqueId& GetUniqueId() const override;
 
-  absl::optional<int> FindTextBoundary(
-      ax::mojom::TextBoundary boundary,
-      int offset,
-      ax::mojom::MoveDirection direction,
-      ax::mojom::TextAffinity affinity) const override;
-
   const std::vector<gfx::NativeViewAccessible> GetUIADirectChildrenInRange(
       ui::AXPlatformNodeDelegate* start,
       ui::AXPlatformNodeDelegate* end) override;
diff --git a/ui/accessibility/platform/ax_platform_node_textprovider_win.cc b/ui/accessibility/platform/ax_platform_node_textprovider_win.cc
index 5d7e546..b7fd12d 100644
--- a/ui/accessibility/platform/ax_platform_node_textprovider_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_textprovider_win.cc
@@ -146,7 +146,7 @@
   auto current_line_start = start->Clone();
   while (!current_line_start->IsNullPosition() && *current_line_start < *end) {
     auto current_line_end = current_line_start->CreateNextLineEndPosition(
-        AXBoundaryBehavior::CrossBoundary);
+        AXBoundaryBehavior::kCrossBoundary);
     if (current_line_end->IsNullPosition() || *current_line_end > *end)
       current_line_end = end->Clone();
 
@@ -163,7 +163,7 @@
     }
 
     current_line_start = current_line_start->CreateNextLineStartPosition(
-        AXBoundaryBehavior::CrossBoundary);
+        AXBoundaryBehavior::kCrossBoundary);
   }
 
   base::win::ScopedSafearray scoped_visible_ranges(
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc
index 77c2bd17..dfa3cc1 100644
--- a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc
@@ -221,14 +221,14 @@
       // boundary, thus we only need to move the end position.
       AXPositionInstance end_backup = end()->Clone();
       SetEnd(start()->CreateNextCharacterPosition(
-          AXBoundaryBehavior::CrossBoundary));
+          AXBoundaryBehavior::kCrossBoundary));
 
       if (end()->IsNullPosition()) {
         // The previous could fail if the start is at the end of the last anchor
         // of the tree, try expanding to the previous character instead.
         AXPositionInstance start_backup = start()->Clone();
         SetStart(start()->CreatePreviousCharacterPosition(
-            AXBoundaryBehavior::CrossBoundary));
+            AXBoundaryBehavior::kCrossBoundary));
 
         if (start()->IsNullPosition()) {
           // Text representation is empty, undo everything and exit.
@@ -237,7 +237,7 @@
           return S_OK;
         }
         SetEnd(start()->CreateNextCharacterPosition(
-            AXBoundaryBehavior::CrossBoundary));
+            AXBoundaryBehavior::kCrossBoundary));
         DCHECK(!end()->IsNullPosition());
       }
 
@@ -250,39 +250,31 @@
     }
     case TextUnit_Format:
       SetStart(start()->CreatePreviousFormatStartPosition(
-          AXBoundaryBehavior::StopIfAlreadyAtBoundary));
+          AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary));
       SetEnd(start()->CreateNextFormatEndPosition(
-          AXBoundaryBehavior::StopIfAlreadyAtBoundary));
+          AXBoundaryBehavior::kStopAtLastAnchorBoundary));
       break;
     case TextUnit_Word: {
       AXPositionInstance start_backup = start()->Clone();
       SetStart(start()->CreatePreviousWordStartPosition(
-          AXBoundaryBehavior::StopIfAlreadyAtBoundary));
-      // Since we use AXBoundaryBehavior::StopIfAlreadyAtBoundary, the only case
-      // possible where CreatePreviousWordStartPosition can return a
-      // NullPosition is when it's called on a node before the first word
-      // boundary. This can happen when the document starts with nodes that have
-      // no word boundaries, like whitespaces and punctuation. When it happens,
-      // move the position back to the start of the document.
-      if (start()->IsNullPosition())
-        SetStart(start_backup->CreatePositionAtStartOfContent());
+          AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary));
 
       // Since start_ is already located at a word boundary, we need to cross it
       // in order to move to the next one. Because Windows ATs behave
       // undesirably when the start and end endpoints are not in the same anchor
       // (for character and word navigation), stop at anchor boundary.
       SetEnd(start()->CreateNextWordStartPosition(
-          AXBoundaryBehavior::StopAtAnchorBoundary));
+          AXBoundaryBehavior::kStopAtAnchorBoundary));
       break;
     }
     case TextUnit_Line:
       SetStart(start()->CreateBoundaryStartPosition(
-          AXBoundaryBehavior::StopIfAlreadyAtBoundary,
+          AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary,
           ax::mojom::MoveDirection::kBackward,
           base::BindRepeating(&AtStartOfLinePredicate),
           base::BindRepeating(&AtEndOfLinePredicate)));
       SetEnd(start()->CreateBoundaryEndPosition(
-          AXBoundaryBehavior::StopIfAlreadyAtBoundary,
+          AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary,
           ax::mojom::MoveDirection::kForward,
           base::BindRepeating(&AtStartOfLinePredicate),
           base::BindRepeating(&AtEndOfLinePredicate)));
@@ -290,9 +282,9 @@
     case TextUnit_Paragraph:
       SetStart(
           start()->CreatePreviousParagraphStartPositionSkippingEmptyParagraphs(
-              AXBoundaryBehavior::StopIfAlreadyAtBoundary));
+              AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary));
       SetEnd(start()->CreateNextParagraphStartPositionSkippingEmptyParagraphs(
-          AXBoundaryBehavior::StopAtLastAnchorBoundary));
+          AXBoundaryBehavior::kStopAtLastAnchorBoundary));
       break;
     case TextUnit_Page: {
       // Per UIA spec, if the document containing the current range doesn't
@@ -300,9 +292,10 @@
       const AXNode* common_anchor = start()->LowestCommonAnchor(*end());
       if (common_anchor->tree()->HasPaginationSupport()) {
         SetStart(start()->CreatePreviousPageStartPosition(
-            ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary));
+            AXBoundaryBehavior::kStopAtAnchorBoundaryOrIfAlreadyAtBoundary));
         SetEnd(start()->CreateNextPageEndPosition(
-            ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary));
+            ui::AXBoundaryBehavior::
+                kStopAtAnchorBoundaryOrIfAlreadyAtBoundary));
         break;
       }
     }
@@ -1240,13 +1233,14 @@
     do {
       AXPositionInstance next_endpoint = GetNextTextBoundaryPosition(
           current_endpoint, boundary_type,
-          AXBoundaryBehavior::StopAtLastAnchorBoundary, boundary_direction);
+          AXBoundaryBehavior::kStopAtLastAnchorBoundary, boundary_direction);
       DCHECK(next_endpoint->IsLeafTextPosition());
 
-      // Since AXBoundaryBehavior::StopAtLastAnchorBoundary forces the next text
-      // boundary position to be different than the input position, the only
-      // case where these are equal is when they're already located at the last
-      // anchor boundary. In such case, there is no next position to move to.
+      // Since AXBoundaryBehavior::kStopAtLastAnchorBoundary forces the next
+      // text boundary position to be different than the input position, the
+      // only case where these are equal is when they're already located at the
+      // last anchor boundary. In such case, there is no next position to move
+      // to.
       if (next_endpoint->GetAnchor() == current_endpoint->GetAnchor() &&
           *next_endpoint == *current_endpoint) {
         *units_moved = (count > 0) ? iteration : -iteration;
diff --git a/ui/accessibility/platform/ax_platform_node_unittest.cc b/ui/accessibility/platform/ax_platform_node_unittest.cc
index 86d30be..9d8c8f1 100644
--- a/ui/accessibility/platform/ax_platform_node_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_unittest.cc
@@ -39,36 +39,37 @@
     const ui::AXNodeData& node6 /* = ui::AXNodeData() */,
     const ui::AXNodeData& node7 /* = ui::AXNodeData() */,
     const ui::AXNodeData& node8 /* = ui::AXNodeData() */,
-    const ui::AXNodeData& node9 /* = ui::AXNodeData() */,
-    const ui::AXNodeData& node10 /* = ui::AXNodeData() */,
-    const ui::AXNodeData& node11 /* = ui::AXNodeData() */,
-    const ui::AXNodeData& node12 /* = ui::AXNodeData() */) {
-  static ui::AXNodeData empty_data;
-  int32_t no_id = empty_data.id;
+    const ui::AXNodeData& node9 /* = AXNodeData() */,
+    const ui::AXNodeData& node10 /* = AXNodeData() */,
+    const ui::AXNodeData& node11 /* = AXNodeData() */,
+    const ui::AXNodeData& node12 /* = AXNodeData() */) {
   AXTreeUpdate update;
   update.root_id = node1.id;
+  update.has_tree_data = true;
+  update.tree_data.tree_id = AXTreeID::CreateNewAXTreeID();
+  update.tree_data.title = "Dialog title";
   update.nodes.push_back(node1);
-  if (node2.id != no_id)
+  if (node2.id != kInvalidAXNodeID)
     update.nodes.push_back(node2);
-  if (node3.id != no_id)
+  if (node3.id != kInvalidAXNodeID)
     update.nodes.push_back(node3);
-  if (node4.id != no_id)
+  if (node4.id != kInvalidAXNodeID)
     update.nodes.push_back(node4);
-  if (node5.id != no_id)
+  if (node5.id != kInvalidAXNodeID)
     update.nodes.push_back(node5);
-  if (node6.id != no_id)
+  if (node6.id != kInvalidAXNodeID)
     update.nodes.push_back(node6);
-  if (node7.id != no_id)
+  if (node7.id != kInvalidAXNodeID)
     update.nodes.push_back(node7);
-  if (node8.id != no_id)
+  if (node8.id != kInvalidAXNodeID)
     update.nodes.push_back(node8);
-  if (node9.id != no_id)
+  if (node9.id != kInvalidAXNodeID)
     update.nodes.push_back(node9);
-  if (node10.id != no_id)
+  if (node10.id != kInvalidAXNodeID)
     update.nodes.push_back(node10);
-  if (node11.id != no_id)
+  if (node11.id != kInvalidAXNodeID)
     update.nodes.push_back(node11);
-  if (node12.id != no_id)
+  if (node12.id != kInvalidAXNodeID)
     update.nodes.push_back(node12);
   Init(update);
 }
diff --git a/ui/accessibility/platform/ax_platform_node_unittest.h b/ui/accessibility/platform/ax_platform_node_unittest.h
index 08e1c99..b006162b 100644
--- a/ui/accessibility/platform/ax_platform_node_unittest.h
+++ b/ui/accessibility/platform/ax_platform_node_unittest.h
@@ -29,18 +29,18 @@
   void Init(const AXTreeUpdate& initial_state);
 
   // Convenience functions to initialize directly from a few AXNodeData objects.
-  void Init(const ui::AXNodeData& node1,
-            const ui::AXNodeData& node2 = ui::AXNodeData(),
-            const ui::AXNodeData& node3 = ui::AXNodeData(),
-            const ui::AXNodeData& node4 = ui::AXNodeData(),
-            const ui::AXNodeData& node5 = ui::AXNodeData(),
-            const ui::AXNodeData& node6 = ui::AXNodeData(),
-            const ui::AXNodeData& node7 = ui::AXNodeData(),
-            const ui::AXNodeData& node8 = ui::AXNodeData(),
-            const ui::AXNodeData& node9 = ui::AXNodeData(),
-            const ui::AXNodeData& node10 = ui::AXNodeData(),
-            const ui::AXNodeData& node11 = ui::AXNodeData(),
-            const ui::AXNodeData& node12 = ui::AXNodeData());
+  void Init(const AXNodeData& node1,
+            const AXNodeData& node2 = AXNodeData(),
+            const AXNodeData& node3 = AXNodeData(),
+            const AXNodeData& node4 = AXNodeData(),
+            const AXNodeData& node5 = AXNodeData(),
+            const AXNodeData& node6 = AXNodeData(),
+            const AXNodeData& node7 = AXNodeData(),
+            const AXNodeData& node8 = AXNodeData(),
+            const AXNodeData& node9 = AXNodeData(),
+            const AXNodeData& node10 = AXNodeData(),
+            const AXNodeData& node11 = AXNodeData(),
+            const AXNodeData& node12 = AXNodeData());
 
   AXTreeUpdate BuildTextField();
   AXTreeUpdate BuildTextFieldWithSelectionRange(int32_t start, int32_t stop);
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index b595d177..bf2d893 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -3606,12 +3606,6 @@
   AXPlatformNode::NotifyAddAXModeFlags(kScreenReaderAndHTMLAccessibilityModes |
                                        AXMode::kInlineTextBoxes);
 
-  // https://accessibility.linuxfoundation.org/a11yspecs/ia2/docs/html/_accessible_text_8idl.html
-  // IA2_TEXT_BOUNDARY_SENTENCE is optional and we can let the screenreader
-  // handle it, the rest of the boundary types must be supported.
-  if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE)
-    return S_FALSE;
-
   HandleSpecialTextOffset(&offset);
   if (offset < 0)
     return E_INVALIDARG;
@@ -3634,7 +3628,6 @@
   }
 
   LONG start, end;
-
   switch (text_offset_type) {
     case TextOffsetType::kAtOffset: {
       end = FindBoundary(boundary_type, offset,
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager.css b/ui/file_manager/file_manager/foreground/css/file_manager.css
index 930eb27..be1fb8b 100644
--- a/ui/file_manager/file_manager/foreground/css/file_manager.css
+++ b/ui/file_manager/file_manager/foreground/css/file_manager.css
@@ -797,11 +797,9 @@
 }
 
 #cloud-import-details {
-  background-color: white;
-  border-radius: 2px;
-  box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 14%),
-              0 1px 10px 0 rgba(0, 0, 0, 12%),
-              0 2px 4px -1px rgba(0, 0, 0, 40%);
+  background-color: var(--cros-bg-color-elevation-3);
+  border-radius: 12px;
+  box-shadow: var(--cros-elevation-3-shadow);
   line-height: 1.5em;
   position: absolute;
   top: 42px;  /* Positioned just overlapping the top of the toolbar */
@@ -812,7 +810,7 @@
 
 /* These horizontal positions for #cloud-import-details are fallback value.
    Usually, these positions are calculated based on the position of dropdown.
-   These fallback values will be used when the cloud import penel is shown
+   These fallback values will be used when the cloud import panel is shown
    before the toolbar buttons are fully laid out. */
 html[dir='ltr'] #cloud-import-details {
   right: 148px;  /* Positioned in relation to the cloud-import toolbar button */
@@ -828,13 +826,14 @@
 }
 
 #cloud-import-details .banner {
-  background-color: rgb(55, 71, 79);
-  border-radius: 2px 2px 0 0;
-  color: white;
+  background-color: var(--cros-color-prominent);
+  border-radius: 12px 12px 0 0;
+  color: var(--cros-button-label-color-primary);
   padding: 20px;
 }
 
 #cloud-import-details .banner .title {
+  font-family: 'Google Sans';
   font-size: 122%;
   font-weight: 500;
   margin-bottom: 5px;
@@ -853,6 +852,7 @@
 }
 
 #cloud-import-details .status iron-icon {
+  --iron-icon-fill-color: var(--cros-icon-color-primary);
   display: block;
   height: 16px;
   opacity: .6;
@@ -860,22 +860,22 @@
 }
 
 #cloud-import-details .status .content {
-  color: #646464;
+  color: var(--cros-text-color-secondary);
   flex: 1;
   padding-inline-start: 10px;
 }
 
 #cloud-import-details .status .content::first-line {
-  color: #333;
+  color: var(--cros-text-color-primary);
   font-size: 110%;
 }
 
 #cloud-import-details .status a[is='action-link'] {
-  color: rgb(51, 103, 214);
+  color: var(--cros-link-color);
 }
 
 #cloud-import-details .progress {
-  background-color: #E0E0E0;
+  background-color: var(--cros-highlight-color);
   border-radius: 2px;
   height: 4px;
   margin-top: 14px;
@@ -883,7 +883,7 @@
 }
 
 #cloud-import-details .progress .value {
-  background-color: rgb(26, 194, 34);
+  background-color: var(--cros-icon-color-prominent);
   border-radius: 2px;
   height: 4px;
   transition: width 100ms linear;
@@ -891,23 +891,45 @@
 }
 
 #cloud-import-details cr-button {
-  --ink-color: white;
+  --active-bg: transparent;
+  --active-shadow:
+    0 1px 2px var(--cros-button-active-shadow-color-key-secondary),
+    0 1px 3px var(--cros-button-active-shadow-color-ambient-secondary);
+  --active-shadow-action:
+    0 1px 2px var(--cros-button-active-shadow-color-key-primary),
+    0 1px 3px var(--cros-button-active-shadow-color-ambient-primary);
+  --bg-action: var(--cros-button-background-color-primary);
+  --border-color: var(--cros-button-stroke-color-secondary);
+  --disabled-bg-action:
+    var(--cros-button-background-color-primary-disabled);
+  --disabled-bg: var(--cros-button-background-color-primary-disabled);
+  --disabled-border-color:
+    var(--cros-button-stroke-color-secondary-disabled);
+  --disabled-text-color: var(--cros-button-label-color-secondary-disabled);
+  --hover-bg-action:
+    var(--cros-button-background-color-primary-hover-preblended);
+  --hover-bg-color: var(--cros-button-background-color-secondary-hover);
+  --hover-border-color: var(--cros-button-stroke-color-secondary-hover);
+  --ink-color: var(--cros-button-ripple-color-secondary);
+  --ripple-opacity-action: var(--cros-button-primary-ripple-opacity);
+  --ripple-opacity: var(--cros-button-secondary-ripple-opacity);
+  --text-color-action: var(--cros-button-label-color-primary);
+  --text-color: var(--cros-button-label-color-secondary);
   align-self: flex-end;
-  border: none;
   box-shadow: none;
-  color: white;
   font-weight: 500;
   margin-top: 20px;
   padding: 0;
   text-transform: uppercase;
 }
 
-#cloud-import-details cr-button.import {
-  background-color: rgb(51, 103, 214);
+#cloud-import-details cr-button.action-button {
+  --ink-color: var(--cros-button-ripple-color-primary);
 }
 
-#cloud-import-details cr-button.cancel {
-  background-color: rgb(219, 68, 55);
+#cloud-import-details cr-button.cancel-button {
+  /* no margin needed because the cancel button is in a new row */
+  margin-inline-end: 0;
 }
 
 #files-selected-label {
@@ -1298,15 +1320,12 @@
 
 html.focus-outline-visible .dialog-footer .primary:focus,
 html.focus-outline-visible .dialog-footer .secondary:focus,
-html.focus-outline-visible .dialog-footer select:focus {
+html.focus-outline-visible .dialog-footer select:focus,
+html.focus-outline-visible #cloud-import-details cr-button:focus {
   outline: 2px solid var(--cros-focus-ring-color);
   outline-offset: 2px;
 }
 
-html.focus-outline-visible #cloud-import-details cr-button:focus {
-  box-shadow: 0 0 0 2px rgba(51, 103, 214, 50%);
-}
-
 .progressable:not([progress]) .progress-bar,
 .progressable:not([progress]) .preparing-label {
   display: none;
@@ -1825,19 +1844,27 @@
   width: 100%
 }
 
-body.files-ng #default-tasks-list li {
+#default-tasks-list li {
   height: 40px;
   line-height: 40px;
 }
 
-body.files-ng #default-tasks-list > li > * {
+#default-tasks-list > li > .icon {
+  -webkit-mask-position: 16px center;
+  -webkit-mask-repeat: no-repeat;
   background-position: 16px center;
   background-repeat: no-repeat;
   background-size: 20px;
-  padding-inline-start: 52px;
+  height: 100%;
 }
 
-html[dir='rtl'] body.files-ng #default-tasks-list > li > * {
+#default-tasks-list > li > .label {
+  padding-inline-start: 52px;
+  position: absolute;
+}
+
+html[dir='rtl'] #default-tasks-list > li > .icon {
+  -webkit-mask-position-x: calc(100% - 16px);
   background-position-x: calc(100% - 16px);
 }
 
@@ -2130,13 +2157,8 @@
   opacity: 0;
 }
 
-#tasks-menu cr-menu-item:not(.change-default) {
-  background-position: left 10px center;
-  padding-inline-start: 32px;
-}
-
-html[dir='rtl'] #tasks-menu cr-menu-item:not(.change-default) {
-  background-position: right 10px center;
+#tasks-menu cr-menu-item.change-default .icon.start {
+  display: none;
 }
 
 #action-bar {
diff --git a/ui/file_manager/file_manager/foreground/css/file_types.css b/ui/file_manager/file_manager/foreground/css/file_types.css
index 6236b4f..7aff9f7 100644
--- a/ui/file_manager/file_manager/foreground/css/file_types.css
+++ b/ui/file_manager/file_manager/foreground/css/file_types.css
@@ -7,52 +7,68 @@
  is no real need for the root/volume icon distinction for the directory tree
  noting that file-type-icon is also used in lists and menus ;) */
 
+ /* We are mixing background-image and -webkit-mask-image here for different
+  SVGs.
+   * For SVGs whose "fill" colors look okay in light/dark mode, e.g.
+   filetype_audio.svg has red color, we need to use background-image to
+   keep the original color.
+   * For SVGs whose "fill" colors look not okay, e.g. filetype_generic.svg,
+   we need to use -webkit-mask-image together with background-color to
+   customize the color.
+   * By default -webkit-mask-image is used because the default SVG is
+   filetype_generic.svg. In order to use background-image to override,
+   we need to reset both -webkit-mask-image and background-color. */
+
 /* Small icons for file types, used in lists and menus. */
 [file-type-icon] {
+  -webkit-mask-image: url(../images/filetype/filetype_generic.svg);
   -webkit-mask-position: center;
   -webkit-mask-repeat: no-repeat;
-  background-image: url(../images/filetype/filetype_generic.svg);
+  background-color: currentColor;
   background-position: center;
   background-repeat: no-repeat;
   background-size: 20px 20px;
 }
 
-body.files-ng [file-type-icon='archive'] {
-  background-image: url(../images/filetype/filetype_archive.svg);
+[file-type-icon='archive'] {
+  -webkit-mask-image: url(../images/filetype/filetype_archive.svg);
 }
 
-body.files-ng [file-type-icon='audio'] {
+[file-type-icon='audio'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_audio.svg);
 }
 
-body.files-ng [file-type-icon='excel'] {
+[file-type-icon='excel'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_excel.svg);
 }
 
-body.files-ng [file-type-icon='folder'] {
+[file-type-icon='folder'] {
   -webkit-mask-image: url(../images/filetype/filetype_folder.svg);
-  background-color: currentColor;
-  background-image: none;
 }
 
-body.check-select.files-ng #list-container li[selected] [file-type-icon] {
+
+body.check-select #list-container li[selected] [file-type-icon] {
   -webkit-mask-image: none;
   background: none;
 }
 
-body.files-ng .computers-root[file-type-icon='folder'] {
+.computers-root[file-type-icon='folder'] {
   -webkit-mask-image: url(../images/volumes/computer.svg);
 }
 
-body.files-ng .external-media-root[file-type-icon='folder'] {
+.external-media-root[file-type-icon='folder'] {
   -webkit-mask-image: url(../images/volumes/usb.svg);
 }
 
-body.files-ng .shared[file-type-icon='folder'] {
+.shared[file-type-icon='folder'] {
   -webkit-mask-image: url(../images/filetype/filetype_folder_shared.svg);
 }
 
-body.files-ng .team-drive-root[file-type-icon='folder'] {
+.team-drive-root[file-type-icon='folder'] {
   -webkit-mask-image: url(../images/volumes/hard_drive.svg);
 }
 
@@ -69,169 +85,234 @@
   -webkit-mask-image: url(../images/filetype/filetype_team_drive.svg);
 }
 
-body.files-ng [file-type-icon='gdoc'] {
+[file-type-icon='gdoc'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_gdoc.svg);
 }
 
-body.files-ng [file-type-icon='gdraw'] {
+[file-type-icon='gdraw'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_gdraw.svg);
 }
 
-body.files-ng [file-type-icon='glink'] {
-  background-image: url(../images/filetype/filetype_generic.svg);
+[file-type-icon='glink'] {
+  -webkit-mask-image: url(../images/filetype/filetype_generic.svg);
 }
 
-body.files-ng [file-type-icon='gsheet'] {
+[file-type-icon='gsheet'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_gsheet.svg);
 }
 
-body.files-ng [file-type-icon='gslides'] {
+[file-type-icon='gslides'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_gslides.svg);
 }
 
-body.files-ng [file-type-icon='gtable'] {
+[file-type-icon='gtable'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_gtable.svg);
 }
 
-body.files-ng [file-type-icon='gform'] {
+[file-type-icon='gform'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_gform.svg);
 }
 
-body.files-ng [file-type-icon='gmap'] {
+[file-type-icon='gmap'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_gmap.svg);
 }
 
-body.files-ng [file-type-icon='gsite'] {
+[file-type-icon='gsite'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_gsite.svg);
 }
 
-body.files-ng [file-type-icon='image'] {
+[file-type-icon='image'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_image.svg);
 }
 
-body.files-ng [file-type-icon='pdf'] {
+[file-type-icon='pdf'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_pdf.svg);
 }
 
-body.files-ng [file-type-icon='ppt'] {
+[file-type-icon='ppt'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_ppt.svg);
 }
 
-body.files-ng [file-type-icon='script'] {
+[file-type-icon='script'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_script.svg);
 }
 
-body.files-ng [file-type-icon='sites'] {
+[file-type-icon='sites'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_sites.svg);
 }
 
-body.files-ng [file-type-icon='tini'] {
+[file-type-icon='tini'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_tini.svg);
 }
 
-body.files-ng [file-type-icon='video'] {
+[file-type-icon='video'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_video.svg);
 }
 
-body.files-ng [file-type-icon='word'] {
+[file-type-icon='word'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_word.svg);
 }
 
 /* Large generic thumbnails, used when a file does not have a thumbnail. */
 .no-thumbnail[generic-thumbnail] {
+  -webkit-mask-image: url(../images/files/ui/filetype_placeholder_generic.svg);
   -webkit-mask-position: center;
   -webkit-mask-repeat: no-repeat;
   -webkit-mask-size: 48px;
-  background-color: transparent;
-  background-image: url(../images/files/ui/filetype_placeholder_generic.svg);
+  background-color: currentColor;
   background-position: center;
   background-repeat: no-repeat;
   background-size: 48px;
 }
 
 .no-thumbnail[generic-thumbnail='audio'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_audio.svg);
 }
 
 .no-thumbnail[generic-thumbnail='image'],
 .no-thumbnail[generic-thumbnail='raw'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_image.svg);
 }
 
 .no-thumbnail[generic-thumbnail='video'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_video.svg);
 }
 
 /* grid view large icons for known types. */
-body.files-ng .no-thumbnail[generic-thumbnail='archive'] {
+.no-thumbnail[generic-thumbnail='archive'] {
   -webkit-mask-image: url(../images/filetype/filetype_archive.svg);
-  background-color: currentColor;
-  background-image: none;
 }
 
-body.files-ng .no-thumbnail[generic-thumbnail='tini'] {
+.no-thumbnail[generic-thumbnail='tini'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_tini.svg);
 }
 
-body.files-ng .no-thumbnail[generic-thumbnail='excel'] {
+.no-thumbnail[generic-thumbnail='excel'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_excel.svg);
 }
 
-body.files-ng .no-thumbnail[generic-thumbnail='gdoc'] {
+.no-thumbnail[generic-thumbnail='gdoc'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_gdoc.svg);
 }
 
-body.files-ng .no-thumbnail[generic-thumbnail='gdraw'] {
+.no-thumbnail[generic-thumbnail='gdraw'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_gdraw.svg);
 }
 
-body.files-ng .no-thumbnail[generic-thumbnail='gsheet'] {
+.no-thumbnail[generic-thumbnail='gsheet'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_gsheet.svg);
 }
 
-body.files-ng .no-thumbnail[generic-thumbnail='gslides'] {
+.no-thumbnail[generic-thumbnail='gslides'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_gslides.svg);
 }
 
-body.files-ng .no-thumbnail[generic-thumbnail='gtable'] {
+.no-thumbnail[generic-thumbnail='gtable'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_gtable.svg);
 }
 
-body.files-ng .no-thumbnail[generic-thumbnail='gform'] {
+.no-thumbnail[generic-thumbnail='gform'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_gform.svg);
 }
 
-body.files-ng .no-thumbnail[generic-thumbnail='gmap'] {
+.no-thumbnail[generic-thumbnail='gmap'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_gmap.svg);
 }
 
-body.files-ng .no-thumbnail[generic-thumbnail='gsite'] {
+.no-thumbnail[generic-thumbnail='gsite'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_gsite.svg);
 }
 
-body.files-ng .no-thumbnail[generic-thumbnail='pdf'] {
+.no-thumbnail[generic-thumbnail='pdf'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_pdf.svg);
 }
 
-body.files-ng .no-thumbnail[generic-thumbnail='ppt'] {
+.no-thumbnail[generic-thumbnail='ppt'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_ppt.svg);
 }
 
-body.files-ng .no-thumbnail[generic-thumbnail='script'] {
+.no-thumbnail[generic-thumbnail='script'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_script.svg);
 }
 
-body.files-ng .no-thumbnail[generic-thumbnail='sites'] {
+.no-thumbnail[generic-thumbnail='sites'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_sites.svg);
 }
 
-body.files-ng .no-thumbnail[generic-thumbnail='word'] {
+.no-thumbnail[generic-thumbnail='word'] {
+  -webkit-mask-image: none;
+  background-color: transparent;
   background-image: url(../images/filetype/filetype_word.svg);
 }
 
 /* Icons for volume types. A ".tree-row > .file-row" component in any rules
    means the rule only matches in files-ng. */
-
 .tree-row > .file-row > [volume-type-icon='archive'] {
   -webkit-mask-image: url(../images/volumes/archive.svg);
 }
@@ -245,16 +326,12 @@
   -webkit-mask-image: url(../images/volumes/downloads.svg);
 }
 
-body.files-ng [file-type-icon='downloads'] {
+[file-type-icon='downloads'] {
   -webkit-mask-image: url(../images/volumes/downloads.svg);
-  background-color: currentColor;
-  background-image: none;
 }
 
-body.files-ng [file-type-icon='camera-folder'] {
+[file-type-icon='camera-folder'] {
   -webkit-mask-image: url(../images/volumes/camera.svg);
-  background-color: currentColor;
-  background-image: none;
 }
 
 .tree-row > .file-row > [volume-type-icon='drive'] {
@@ -334,10 +411,8 @@
   -webkit-mask-image: url(../images/volumes/phone.svg);
 }
 
-body.files-ng [file-type-icon='removable'] {
+[file-type-icon='removable'] {
   -webkit-mask-image: url(../images/volumes/hard_drive.svg);
-  background-color: currentColor;
-  background-image: none;
 }
 
 .tree-row > .file-row > [volume-type-icon='removable'][volume-subtype='unknown'],
@@ -349,8 +424,8 @@
   -webkit-mask-image: url(../images/volumes/recent.svg);
 }
 
-body.files-ng [file-type-icon='crostini'] {
-  background-image: url(../images/volumes/linux_files.svg);
+[file-type-icon='crostini'] {
+  -webkit-mask-image: url(../images/volumes/linux_files.svg);
 }
 
 .tree-row > .file-row > [root-type-icon='crostini'],
@@ -358,20 +433,16 @@
   -webkit-mask-image: url(../images/volumes/linux_files.svg);
 }
 
-body.files-ng [file-type-icon='android_files'] {
+[file-type-icon='android_files'] {
   -webkit-mask-image: url(../images/volumes/android.svg);
-  background-color: currentColor;
-  background-image: none;
 }
 
 .tree-row > .file-row > [volume-type-icon='android_files'] {
   -webkit-mask-image: url(../images/volumes/android.svg);
 }
 
-body.files-ng [file-type-icon='plugin_vm'] {
+[file-type-icon='plugin_vm'] {
   -webkit-mask-image: url(../images/volumes/plugin_vm_ng.svg);
-  background-color: currentColor;
-  background-image: none;
 }
 
 .tree-row > .file-row > [file-type-icon='plugin_vm'] {
@@ -382,10 +453,8 @@
   -webkit-mask-image: url(../images/volumes/smb.svg);
 }
 
-body.files-ng [file-type-icon='trash'] {
+[file-type-icon='trash'] {
   -webkit-mask-image: url(../images/files/ui/delete_ng.svg);
-  background-color: currentColor;
-  background-image: none;
 }
 
 .tree-row > .file-row > [root-type-icon='trash'],
diff --git a/ui/file_manager/file_manager/foreground/css/menu.css b/ui/file_manager/file_manager/foreground/css/menu.css
index 524dd792..cc04b62 100644
--- a/ui/file_manager/file_manager/foreground/css/menu.css
+++ b/ui/file_manager/file_manager/foreground/css/menu.css
@@ -69,26 +69,40 @@
 }
 
 cr-menu.files-menu > cr-menu-item {
-  background-size: 16px 16px;
   position: relative;
 }
 
 /* Icon on the left of the item label for cr.ui.FilesMenuItem.
    TODO(mtomasz): Upstream to cr.ui.MenuItem. */
-cr-menu.files-menu.has-icon-start cr-menu-item .icon.start {
+cr-menu.files-menu cr-menu-item .icon {
+  -webkit-mask-position: center;
+  -webkit-mask-repeat: no-repeat;
+  -webkit-mask-size: 16px 16px;
   background-position: center;
   background-repeat: no-repeat;
-  display: inline-block;
-  height: 16px;
-  margin-inline-end: 8px;
+  background-size: 16px 16px;
+  height: 32px;
   vertical-align: middle;
   width: 16px;
 }
 
+cr-menu.files-menu cr-menu-item .icon.start {
+  display: inline-block;
+  margin-inline-end: 8px;
+}
+
 cr-menu.files-menu:not(.has-icon-start) cr-menu-item .icon.start {
   display: none;
 }
 
+cr-menu.files-menu cr-menu-item .icon.end {
+  float: right;
+}
+
+html[dir='rtl'] cr-menu.files-menu cr-menu-item .icon.end {
+  float: left;
+}
+
 cr-menu.files-menu > cr-menu-item > .icon {
   position: relative;
   z-index: 1;
diff --git a/ui/file_manager/file_manager/foreground/elements/files_message.html b/ui/file_manager/file_manager/foreground/elements/files_message.html
index 1f3a5b9..41845eb 100644
--- a/ui/file_manager/file_manager/foreground/elements/files_message.html
+++ b/ui/file_manager/file_manager/foreground/elements/files_message.html
@@ -9,7 +9,7 @@
   }
 
   :host {
-    border-bottom: 1px solid var(--google-grey-refresh-300);
+    border-bottom: 1px solid var(--google-grey-300);
     color: var(--cr-primary-text-color);
     display: flex;
     height: 36px;
diff --git a/ui/file_manager/file_manager/foreground/js/task_controller.js b/ui/file_manager/file_manager/foreground/js/task_controller.js
index 8cd5351..45957533 100644
--- a/ui/file_manager/file_manager/foreground/js/task_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/task_controller.js
@@ -443,25 +443,28 @@
   updateContextMenuTaskItems_(openTasks) {
     const defaultTask = FileTasks.getDefaultTask(openTasks, this.taskHistory_);
     if (defaultTask) {
-      this.ui_.defaultTaskMenuItem.removeAttribute('file-type-icon');
+      const menuItem = this.ui_.defaultTaskMenuItem;
+      /**
+       * Menu icon can be controlled by either `iconEndImage` or
+       * `iconEndFileType`, since the default task menu item DOM is shared,
+       * before updating it, we should remove the previous one, e.g. reset both
+       * `iconEndImage` and `iconEndFileType`.
+       */
+      menuItem.iconEndImage = '';
+      menuItem.removeIconEndFileType();
+
+      menuItem.setIconEndHidden(false);
       if (defaultTask.iconType) {
-        this.ui_.defaultTaskMenuItem.style.backgroundImage = '';
-        this.ui_.defaultTaskMenuItem.setAttribute(
-            'file-type-icon', defaultTask.iconType);
-        this.ui_.defaultTaskMenuItem.style.marginInlineEnd = '28px';
+        menuItem.iconEndFileType = defaultTask.iconType;
       } else if (defaultTask.iconUrl) {
-        this.ui_.defaultTaskMenuItem.style.backgroundImage =
-            'url(' + defaultTask.iconUrl + ')';
-        this.ui_.defaultTaskMenuItem.style.marginInlineEnd = '28px';
+        menuItem.iconEndImage = 'url(' + defaultTask.iconUrl + ')';
       } else {
-        this.ui_.defaultTaskMenuItem.style.backgroundImage = '';
-        this.ui_.defaultTaskMenuItem.style.marginInlineEnd = '';
+        menuItem.setIconEndHidden(true);
       }
 
-      this.ui_.defaultTaskMenuItem.label =
-          defaultTask.label || defaultTask.title;
-      this.ui_.defaultTaskMenuItem.disabled = !!defaultTask.disabled;
-      this.ui_.defaultTaskMenuItem.descriptor = defaultTask.descriptor;
+      menuItem.label = defaultTask.label || defaultTask.title;
+      menuItem.disabled = !!defaultTask.disabled;
+      menuItem.descriptor = defaultTask.descriptor;
     }
 
     this.canExecuteDefaultTask_ = defaultTask != null;
diff --git a/ui/file_manager/file_manager/foreground/js/ui/breadcrumb.html b/ui/file_manager/file_manager/foreground/js/ui/breadcrumb.html
index 6785715..d350432 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/breadcrumb.html
+++ b/ui/file_manager/file_manager/foreground/js/ui/breadcrumb.html
@@ -155,6 +155,7 @@
 
   cr-action-menu {
     --cr-menu-background-color: var(--cros-bg-color-elevation-2);
+    --cr-menu-background-sheen: none;
     --cr-menu-shadow: var(--cros-elevation-2-shadow);
   }
 </style>
diff --git a/ui/file_manager/file_manager/foreground/js/ui/combobutton.js b/ui/file_manager/file_manager/foreground/js/ui/combobutton.js
index 5c5277f..5385983 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/combobutton.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/combobutton.js
@@ -59,9 +59,13 @@
     }
 
     menuitem.data = item;
+    // Move backgroundImage from the menu item container to the child icon.
+    menuitem.iconStartImage = menuitem.style.backgroundImage;
+    menuitem.style.backgroundImage = '';
+
     if (item.iconType) {
-      menuitem.style.backgroundImage = '';
-      menuitem.setAttribute('file-type-icon', item.iconType);
+      menuitem.iconStartImage = '';
+      menuitem.iconStartFileType = item.iconType;
     }
     if (item.bold) {
       menuitem.style.fontWeight = 'bold';
diff --git a/ui/file_manager/file_manager/foreground/js/ui/default_task_dialog.js b/ui/file_manager/file_manager/foreground/js/ui/default_task_dialog.js
index 9e2321a..2f5cf6c 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/default_task_dialog.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/default_task_dialog.js
@@ -88,20 +88,27 @@
   renderItem(item) {
     const result = this.document_.createElement('li');
 
-    const div = this.document_.createElement('div');
-    div.textContent = item.label;
+    // Task label.
+    const labelSpan = this.document_.createElement('span');
+    labelSpan.classList.add('label');
+    labelSpan.textContent = item.label;
+
+    // Task file type icon.
+    const iconDiv = this.document_.createElement('div');
+    iconDiv.classList.add('icon');
 
     if (item.iconType) {
-      div.setAttribute('file-type-icon', item.iconType);
+      iconDiv.setAttribute('file-type-icon', item.iconType);
     } else if (item.iconUrl) {
-      div.style.backgroundImage = 'url(' + item.iconUrl + ')';
+      iconDiv.style.backgroundImage = 'url(' + item.iconUrl + ')';
     }
 
     if (item.class) {
-      div.classList.add(item.class);
+      iconDiv.classList.add(item.class);
     }
 
-    result.appendChild(div);
+    result.appendChild(labelSpan);
+    result.appendChild(iconDiv);
     // A11y - make it focusable and readable.
     result.setAttribute('tabindex', '-1');
 
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js b/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
index 29a4c30..5d2e32d1 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
@@ -304,11 +304,11 @@
         util.queryDecoratedElement('#file-context-menu', MultiMenu);
 
     /**
-     * @public {!HTMLMenuItemElement}
+     * @public {!FilesMenuItem}
      * @const
      */
     this.defaultTaskMenuItem =
-        /** @type {!HTMLMenuItemElement} */
+        /** @type {!FilesMenuItem} */
         (queryRequiredElement('#default-task-menu-item', this.fileContextMenu));
 
     /**
diff --git a/ui/file_manager/file_manager/foreground/js/ui/files_menu.js b/ui/file_manager/file_manager/foreground/js/ui/files_menu.js
index cf68781..029f38b 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/files_menu.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/files_menu.js
@@ -26,8 +26,14 @@
     this.iconStart_ = null;
 
     /** @private {?HTMLElement} */
+    this.iconEnd_ = null;
+
+    /** @private {?HTMLElement} */
     this.ripple_ = null;
 
+    /** @public @type {?chrome.fileManagerPrivate.FileTaskDescriptor} */
+    this.descriptor = null;
+
     throw new Error('Designed to decorate elements');
   }
 
@@ -58,10 +64,21 @@
           assertInstanceof(document.createElement('div'), HTMLElement);
       this.iconStart_.classList.add('icon', 'start');
 
+      this.iconEnd_ =
+          assertInstanceof(document.createElement('div'), HTMLElement);
+      this.iconEnd_.classList.add('icon', 'end');
+      /**
+       * This is hidden by default because most of the menu items don't require
+       * an end icon, the component which uses end icon should explicitly make
+       * it visible.
+       */
+      this.setIconEndHidden(true);
+
       // Override with standard menu item elements.
       this.textContent = '';
       this.appendChild(this.iconStart_);
       this.appendChild(this.label_);
+      this.appendChild(this.iconEnd_);
     }
 
     this.ripple_ =
@@ -205,4 +222,58 @@
   set iconStartImage(value) {
     this.iconStart_.setAttribute('style', 'background-image: ' + value);
   }
+
+  /**
+   * @return {string}
+   */
+  get iconStartFileType() {
+    return this.iconStart_.getAttribute('file-type-icon');
+  }
+
+  /**
+   * @param {string} value
+   */
+  set iconStartFileType(value) {
+    this.iconStart_.setAttribute('file-type-icon', value);
+  }
+
+  /**
+   * @return {string}
+   */
+  get iconEndImage() {
+    return this.iconEnd_.style.backgroundImage;
+  }
+
+  /**
+   * @param {string} value
+   */
+  set iconEndImage(value) {
+    this.iconEnd_.setAttribute('style', 'background-image: ' + value);
+  }
+
+  /**
+   * @return {string}
+   */
+  get iconEndFileType() {
+    return this.iconEnd_.getAttribute('file-type-icon');
+  }
+
+  /**
+   * @param {string} value
+   */
+  set iconEndFileType(value) {
+    this.iconEnd_.setAttribute('file-type-icon', value);
+  }
+
+  removeIconEndFileType() {
+    this.iconEnd_.removeAttribute('file-type-icon');
+  }
+
+  /**
+   *
+   * @param {boolean} isHidden
+   */
+  setIconEndHidden(isHidden) {
+    this.iconEnd_.toggleAttribute('hidden', isHidden);
+  }
 }
diff --git a/ui/file_manager/file_manager/main.html b/ui/file_manager/file_manager/main.html
index d912e9b7..2653ca4 100644
--- a/ui/file_manager/file_manager/main.html
+++ b/ui/file_manager/file_manager/main.html
@@ -311,7 +311,7 @@
         </cr-menu-item>
       </cr-menu>
 
-      <cr-menu id="tasks-menu" class="chrome-menu files-menu"
+      <cr-menu id="tasks-menu" class="chrome-menu files-menu has-icon-start"
                aria-label="$i18n{OPEN_WITH_BUTTON_LABEL}"
                menu-item-selector="cr-menu-item, hr">
       </cr-menu>
@@ -344,10 +344,10 @@
           <div class="content"></div>
         </div>
         <div class="progress"><div class="value"></div></div>
-        <cr-button class="import" tabindex="0">
+        <cr-button class="import action-button" tabindex="0">
           <span>$i18n{CLOUD_IMPORT_COMMAND}</span>
         </cr-button>
-        <cr-button class="cancel" tabindex="0">
+        <cr-button class="cancel cancel-button" tabindex="0">
           <span>$i18n{CLOUD_IMPORT_CANCEL_COMMAND}</span>
         </cr-button>
       </div>
diff --git a/ui/gl/gl_context_cgl.cc b/ui/gl/gl_context_cgl.cc
index 47f4192..7aa2655a 100644
--- a/ui/gl/gl_context_cgl.cc
+++ b/ui/gl/gl_context_cgl.cc
@@ -78,6 +78,7 @@
 bool GLContextCGL::Initialize(GLSurface* compatible_surface,
                               const GLContextAttribs& attribs) {
   DCHECK(compatible_surface);
+  DCHECK(share_group());
 
   // webgl_compatibility_context and disabling bind_generates_resource are not
   // supported.
@@ -87,9 +88,6 @@
   GpuPreference gpu_preference =
       GLSurface::AdjustGpuPreference(attribs.gpu_preference);
 
-  GLContextCGL* share_context = share_group() ?
-      static_cast<GLContextCGL*>(share_group()->GetContext()) : nullptr;
-
   CGLPixelFormatObj format = GetPixelFormat();
   if (!format)
     return false;
@@ -106,9 +104,7 @@
   }
 
   CGLError res = CGLCreateContext(
-      format,
-      share_context ?
-          static_cast<CGLContextObj>(share_context->GetHandle()) : nullptr,
+      format, static_cast<CGLContextObj>(share_group()->GetHandle()),
       reinterpret_cast<CGLContextObj*>(&context_));
   if (res != kCGLNoError) {
     LOG(ERROR) << "Error creating context.";
diff --git a/ui/gl/gl_context_cgl.h b/ui/gl/gl_context_cgl.h
index f6474e3..6bcb333 100644
--- a/ui/gl/gl_context_cgl.h
+++ b/ui/gl/gl_context_cgl.h
@@ -18,7 +18,7 @@
 class GLSurface;
 
 // Encapsulates a CGL OpenGL context.
-class GL_EXPORT GLContextCGL : public GLContextReal {
+class GL_EXPORT GLContextCGL final : public GLContextReal {
  public:
   explicit GLContextCGL(GLShareGroup* share_group);
 
diff --git a/ui/shell_dialogs/select_file_dialog_win_unittest.cc b/ui/shell_dialogs/select_file_dialog_win_unittest.cc
index 0a90cc21..fe1f2395 100644
--- a/ui/shell_dialogs/select_file_dialog_win_unittest.cc
+++ b/ui/shell_dialogs/select_file_dialog_win_unittest.cc
@@ -20,10 +20,11 @@
 #include "base/test/test_timeouts.h"
 #include "base/threading/platform_thread.h"
 #include "base/win/scoped_com_initializer.h"
+#include "base/win/windows_version.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/shell_dialogs/select_file_dialog.h"
 #include "ui/shell_dialogs/select_file_dialog_win.h"
+#include "ui/shell_dialogs/select_file_dialog.h"
 #include "ui/shell_dialogs/select_file_policy.h"
 #include "ui/strings/grit/ui_strings.h"
 
@@ -197,8 +198,11 @@
   bool was_cancelled_ = false;
 };
 
-// TODO(crbug.com/1265379): Flaky.
-TEST_F(SelectFileDialogWinTest, DISABLED_CancelAllDialogs) {
+TEST_F(SelectFileDialogWinTest, CancelAllDialogs) {
+  // TODO(crbug.com/1265379): Flaky on Windows 7.
+  if (base::win::GetVersion() <= base::win::Version::WIN7)
+    GTEST_SKIP() << "Skipping test for Windows 7";
+
   // Intentionally not testing SELECT_UPLOAD_FOLDER because the dialog is
   // customized for that case.
   struct {
diff --git a/url/origin.cc b/url/origin.cc
index 2b9b92f..557516b 100644
--- a/url/origin.cc
+++ b/url/origin.cc
@@ -163,6 +163,20 @@
   return std::tie(tuple_, nonce_) == std::tie(other.tuple_, other.nonce_);
 }
 
+bool Origin::IsSameOriginWith(const GURL& url) const {
+  if (opaque())
+    return false;
+
+  // The `url::Origin::Create` call here preserves how IsSameOriginWith was used
+  // historically, even though in some scenarios it is not clearly correct:
+  // - Origin of about:blank and about:srcdoc cannot be correctly
+  //   computed/recovered.
+  // - Ideally passing an invalid `url` would be a caller error (e.g. a DCHECK).
+  // - The caller intent is not always clear wrt handling the outer-vs-inner
+  //   origins/URLs in blob: and filesystem: schemes.
+  return IsSameOriginWith(url::Origin::Create(url));
+}
+
 bool Origin::CanBeDerivedFrom(const GURL& url) const {
   DCHECK(url.is_valid());
 
diff --git a/url/origin.h b/url/origin.h
index 17cadf3..8938e67a 100644
--- a/url/origin.h
+++ b/url/origin.h
@@ -222,6 +222,15 @@
     return !IsSameOriginWith(other);
   }
 
+  // Non-opaque origin is "same-origin" with `url` if their schemes, hosts, and
+  // ports are exact matches.  Opaque origin is never "same-origin" with any
+  // `url`.  about:blank, about:srcdoc, and invalid GURLs are never
+  // "same-origin" with any origin.  This method is a shorthand for
+  // `origin.IsSameOriginWith(url::Origin::Create(url))`.
+  //
+  // See also CanBeDerivedFrom.
+  bool IsSameOriginWith(const GURL& url) const;
+
   // This method returns true for any |url| which if navigated to could result
   // in an origin compatible with |this|.
   bool CanBeDerivedFrom(const GURL& url) const;
diff --git a/url/origin_unittest.cc b/url/origin_unittest.cc
index bc542967..1565e89 100644
--- a/url/origin_unittest.cc
+++ b/url/origin_unittest.cc
@@ -746,6 +746,29 @@
   EXPECT_EQ(opaque.GetDebugString(), deserialized.value().GetDebugString());
 }
 
+TEST_F(OriginTest, IsSameOriginWith) {
+  url::Origin opaque_origin;
+  GURL foo_url = GURL("https://foo.com/path");
+  url::Origin foo_origin = url::Origin::Create(foo_url);
+  GURL bar_url = GURL("https://bar.com/path");
+  url::Origin bar_origin = url::Origin::Create(bar_url);
+
+  EXPECT_FALSE(opaque_origin.IsSameOriginWith(foo_origin));
+  EXPECT_FALSE(opaque_origin.IsSameOriginWith(foo_url));
+
+  EXPECT_TRUE(foo_origin.IsSameOriginWith(foo_origin));
+  EXPECT_TRUE(foo_origin.IsSameOriginWith(foo_url));
+
+  EXPECT_FALSE(foo_origin.IsSameOriginWith(bar_origin));
+  EXPECT_FALSE(foo_origin.IsSameOriginWith(bar_url));
+
+  // Documenting legacy behavior.  This doesn't necessarily mean that the legacy
+  // behavior is correct (or desirable in the long-term).
+  EXPECT_FALSE(foo_origin.IsSameOriginWith(GURL("about:blank")));
+  EXPECT_FALSE(foo_origin.IsSameOriginWith(GURL()));  // Invalid GURL.
+  EXPECT_TRUE(foo_origin.IsSameOriginWith(GURL("blob:https://foo.com/guid")));
+}
+
 INSTANTIATE_TYPED_TEST_SUITE_P(UrlOrigin,
                                AbstractOriginTest,
                                UrlOriginTestTraits);