diff --git a/DEPS b/DEPS
index cb97b96..d6d16ee 100644
--- a/DEPS
+++ b/DEPS
@@ -209,11 +209,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'd977fdecc63406243a2ff698fa63a5b07a13d593',
+  'skia_revision': 'cad48c6868bfa28c9373f7410af748477b86b8e5',
   # 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': 'c2b5d940cd0093b0cc6e5689982e29990f891380',
+  'v8_revision': 'be9a3d51b07069d6d4a070209436007df9e0637b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -280,7 +280,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '52e67e75f6c2d0315d510a54a52ed29abe3d57f7',
+  'catapult_revision': 'affd272f9ee374467307e6b5af1f0c3f1b0c16e8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -328,7 +328,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '82ba34a94114de8ac9de252607da255ffcd69b51',
+  'dawn_revision': '73c0190b4d39e190e50f42c1600f11623f9863d2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -961,12 +961,12 @@
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '3b49330064404cd554cd2cd4c6d5bbcdf3b9418c',
+      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + 'fcb33a93e2fc59ca1d5d13f5a5c31b771840013f',
       'condition': 'checkout_linux',
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'b073879ad6a0867654a36e951a37467a9e8efe8c',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '47a4b0bc5937e8309f1ed9abeb02fc5423e64bb0',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1423,11 +1423,22 @@
       'dep_type': 'cipd',
   },
 
+  'src/third_party/aemu-linux-arm64': {
+      'packages': [
+          {
+              'package': 'fuchsia/third_party/aemu/linux-arm64',
+              'version': 'r2LsKQPbfi0NYEO8tfocwaJ1MMACXPDLkgCI0IjJq-YC'
+          },
+      ],
+      'condition': 'host_os == "linux" and checkout_fuchsia',
+      'dep_type': 'cipd',
+  },
+
   'src/third_party/aemu-linux-x64': {
       'packages': [
           {
               'package': 'fuchsia/third_party/aemu/linux-amd64',
-              'version': 'UbJ5WKeCpti3a2tT_h2wS1sh_OeOd-s0-O6_rlN0zcAC'
+              'version': 'JANUSSL6vlpZwl7eeXT1Jv3TTKfhHXjW18WlDQyun4kC'
           },
       ],
       'condition': 'host_os == "linux" and checkout_fuchsia',
@@ -1536,7 +1547,7 @@
   'src/third_party/usrsctp/usrsctplib':
     Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + 'acfce46e428cc084b4bd0164e1b019261a8dbeda',
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@059281f5a2642cb0e4b74a77833e7321971d1712',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@ae2238052067b2a6e66e07be7a0958ddddec7fa6',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + '732a76d9d3c70d6aa487216495eeb28518349c3a',
@@ -1624,7 +1635,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@e241fd0a109c28d5e31e236746b4b7b991d4c778',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@15b0ef0e832be7b65e840f14645b2fcaa78911e0',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 477946d..9444020 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -2169,6 +2169,12 @@
       'Var': _VarImpl(local_scope).Lookup,
       'Str': str,
   }
+
+  # TODO(crbug.com/1207012): We need to strip the BOM because it isn't
+  # legal in Python source files. We can remove this check once the CL
+  # that actually removes the BOM from //third_party/crashpad/DEPS lands.
+  if contents.startswith(u'\ufeff'):
+      contents = contents[1:]
   exec contents in global_scope, local_scope
   return local_scope
 
diff --git a/ash/app_list/BUILD.gn b/ash/app_list/BUILD.gn
index c098b77..c728234 100644
--- a/ash/app_list/BUILD.gn
+++ b/ash/app_list/BUILD.gn
@@ -18,6 +18,8 @@
     "app_list_presenter_delegate.h",
     "app_list_presenter_delegate_impl.cc",
     "app_list_presenter_delegate_impl.h",
+    "app_list_presenter_event_filter.cc",
+    "app_list_presenter_event_filter.h",
     "app_list_presenter_impl.cc",
     "app_list_presenter_impl.h",
     "app_list_util.cc",
diff --git a/ash/app_list/app_list_presenter_delegate_impl.cc b/ash/app_list/app_list_presenter_delegate_impl.cc
index f7a1467..c02fc9c2 100644
--- a/ash/app_list/app_list_presenter_delegate_impl.cc
+++ b/ash/app_list/app_list_presenter_delegate_impl.cc
@@ -5,37 +5,18 @@
 #include "ash/app_list/app_list_presenter_delegate_impl.h"
 
 #include <memory>
-#include <utility>
 
 #include "ash/app_list/app_list_controller_impl.h"
+#include "ash/app_list/app_list_presenter_event_filter.h"
 #include "ash/app_list/app_list_presenter_impl.h"
-#include "ash/app_list/app_list_util.h"
-#include "ash/app_list/views/app_list_main_view.h"
 #include "ash/app_list/views/app_list_view.h"
-#include "ash/app_list/views/contents_view.h"
-#include "ash/app_list/views/search_box_view.h"
-#include "ash/bubble/bubble_utils.h"
-#include "ash/constants/ash_switches.h"
-#include "ash/keyboard/ui/keyboard_ui_controller.h"
-#include "ash/public/cpp/app_list/app_list_switches.h"
-#include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/shelf_types.h"
-#include "ash/shelf/back_button.h"
-#include "ash/shelf/home_button.h"
-#include "ash/shelf/hotseat_widget.h"
+#include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_layout_manager.h"
-#include "ash/shelf/shelf_navigation_widget.h"
-#include "ash/shelf/shelf_widget.h"
 #include "ash/shell.h"
-#include "ash/system/status_area_widget.h"
-#include "base/command_line.h"
 #include "ui/aura/window.h"
 #include "ui/display/manager/display_manager.h"
-#include "ui/events/event.h"
-#include "ui/events/event_handler.h"
-#include "ui/events/keycodes/keyboard_codes_posix.h"
 #include "ui/views/widget/widget.h"
-#include "ui/wm/core/coordinate_conversion.h"
 
 namespace ash {
 namespace {
@@ -126,7 +107,8 @@
 
   SnapAppListBoundsToDisplayEdge();
 
-  event_filter_ = std::make_unique<EventFilter>(controller_, presenter_, view_);
+  event_filter_ = std::make_unique<AppListPresenterEventFilter>(
+      controller_, presenter_, view_);
   controller_->ViewShown(display_id);
 }
 
@@ -162,178 +144,6 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// AppListPresenterDelegateImpl::EventFilter:
-
-// Listens to shell events and touches/mouse clicks outside the app list to auto
-// dismiss the UI when necessary.
-class AppListPresenterDelegateImpl::EventFilter : public ui::EventHandler {
- public:
-  EventFilter(AppListControllerImpl* controller,
-              AppListPresenterImpl* presenter,
-              AppListView* view);
-  EventFilter(const EventFilter&) = delete;
-  EventFilter& operator=(const EventFilter&) = delete;
-  ~EventFilter() override;
-
- private:
-  void ProcessLocatedEvent(ui::LocatedEvent* event);
-
-  // ui::EventHandler overrides:
-  void OnMouseEvent(ui::MouseEvent* event) override;
-  void OnGestureEvent(ui::GestureEvent* event) override;
-  void OnKeyEvent(ui::KeyEvent* event) override;
-
-  AppListControllerImpl* const controller_;
-  AppListPresenterImpl* const presenter_;
-  AppListView* const view_;
-};
-
-AppListPresenterDelegateImpl::EventFilter::EventFilter(
-    AppListControllerImpl* controller,
-    AppListPresenterImpl* presenter,
-    AppListView* view)
-    : controller_(controller), presenter_(presenter), view_(view) {
-  DCHECK(controller_);
-  DCHECK(presenter_);
-  DCHECK(view_);
-  Shell::Get()->AddPreTargetHandler(this);
-}
-
-AppListPresenterDelegateImpl::EventFilter::~EventFilter() {
-  Shell::Get()->RemovePreTargetHandler(this);
-}
-
-void AppListPresenterDelegateImpl::EventFilter::ProcessLocatedEvent(
-    ui::LocatedEvent* event) {
-  // Check the general rules for closing bubbles.
-  if (!bubble_utils::ShouldCloseBubbleForEvent(*event))
-    return;
-
-  aura::Window* target = static_cast<aura::Window*>(event->target());
-  if (!target)
-    return;
-
-  // If the event happened on the home button's widget, it'll get handled by the
-  // button.
-  Shelf* shelf = Shelf::ForWindow(target);
-  HomeButton* home_button = shelf->navigation_widget()->GetHomeButton();
-  if (home_button && home_button->GetWidget() &&
-      target == home_button->GetWidget()->GetNativeWindow()) {
-    gfx::Point location_in_home_button = event->location();
-    views::View::ConvertPointFromWidget(home_button, &location_in_home_button);
-    if (home_button->HitTestPoint(location_in_home_button))
-      return;
-  }
-
-  // If the event happened on the back button, it'll get handled by the
-  // button.
-  BackButton* back_button = shelf->navigation_widget()->GetBackButton();
-  if (back_button && back_button->GetWidget() &&
-      target == back_button->GetWidget()->GetNativeWindow()) {
-    gfx::Point location_in_back_button = event->location();
-    views::View::ConvertPointFromWidget(back_button, &location_in_back_button);
-    if (back_button->HitTestPoint(location_in_back_button))
-      return;
-  }
-
-  aura::Window* window = view_->GetWidget()->GetNativeView()->parent();
-  if (window->Contains(target))
-    return;
-
-  // Try to close an open folder window: return if an open folder view was
-  // closed successfully.
-  if (presenter_->HandleCloseOpenFolder())
-    return;
-
-  if (!Shell::Get()->IsInTabletMode()) {
-    // Do not dismiss the app list if the event is targeting shelf area
-    // containing app icons.
-    if (target == shelf->hotseat_widget()->GetNativeWindow() &&
-        shelf->hotseat_widget()->EventTargetsShelfView(*event)) {
-      return;
-    }
-
-    // Don't dismiss the auto-hide shelf if event happened in status area. Then
-    // the event can still be propagated.
-    const aura::Window* status_window =
-        shelf->shelf_widget()->status_area_widget()->GetNativeWindow();
-    if (status_window && status_window->Contains(target)) {
-      auto shelf_visibility_lock =
-          std::make_unique<ShelfLayoutManager::ScopedVisibilityLock>(
-              shelf->shelf_layout_manager());
-
-      // Use a task runner to delete the |shelf_visibility_lock| and update the
-      // shelf visibility after the current event has been handled by the shelf.
-      // This is important for the case where dismissing the app list might hide
-      // the shelf, which would stop the shelf from handling the event.
-      // TODO(crbug.com/1186479): Investigate whether there is a better way to
-      // do this, instead of using a task runner here.
-      base::ThreadTaskRunnerHandle::Get()->DeleteSoon(
-          FROM_HERE, std::move(shelf_visibility_lock));
-    }
-
-    // Record the current AppListViewState to be used later for metrics. The
-    // AppListViewState will change on app launch, so this will record the
-    // AppListViewState before the app was launched.
-    controller_->RecordAppListState();
-    presenter_->Dismiss(event->time_stamp());
-  }
-}
-
-void AppListPresenterDelegateImpl::EventFilter::OnMouseEvent(
-    ui::MouseEvent* event) {
-  // Moving the mouse shouldn't hide focus rings.
-  if (event->IsAnyButton())
-    controller_->SetKeyboardTraversalMode(false);
-
-  if (event->type() == ui::ET_MOUSE_PRESSED)
-    ProcessLocatedEvent(event);
-}
-
-void AppListPresenterDelegateImpl::EventFilter::OnGestureEvent(
-    ui::GestureEvent* event) {
-  controller_->SetKeyboardTraversalMode(false);
-
-  // Checks tap types instead of ui::ET_TOUCH_PRESSED so that swipes on the
-  // shelf do not close the launcher. https://crbug.com/750274
-  if (event->type() == ui::ET_GESTURE_TAP ||
-      event->type() == ui::ET_GESTURE_TWO_FINGER_TAP ||
-      event->type() == ui::ET_GESTURE_LONG_PRESS) {
-    ProcessLocatedEvent(event);
-  }
-}
-
-void AppListPresenterDelegateImpl::EventFilter::OnKeyEvent(
-    ui::KeyEvent* event) {
-  // If keyboard traversal is already engaged, no-op.
-  if (controller_->KeyboardTraversalEngaged())
-    return;
-
-  // If the home launcher is not shown in tablet mode, ignore events.
-  if (Shell::Get()->IsInTabletMode() && !controller_->IsVisible(base::nullopt))
-    return;
-
-  // Don't absorb the first event for the search box while it is open
-  if (view_->search_box_view()->is_search_box_active())
-    return;
-
-  // Don't absorb the first event when showing Assistant.
-  if (view_->IsShowingEmbeddedAssistantUI())
-    return;
-
-  // Don't absorb the first event when renaming folder.
-  if (view_->IsFolderBeingRenamed())
-    return;
-
-  // Arrow keys or Tab will engage the traversal mode.
-  if ((IsUnhandledArrowKeyEvent(*event) || event->key_code() == ui::VKEY_TAB)) {
-    // Handle the first arrow key event to just show the focus rings.
-    event->SetHandled();
-    controller_->SetKeyboardTraversalMode(true);
-  }
-}
-
-////////////////////////////////////////////////////////////////////////////////
 // AppListPresenterDelegateImpl, private:
 
 void AppListPresenterDelegateImpl::SnapAppListBoundsToDisplayEdge() {
diff --git a/ash/app_list/app_list_presenter_delegate_impl.h b/ash/app_list/app_list_presenter_delegate_impl.h
index 7b6cac1..302904b 100644
--- a/ash/app_list/app_list_presenter_delegate_impl.h
+++ b/ash/app_list/app_list_presenter_delegate_impl.h
@@ -21,6 +21,7 @@
 
 namespace ash {
 class AppListControllerImpl;
+class AppListPresenterEventFilter;
 class AppListPresenterImpl;
 class AppListView;
 enum class AppListViewState;
@@ -70,7 +71,7 @@
   AppListControllerImpl* const controller_ = nullptr;
 
   // Closes the app list when the user clicks outside its bounds.
-  std::unique_ptr<EventFilter> event_filter_;
+  std::unique_ptr<AppListPresenterEventFilter> event_filter_;
 
   // An observer that notifies AppListView when the display has changed.
   base::ScopedObservation<display::Screen, display::DisplayObserver>
diff --git a/ash/app_list/app_list_presenter_event_filter.cc b/ash/app_list/app_list_presenter_event_filter.cc
new file mode 100644
index 0000000..0c2594f
--- /dev/null
+++ b/ash/app_list/app_list_presenter_event_filter.cc
@@ -0,0 +1,176 @@
+// 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/app_list/app_list_presenter_event_filter.h"
+
+#include <memory>
+#include <utility>
+
+#include "ash/app_list/app_list_controller_impl.h"
+#include "ash/app_list/app_list_presenter_impl.h"
+#include "ash/app_list/app_list_util.h"
+#include "ash/app_list/views/app_list_main_view.h"
+#include "ash/app_list/views/search_box_view.h"
+#include "ash/bubble/bubble_utils.h"
+#include "ash/shelf/back_button.h"
+#include "ash/shelf/home_button.h"
+#include "ash/shelf/hotseat_widget.h"
+#include "ash/shelf/shelf.h"
+#include "ash/shelf/shelf_layout_manager.h"
+#include "ash/shelf/shelf_navigation_widget.h"
+#include "ash/shelf/shelf_widget.h"
+#include "ash/shell.h"
+#include "ash/system/status_area_widget.h"
+#include "base/check.h"
+#include "base/optional.h"
+#include "ui/aura/window.h"
+#include "ui/events/event.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+
+namespace ash {
+
+AppListPresenterEventFilter::AppListPresenterEventFilter(
+    AppListControllerImpl* controller,
+    AppListPresenterImpl* presenter,
+    AppListView* view)
+    : controller_(controller), presenter_(presenter), view_(view) {
+  DCHECK(controller_);
+  DCHECK(presenter_);
+  DCHECK(view_);
+  Shell::Get()->AddPreTargetHandler(this);
+}
+
+AppListPresenterEventFilter::~AppListPresenterEventFilter() {
+  Shell::Get()->RemovePreTargetHandler(this);
+}
+
+void AppListPresenterEventFilter::OnMouseEvent(ui::MouseEvent* event) {
+  // Moving the mouse shouldn't hide focus rings.
+  if (event->IsAnyButton())
+    controller_->SetKeyboardTraversalMode(false);
+
+  if (event->type() == ui::ET_MOUSE_PRESSED)
+    ProcessLocatedEvent(event);
+}
+
+void AppListPresenterEventFilter::OnGestureEvent(ui::GestureEvent* event) {
+  controller_->SetKeyboardTraversalMode(false);
+
+  // Checks tap types instead of ui::ET_TOUCH_PRESSED so that swipes on the
+  // shelf do not close the launcher. https://crbug.com/750274
+  if (event->type() == ui::ET_GESTURE_TAP ||
+      event->type() == ui::ET_GESTURE_TWO_FINGER_TAP ||
+      event->type() == ui::ET_GESTURE_LONG_PRESS) {
+    ProcessLocatedEvent(event);
+  }
+}
+
+void AppListPresenterEventFilter::OnKeyEvent(ui::KeyEvent* event) {
+  // If keyboard traversal is already engaged, no-op.
+  if (controller_->KeyboardTraversalEngaged())
+    return;
+
+  // If the home launcher is not shown in tablet mode, ignore events.
+  if (Shell::Get()->IsInTabletMode() && !controller_->IsVisible(base::nullopt))
+    return;
+
+  // Don't absorb the first event for the search box while it is open.
+  if (view_->search_box_view()->is_search_box_active())
+    return;
+
+  // Don't absorb the first event when showing Assistant.
+  if (view_->IsShowingEmbeddedAssistantUI())
+    return;
+
+  // Don't absorb the first event when renaming folder.
+  if (view_->IsFolderBeingRenamed())
+    return;
+
+  // Arrow keys or Tab will engage the traversal mode.
+  if ((IsUnhandledArrowKeyEvent(*event) || event->key_code() == ui::VKEY_TAB)) {
+    // Handle the first arrow key event to just show the focus rings.
+    event->SetHandled();
+    controller_->SetKeyboardTraversalMode(true);
+  }
+}
+
+void AppListPresenterEventFilter::ProcessLocatedEvent(ui::LocatedEvent* event) {
+  // Check the general rules for closing bubbles.
+  if (!bubble_utils::ShouldCloseBubbleForEvent(*event))
+    return;
+
+  aura::Window* target = static_cast<aura::Window*>(event->target());
+  if (!target)
+    return;
+
+  // If the event happened on the home button's widget, it'll get handled by the
+  // button.
+  Shelf* shelf = Shelf::ForWindow(target);
+  HomeButton* home_button = shelf->navigation_widget()->GetHomeButton();
+  if (home_button && home_button->GetWidget() &&
+      target == home_button->GetWidget()->GetNativeWindow()) {
+    gfx::Point location_in_home_button = event->location();
+    views::View::ConvertPointFromWidget(home_button, &location_in_home_button);
+    if (home_button->HitTestPoint(location_in_home_button))
+      return;
+  }
+
+  // If the event happened on the back button, it'll get handled by the
+  // button.
+  BackButton* back_button = shelf->navigation_widget()->GetBackButton();
+  if (back_button && back_button->GetWidget() &&
+      target == back_button->GetWidget()->GetNativeWindow()) {
+    gfx::Point location_in_back_button = event->location();
+    views::View::ConvertPointFromWidget(back_button, &location_in_back_button);
+    if (back_button->HitTestPoint(location_in_back_button))
+      return;
+  }
+
+  aura::Window* window = view_->GetWidget()->GetNativeView()->parent();
+  if (window->Contains(target))
+    return;
+
+  // Try to close an open folder window: return if an open folder view was
+  // closed successfully.
+  if (presenter_->HandleCloseOpenFolder())
+    return;
+
+  if (!Shell::Get()->IsInTabletMode()) {
+    // Do not dismiss the app list if the event is targeting shelf area
+    // containing app icons.
+    if (target == shelf->hotseat_widget()->GetNativeWindow() &&
+        shelf->hotseat_widget()->EventTargetsShelfView(*event)) {
+      return;
+    }
+
+    // Don't dismiss the auto-hide shelf if event happened in status area. Then
+    // the event can still be propagated.
+    const aura::Window* status_window =
+        shelf->shelf_widget()->status_area_widget()->GetNativeWindow();
+    if (status_window && status_window->Contains(target)) {
+      auto shelf_visibility_lock =
+          std::make_unique<ShelfLayoutManager::ScopedVisibilityLock>(
+              shelf->shelf_layout_manager());
+
+      // Use a task runner to delete the |shelf_visibility_lock| and update the
+      // shelf visibility after the current event has been handled by the shelf.
+      // This is important for the case where dismissing the app list might hide
+      // the shelf, which would stop the shelf from handling the event.
+      // TODO(crbug.com/1186479): Investigate whether there is a better way to
+      // do this, instead of using a task runner here.
+      base::ThreadTaskRunnerHandle::Get()->DeleteSoon(
+          FROM_HERE, std::move(shelf_visibility_lock));
+    }
+
+    // Record the current AppListViewState to be used later for metrics. The
+    // AppListViewState will change on app launch, so this will record the
+    // AppListViewState before the app was launched.
+    controller_->RecordAppListState();
+    presenter_->Dismiss(event->time_stamp());
+  }
+}
+
+}  // namespace ash
diff --git a/ash/app_list/app_list_presenter_event_filter.h b/ash/app_list/app_list_presenter_event_filter.h
new file mode 100644
index 0000000..2f537550
--- /dev/null
+++ b/ash/app_list/app_list_presenter_event_filter.h
@@ -0,0 +1,48 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_APP_LIST_APP_LIST_PRESENTER_EVENT_FILTER_H_
+#define ASH_APP_LIST_APP_LIST_PRESENTER_EVENT_FILTER_H_
+
+#include "ash/ash_export.h"
+#include "ui/events/event_handler.h"
+
+namespace ui {
+class LocatedEvent;
+}  // namespace ui
+
+namespace ash {
+
+class AppListControllerImpl;
+class AppListPresenterImpl;
+class AppListView;
+
+// Listens for mouse clicks and taps outside the app list to close the UI when
+// necessary. Used by the peeking/fullscreen launcher.
+class ASH_EXPORT AppListPresenterEventFilter : public ui::EventHandler {
+ public:
+  AppListPresenterEventFilter(AppListControllerImpl* controller,
+                              AppListPresenterImpl* presenter,
+                              AppListView* view);
+  AppListPresenterEventFilter(const AppListPresenterEventFilter&) = delete;
+  AppListPresenterEventFilter& operator=(const AppListPresenterEventFilter&) =
+      delete;
+  ~AppListPresenterEventFilter() override;
+
+  // ui::EventHandler overrides:
+  void OnMouseEvent(ui::MouseEvent* event) override;
+  void OnGestureEvent(ui::GestureEvent* event) override;
+  void OnKeyEvent(ui::KeyEvent* event) override;
+
+ private:
+  void ProcessLocatedEvent(ui::LocatedEvent* event);
+
+  AppListControllerImpl* const controller_;
+  AppListPresenterImpl* const presenter_;
+  AppListView* const view_;
+};
+
+}  // namespace ash
+
+#endif  // ASH_APP_LIST_APP_LIST_PRESENTER_EVENT_FILTER_H_
diff --git a/ash/components/audio/BUILD.gn b/ash/components/audio/BUILD.gn
index 0a6c5ce6..64c29aa 100644
--- a/ash/components/audio/BUILD.gn
+++ b/ash/components/audio/BUILD.gn
@@ -16,6 +16,7 @@
     "//components/prefs",
     "//media/base:video_facing",
     "//services/media_session/public/mojom",
+    "//ui/events/devices",
   ]
   sources = [
     "audio_device.cc",
diff --git a/ash/components/audio/DEPS b/ash/components/audio/DEPS
index 7bd3662b..35a2491 100644
--- a/ash/components/audio/DEPS
+++ b/ash/components/audio/DEPS
@@ -8,5 +8,6 @@
   "+media",
   "+mojo/public/cpp/bindings",
   "+services/media_session/public",
+  "+ui/events/devices",
   "+testing",
 ]
diff --git a/ash/components/audio/cras_audio_handler.cc b/ash/components/audio/cras_audio_handler.cc
index 0c751e4..e850672b 100644
--- a/ash/components/audio/cras_audio_handler.cc
+++ b/ash/components/audio/cras_audio_handler.cc
@@ -61,6 +61,13 @@
   return false;
 }
 
+// Gets the current state of the microphone mute switch. If the switch is on,
+// cras will be kept in the muted state. The switch disables the internal audio
+// input.
+bool IsMicrophoneMuteSwitchOn() {
+  return ui::MicrophoneMuteSwitchMonitor::Get()->microphone_mute_switch_on();
+}
+
 }  // namespace
 
 CrasAudioHandler::AudioObserver::AudioObserver() = default;
@@ -315,6 +322,14 @@
   CrasAudioClient::Get()->SetPlayerPosition(current_position);
 }
 
+void CrasAudioHandler::OnMicrophoneMuteSwitchValueChanged(bool muted) {
+  input_muted_by_microphone_mute_switch_ = muted;
+  SetInputMute(muted);
+
+  for (auto& observer : observers_)
+    observer.OnInputMutedByMicrophoneMuteSwitchChanged(muted);
+}
+
 void CrasAudioHandler::AddAudioObserver(AudioObserver* observer) {
   observers_.AddObserver(observer);
 }
@@ -641,9 +656,13 @@
 }
 
 void CrasAudioHandler::SetInputMute(bool mute_on) {
+  const bool old_mute_on = input_mute_on_;
   SetInputMuteInternal(mute_on);
-  for (auto& observer : observers_)
-    observer.OnInputMuteChanged(input_mute_on_);
+
+  if (old_mute_on != input_mute_on_) {
+    for (auto& observer : observers_)
+      observer.OnInputMuteChanged(input_mute_on_);
+  }
 }
 
 void CrasAudioHandler::SetActiveDevice(const AudioDevice& active_device,
@@ -752,6 +771,8 @@
   DCHECK(CrasAudioClient::Get());
   CrasAudioClient::Get()->AddObserver(this);
   audio_pref_handler_->AddAudioPrefObserver(this);
+  ui::MicrophoneMuteSwitchMonitor::Get()->AddObserver(this);
+
   BindMediaControllerObserver();
   InitializeAudioState();
   // Unittest may not have the task runner for the current thread.
@@ -767,6 +788,7 @@
   DCHECK(CrasAudioClient::Get());
   CrasAudioClient::Get()->RemoveObserver(this);
   audio_pref_handler_->RemoveAudioPrefObserver(this);
+  ui::MicrophoneMuteSwitchMonitor::Get()->RemoveObserver(this);
 
   DCHECK(g_cras_audio_handler);
   g_cras_audio_handler = nullptr;
@@ -1039,6 +1061,10 @@
         base::BindOnce(&CrasAudioHandler::HandleGetDeprioritizeBtWbsMic,
                        weak_ptr_factory_.GetWeakPtr()));
   }
+
+  input_muted_by_microphone_mute_switch_ = IsMicrophoneMuteSwitchOn();
+  if (input_muted_by_microphone_mute_switch_)
+    SetInputMute(true);
 }
 
 void CrasAudioHandler::ApplyAudioPolicy() {
@@ -1114,6 +1140,13 @@
 }
 
 void CrasAudioHandler::SetInputMuteInternal(bool mute_on) {
+  // Do not allow unmuting the device if hardware microphone mute switch is on.
+  // The switch disables internal microphone, and cras audio handler is expected
+  // to keep system wide cras mute on while the switch is toggled (which should
+  // ensure non-internal audio input devices are kept muted).
+  if (!mute_on && input_muted_by_microphone_mute_switch_)
+    return;
+
   input_mute_on_ = mute_on;
   CrasAudioClient::Get()->SetInputMute(mute_on);
 }
diff --git a/ash/components/audio/cras_audio_handler.h b/ash/components/audio/cras_audio_handler.h
index 7f3a8d66..07a54ed1 100644
--- a/ash/components/audio/cras_audio_handler.h
+++ b/ash/components/audio/cras_audio_handler.h
@@ -30,6 +30,7 @@
 #include "mojo/public/cpp/bindings/remote.h"
 #include "services/media_session/public/mojom/media_controller.mojom.h"
 #include "services/media_session/public/mojom/media_session.mojom.h"
+#include "ui/events/devices/microphone_mute_switch_monitor.h"
 
 namespace base {
 class SingleThreadTaskRunner;
@@ -48,6 +49,7 @@
 // browser main thread.
 class COMPONENT_EXPORT(ASH_COMPONENTS_AUDIO) CrasAudioHandler
     : public chromeos::CrasAudioClient::Observer,
+      public ui::MicrophoneMuteSwitchMonitor::Observer,
       public AudioPrefObserver,
       public media::VideoCaptureObserver,
       public media_session::mojom::MediaControllerObserver {
@@ -164,6 +166,9 @@
   void MediaSessionPositionChanged(
       const base::Optional<media_session::MediaPosition>& position) override;
 
+  // ui::MicrophoneMuteSwitchMonitor::Observer:
+  void OnMicrophoneMuteSwitchValueChanged(bool muted) override;
+
   // Adds an audio observer.
   void AddAudioObserver(AudioObserver* observer);
 
diff --git a/ash/components/audio/cras_audio_handler_unittest.cc b/ash/components/audio/cras_audio_handler_unittest.cc
index 9284514..6aef2ace 100644
--- a/ash/components/audio/cras_audio_handler_unittest.cc
+++ b/ash/components/audio/cras_audio_handler_unittest.cc
@@ -4265,4 +4265,56 @@
   ChangeAudioNodes(audio_nodes);
 }
 
+TEST_P(CrasAudioHandlerTest, MicrophoneMuteHwSwitchMutesInput) {
+  // Set up initial input audio devices, with internal mic and mic jack.
+  AudioNodeList audio_nodes = GenerateAudioNodeList({kInternalMic, kMicJack});
+  SetUpCrasAudioHandler(audio_nodes);
+
+  // Simulate hw microphone mute switch toggle.
+  ui::MicrophoneMuteSwitchMonitor::Get()->SetMicrophoneMuteSwitchValue(
+      /*muted=*/true);
+
+  // Verify the input is muted, OnInputMuteChanged event is fired.
+  EXPECT_TRUE(cras_audio_handler_->IsInputMuted());
+  EXPECT_EQ(1, test_observer_->input_mute_changed_count());
+
+  // Unmuting input while the hw mute switch is on should fail.
+  cras_audio_handler_->SetInputMute(false);
+
+  EXPECT_TRUE(cras_audio_handler_->IsInputMuted());
+  EXPECT_EQ(1, test_observer_->input_mute_changed_count());
+
+  // Verify the input is unmuted if the hw mute switch is toggled again.
+  ui::MicrophoneMuteSwitchMonitor::Get()->SetMicrophoneMuteSwitchValue(
+      /*muted=*/false);
+  EXPECT_FALSE(cras_audio_handler_->IsInputMuted());
+  EXPECT_EQ(2, test_observer_->input_mute_changed_count());
+}
+
+TEST_P(CrasAudioHandlerTest, MicrophoneMuteSwitchToggledBeforeHandlerSetup) {
+  // Simulate hw microphone mute switch toggle.
+  ui::MicrophoneMuteSwitchMonitor::Get()->SetMicrophoneMuteSwitchValue(
+      /*muted=*/true);
+
+  // Set up initial input audio devices, with internal mic and mic jack.
+  AudioNodeList audio_nodes = GenerateAudioNodeList({kInternalMic, kMicJack});
+  SetUpCrasAudioHandler(audio_nodes);
+
+  // Verify the input is muted, OnInputMuteChanged event is fired.
+  EXPECT_TRUE(cras_audio_handler_->IsInputMuted());
+  EXPECT_EQ(0, test_observer_->input_mute_changed_count());
+
+  // Unmuting input while the hw mute switch is on should fail.
+  cras_audio_handler_->SetInputMute(false);
+
+  EXPECT_TRUE(cras_audio_handler_->IsInputMuted());
+  EXPECT_EQ(0, test_observer_->input_mute_changed_count());
+
+  // Verify the input is unmuted if the hw mute switch is toggled again.
+  ui::MicrophoneMuteSwitchMonitor::Get()->SetMicrophoneMuteSwitchValue(
+      /*muted=*/false);
+  EXPECT_FALSE(cras_audio_handler_->IsInputMuted());
+  EXPECT_EQ(1, test_observer_->input_mute_changed_count());
+}
+
 }  // namespace ash
diff --git a/ash/content/common/resources/navigation_selector.js b/ash/content/common/resources/navigation_selector.js
index 581310b..e5a92f2 100644
--- a/ash/content/common/resources/navigation_selector.js
+++ b/ash/content/common/resources/navigation_selector.js
@@ -58,6 +58,7 @@
       selectedItem: {
         type: Object,
         value: null,
+        observer: 'updateCurrentSelection_',
         notify: true,
       },
 
@@ -77,7 +78,6 @@
    */
   onSelected_(e) {
     this.selectedItem = e.model.item.selectorItem;
-    this.updateCurrentSelection_();
   }
 
   /**
@@ -86,7 +86,6 @@
    */
   onNestedSelected_(e) {
     this.selectedItem = e.model.item;
-    this.updateCurrentSelection_();
   }
 
   /** @private */
diff --git a/ash/content/common/resources/navigation_view_panel.js b/ash/content/common/resources/navigation_view_panel.js
index a681a85..1496ac3 100644
--- a/ash/content/common/resources/navigation_view_panel.js
+++ b/ash/content/common/resources/navigation_view_panel.js
@@ -61,6 +61,16 @@
     });
 
     this.push('menuItems_', menuItem);
+    // Set the initial default page, if the first entry is a collapsible entry
+    // the initial page is the first sub menu item. Otherwise, the first entry
+    // is the first menu item.
+    if (!this.selectedItem) {
+      if (property.isCollapsible) {
+        this.selectedItem = property.subMenuItems[0];
+      } else {
+        this.selectedItem = item;
+      }
+    }
   }
 
   /** @private */
diff --git a/ash/host/ash_window_tree_host_platform_unittest.cc b/ash/host/ash_window_tree_host_platform_unittest.cc
index 548dcee..553d0ebd 100644
--- a/ash/host/ash_window_tree_host_platform_unittest.cc
+++ b/ash/host/ash_window_tree_host_platform_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "ash/test/ash_test_base.h"
 
+#include "ui/events/devices/stylus_state.h"
 #include "ui/ozone/public/input_controller.h"
 #include "ui/ozone/public/ozone_platform.h"
 
@@ -63,6 +64,11 @@
   void SetTouchpadAcceleration(bool enabled) override {}
   void SetTouchpadScrollAcceleration(bool enabled) override {}
   void SetTapToClickPaused(bool state) override {}
+  void GetStylusSwitchState(GetStylusSwitchStateReply reply) override {
+    // Return that there is no stylus in the garage; this test class
+    // does not need to trigger stylus charging behaviours.
+    std::move(reply).Run(ui::StylusState::REMOVED);
+  }
   void GetTouchDeviceStatus(GetTouchDeviceStatusReply reply) override {
     std::move(reply).Run(std::string());
   }
diff --git a/ash/lock_screen_action/lock_screen_note_display_state_handler.cc b/ash/lock_screen_action/lock_screen_note_display_state_handler.cc
index 4349b139..03be2e7 100644
--- a/ash/lock_screen_action/lock_screen_note_display_state_handler.cc
+++ b/ash/lock_screen_action/lock_screen_note_display_state_handler.cc
@@ -47,9 +47,9 @@
   }
 }
 
-void LockScreenNoteDisplayStateHandler::OnScreenStateChanged(
-    ScreenState screen_state) {
-  if (screen_state != ScreenState::ON &&
+void LockScreenNoteDisplayStateHandler::OnScreenBacklightStateChanged(
+    ScreenBacklightState screen_backlight_state) {
+  if (screen_backlight_state != ScreenBacklightState::ON &&
       note_launch_delayed_until_screen_off_) {
     RunLockScreenNoteLauncher();
   }
@@ -76,7 +76,8 @@
   // been turned off yet - the note should be launched when the pending
   // backlights state is finished (i.e. the screen is turned off).
   if (backlights_forced_off_setter_->backlights_forced_off() &&
-      backlights_forced_off_setter_->GetScreenState() == ScreenState::ON) {
+      backlights_forced_off_setter_->GetScreenBacklightState() ==
+          ScreenBacklightState::ON) {
     note_launch_delayed_until_screen_off_ = true;
     return;
   }
@@ -124,8 +125,8 @@
   // delay between request to force backlights off and screen state getting
   // updated due to that request.
   return backlights_forced_off_setter_->backlights_forced_off() ||
-         backlights_forced_off_setter_->GetScreenState() ==
-             ScreenState::OFF_AUTO;
+         backlights_forced_off_setter_->GetScreenBacklightState() ==
+             ScreenBacklightState::OFF_AUTO;
 }
 
 bool LockScreenNoteDisplayStateHandler::NoteLaunchInProgressOrDelayed() const {
diff --git a/ash/lock_screen_action/lock_screen_note_display_state_handler.h b/ash/lock_screen_action/lock_screen_note_display_state_handler.h
index 7dc6e33..c0482f6 100644
--- a/ash/lock_screen_action/lock_screen_note_display_state_handler.h
+++ b/ash/lock_screen_action/lock_screen_note_display_state_handler.h
@@ -38,7 +38,8 @@
 
   // ScreenBacklightObserver:
   void OnBacklightsForcedOffChanged(bool backlights_forced_off) override;
-  void OnScreenStateChanged(ScreenState screen_state) override;
+  void OnScreenBacklightStateChanged(
+      ScreenBacklightState screen_backlight_state) override;
 
   // If lock screen note action is available, it requests a new lock screen note
   // with launch reason set to stylus eject.
diff --git a/ash/login/ui/login_password_view.cc b/ash/login/ui/login_password_view.cc
index 3010ec0..eaa8777 100644
--- a/ash/login/ui/login_password_view.cc
+++ b/ash/login/ui/login_password_view.cc
@@ -55,8 +55,7 @@
 // tooltip.
 const int kDelayBeforeShowingTooltipMs = 500;
 
-// External padding on the password row and submit button, used for the focus
-// ring.
+// External padding on the submit button, used for the focus ring.
 constexpr const int kBorderForFocusRingDp = 3;
 
 // Spacing between the icons (easy unlock, caps lock, display password) and the
@@ -66,7 +65,7 @@
 
 // Spacing between the password row and the submit button.
 constexpr int kSpacingBetweenPasswordRowAndSubmitButtonDp =
-    8 - 2 * kBorderForFocusRingDp;
+    8 - kBorderForFocusRingDp;
 
 // Size (width/height) of the submit button.
 constexpr int kSubmitButtonContentSizeDp = 32;
@@ -82,7 +81,7 @@
 
 // Width of the password row, placed at the center of the password view
 // (which also contains the submit button).
-constexpr int kPasswordRowWidthDp = 204 + 2 * kBorderForFocusRingDp;
+constexpr int kPasswordRowWidthDp = 204 + kBorderForFocusRingDp;
 
 // Total width of the password view (left margin + password row + spacing +
 // submit button).
@@ -127,8 +126,6 @@
 
 constexpr const int kPasswordRowCornerRadiusDp = 4;
 
-constexpr const int kPasswordRowFocusRingRadiusDp = 6;
-
 // Delay after which the password gets cleared if nothing has been typed. It is
 // only effective if the display password button is shown, as there is no
 // potential security threat otherwise.
@@ -203,26 +200,11 @@
 // and indicators (easy unlock, display password, caps lock enabled).
 class LoginPasswordView::LoginPasswordRow : public views::View {
  public:
-  LoginPasswordRow() : focus_ring_(views::FocusRing::Install(this)) {
-    focus_ring_->SetColor(ShelfConfig::Get()->shelf_focus_border_color());
-    views::InstallRoundRectHighlightPathGenerator(
-        this, gfx::Insets(), kPasswordRowFocusRingRadiusDp);
-
-    focus_ring_->SetHasFocusPredicate([](View* view) {
-      return static_cast<LoginPasswordRow*>(view)->is_highlighted_;
-    });
-
-    SetBorder(views::CreateEmptyBorder(gfx::Insets(kBorderForFocusRingDp)));
-  }
+  LoginPasswordRow() = default;
   ~LoginPasswordRow() override = default;
   LoginPasswordRow(const LoginPasswordRow&) = delete;
   LoginPasswordRow& operator=(const LoginPasswordRow&) = delete;
 
-  void SetHighlight(bool enabled) {
-    is_highlighted_ = enabled;
-    focus_ring_->SchedulePaint();
-  }
-
   // views::View:
   void OnPaint(gfx::Canvas* canvas) override {
     views::View::OnPaint(canvas);
@@ -234,10 +216,6 @@
     canvas->DrawRoundRect(GetContentsBounds(), kPasswordRowCornerRadiusDp,
                           flags);
   }
-
- private:
-  bool is_highlighted_ = false;
-  views::FocusRing* focus_ring_;
 };
 
 // A textfield that selects all text on focus and allows to switch between
@@ -246,8 +224,7 @@
  public:
   LoginTextfield(const LoginPalette& palette,
                  base::RepeatingClosure on_focus_closure,
-                 base::RepeatingClosure on_blur_closure,
-                 base::RepeatingClosure on_tab_focus_closure)
+                 base::RepeatingClosure on_blur_closure)
       : on_focus_closure_(std::move(on_focus_closure)),
         on_blur_closure_(std::move(on_blur_closure)) {
     SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
@@ -276,9 +253,6 @@
   }
 
   void AboutToRequestFocusFromTabTraversal(bool reverse) override {
-    if (on_tab_focus_closure_)
-      on_tab_focus_closure_.Run();
-
     if (!GetText().empty())
       SelectAll(/*reversed=*/false);
   }
@@ -624,7 +598,21 @@
   root_layout->set_main_axis_alignment(
       views::BoxLayout::MainAxisAlignment::kEnd);
 
-  password_row_ = AddChildView(std::make_unique<LoginPasswordRow>());
+  auto* password_row_container =
+      AddChildView(std::make_unique<NonAccessibleView>());
+  // The password row should have the same visible height than the submit
+  // button. Since the login password view has the same height than the submit
+  // button – border included – we need to remove its border.
+  auto* password_row_container_layout =
+      password_row_container->SetLayoutManager(
+          std::make_unique<views::BoxLayout>(
+              views::BoxLayout::Orientation::kVertical,
+              gfx::Insets(kBorderForFocusRingDp, 0)));
+  password_row_container_layout->set_main_axis_alignment(
+      views::BoxLayout::MainAxisAlignment::kCenter);
+
+  password_row_ = password_row_container->AddChildView(
+      std::make_unique<LoginPasswordRow>());
   auto layout = std::make_unique<views::BoxLayout>(
       views::BoxLayout::Orientation::kHorizontal,
       gfx::Insets(0, kInternalHorizontalPaddingPasswordRowDp),
@@ -634,6 +622,9 @@
       views::BoxLayout::CrossAxisAlignment::kCenter);
   auto* layout_ptr = password_row_->SetLayoutManager(std::move(layout));
 
+  // Make the password row fill the view.
+  password_row_container_layout->SetFlexForView(password_row_, 1);
+
   left_icon_ =
       password_row_->AddChildView(std::make_unique<AlternateIconsView>());
   left_icon_->SetLayoutManager(std::make_unique<views::FillLayout>());
@@ -661,11 +652,8 @@
           // Highlight on focus. Remove highlight on blur.
           base::BindRepeating(&LoginPasswordView::SetCapsLockHighlighted,
                               base::Unretained(this), /*highlight=*/true),
-          base::BindRepeating(
-              &LoginPasswordView::RemoveHighlightFromCapsLockAndRow,
-              base::Unretained(this)),
-          base::BindRepeating(&LoginPasswordView::SetPasswordRowHighlighted,
-                              base::Unretained(this), /*highlight=*/true)));
+          base::BindRepeating(&LoginPasswordView::SetCapsLockHighlighted,
+                              base::Unretained(this), /*highlight=*/false)));
   textfield_->set_controller(this);
 
   layout_ptr->SetFlexForView(textfield_container, 1);
@@ -975,13 +963,4 @@
       gfx::CreateVectorIcon(kLockScreenCapsLockIcon, kIconSizeDp, color));
 }
 
-void LoginPasswordView::SetPasswordRowHighlighted(bool highlight) {
-  password_row_->SetHighlight(highlight);
-}
-
-void LoginPasswordView::RemoveHighlightFromCapsLockAndRow() {
-  SetCapsLockHighlighted(false);
-  SetPasswordRowHighlighted(false);
-}
-
 }  // namespace ash
diff --git a/ash/login/ui/login_password_view.h b/ash/login/ui/login_password_view.h
index f9f99a34..b3398d7 100644
--- a/ash/login/ui/login_password_view.h
+++ b/ash/login/ui/login_password_view.h
@@ -178,13 +178,6 @@
   // Increases/decreases the contrast of the capslock icon.
   void SetCapsLockHighlighted(bool highlight);
 
-  // Highlight or remove highlight from password row.
-  void SetPasswordRowHighlighted(bool highlight);
-
-  // Remove highlight from caps lock and password row, when textfield looses
-  // focus.
-  void RemoveHighlightFromCapsLockAndRow();
-
   // Needs to be true in order for SubmitPassword to be ran. Returns true if the
   // textfield is not empty or if |enabled_on_empty_password| is true.
   bool IsPasswordSubmittable();
diff --git a/ash/public/cpp/app_list/app_list_metrics.h b/ash/public/cpp/app_list/app_list_metrics.h
index ca932db..0ae22fb2 100644
--- a/ash/public/cpp/app_list/app_list_metrics.h
+++ b/ash/public/cpp/app_list/app_list_metrics.h
@@ -92,8 +92,9 @@
   REMOTE_APP,
   // A Borealis App Result.
   BOREALIS_APP,
-  // A Help App (aka Explore) Result.
-  HELP_APP,
+  // A Help App (aka Explore) Result. For default or help results. There are
+  // different search result types for Updates and Discover.
+  HELP_APP_DEFAULT,
   // A result from omnibox for query suggestion.
   OMNIBOX_SEARCH_SUGGEST_ENTITY,
   // A result from omnibox for suggested navigation.
@@ -106,6 +107,10 @@
   FILE_SEARCH,
   // A Drive file search result.
   DRIVE_SEARCH,
+  // A Help App result about the "What's new" (Updates) page.
+  HELP_APP_UPDATES,
+  // A Help App result about the "Discover" page.
+  HELP_APP_DISCOVER,
   // Boundary is always last.
   SEARCH_RESULT_TYPE_BOUNDARY
 };
diff --git a/ash/public/cpp/screen_backlight.h b/ash/public/cpp/screen_backlight.h
index f803afd8..0ced188 100644
--- a/ash/public/cpp/screen_backlight.h
+++ b/ash/public/cpp/screen_backlight.h
@@ -24,8 +24,8 @@
   virtual void AddObserver(ScreenBacklightObserver* observer) = 0;
   virtual void RemoveObserver(ScreenBacklightObserver* observer) = 0;
 
-  // Returns current system screen state.
-  virtual ScreenState GetScreenState() const = 0;
+  // Returns current system screen backlight state.
+  virtual ScreenBacklightState GetScreenBacklightState() const = 0;
 
  protected:
   ScreenBacklight();
diff --git a/ash/public/cpp/screen_backlight_observer.h b/ash/public/cpp/screen_backlight_observer.h
index 5a28ac8..e2e7fb0 100644
--- a/ash/public/cpp/screen_backlight_observer.h
+++ b/ash/public/cpp/screen_backlight_observer.h
@@ -19,8 +19,9 @@
   // starts forcing backlights off.
   virtual void OnBacklightsForcedOffChanged(bool backlights_forced_off) {}
 
-  // Called when the screen state change is detected.
-  virtual void OnScreenStateChanged(ScreenState screen_state) {}
+  // Called when the screen backlight state change is detected.
+  virtual void OnScreenBacklightStateChanged(
+      ScreenBacklightState screen_state) {}
 };
 
 }  // namespace ash
diff --git a/ash/public/cpp/screen_backlight_type.h b/ash/public/cpp/screen_backlight_type.h
index 60e3f55..5239686 100644
--- a/ash/public/cpp/screen_backlight_type.h
+++ b/ash/public/cpp/screen_backlight_type.h
@@ -7,9 +7,9 @@
 
 namespace ash {
 
-// Screen state as communicated by D-Bus signals from powerd about backlight
-// brightness changes.
-enum class ScreenState {
+// Screen backlight state as communicated by D-Bus signals from powerd about
+// backlight brightness changes.
+enum class ScreenBacklightState {
   // The screen is on.
   ON,
   // The screen is off.
diff --git a/ash/shortcut_viewer/keyboard_shortcut_viewer_metadata.cc b/ash/shortcut_viewer/keyboard_shortcut_viewer_metadata.cc
index 46110f1..00d00a1 100644
--- a/ash/shortcut_viewer/keyboard_shortcut_viewer_metadata.cc
+++ b/ash/shortcut_viewer/keyboard_shortcut_viewer_metadata.cc
@@ -167,7 +167,8 @@
   return l10n_util::GetStringUTF16(msg_id);
 }
 
-std::u16string GetStringForKeyboardCode(ui::KeyboardCode key_code) {
+std::u16string GetStringForKeyboardCode(ui::KeyboardCode key_code,
+                                        bool remap_positional_key) {
   const base::Optional<std::u16string> key_label =
       GetSpecialStringForKeyboardCode(key_code);
   if (key_label)
@@ -185,7 +186,8 @@
   // normally in the loop below. For the positional keys, the |DomCode| is
   // then mapped to the |DomKey| in the current layout which represents the
   // glyph/character that appears on the key (and usually when typed).
-  if (::features::IsImprovedKeyboardShortcutsEnabled()) {
+  if (remap_positional_key &&
+      ::features::IsImprovedKeyboardShortcutsEnabled()) {
     ui::DomCode dom_code =
         ui::KeycodeConverter::MapUSPositionalShortcutKeyToDomCode(key_code);
     if (dom_code != ui::DomCode::NONE) {
diff --git a/ash/shortcut_viewer/keyboard_shortcut_viewer_metadata.h b/ash/shortcut_viewer/keyboard_shortcut_viewer_metadata.h
index 5bb6803a..a51e774 100644
--- a/ash/shortcut_viewer/keyboard_shortcut_viewer_metadata.h
+++ b/ash/shortcut_viewer/keyboard_shortcut_viewer_metadata.h
@@ -31,9 +31,17 @@
 // Returns the string of a DomKey for a given VKEY. VKEY needs to be mapped to
 // a physical key |dom_code| and then the |dom_code| needs to be mapped to a
 // meaning or character of |dom_key| based on the corresponding keyboard layout.
-// Returns empty string if the |dom_key| IsDeadKey or has no mapped meaning or
-// character.
-std::u16string GetStringForKeyboardCode(ui::KeyboardCode key_code);
+//
+// For shortcuts based on keys that use positional mapping, eg. plus, minus,
+// left/right bracket, comma, period, or slash the VKEY is mapped to the
+// glyph on the key with the same physical position as the US layout. This
+// remapping can be disabled by passing false to |remap_positional_key|. This
+// is currently used for the 2 browser shortcuts that use these keys but are
+// not remapped (page zoom in/out).
+//
+// Returns empty string if the |dom_key| has no mapped meaning or character.
+std::u16string GetStringForKeyboardCode(ui::KeyboardCode key_code,
+                                        bool remap_positional_key = true);
 
 // Certain punctuation is not verbalized by ChromeVox, i.e. ".". So, whenever
 // one of these is used in a keyboard shortcut, need to set the accessible name
diff --git a/ash/shortcut_viewer/views/keyboard_shortcut_item_view.cc b/ash/shortcut_viewer/views/keyboard_shortcut_item_view.cc
index d74676c..34e84d76 100644
--- a/ash/shortcut_viewer/views/keyboard_shortcut_item_view.cc
+++ b/ash/shortcut_viewer/views/keyboard_shortcut_item_view.cc
@@ -85,7 +85,24 @@
                  ->emplace(key_code, GetStringForKeyboardCode(key_code))
                  .first;
     }
-    const std::u16string& dom_key_string = iter->second;
+
+    // Get the string for the |DomKey|.
+    std::u16string dom_key_string = iter->second;
+
+    // There are two existing browser shortcuts which should not be
+    // positionally remapped, these are manually overridden here. When
+    // this app is deprecated, the new shortcut app will source the shortcut
+    // data directly from ash or the browser and will not remap the browser
+    // set. Since they are duplicated and intermixed in this app they need
+    // to be explicitly omitted.
+    const bool dont_remap_position =
+        item.description_message_id == IDS_KSV_DESCRIPTION_IDC_ZOOM_PLUS ||
+        item.description_message_id == IDS_KSV_DESCRIPTION_IDC_ZOOM_MINUS;
+    if (dont_remap_position) {
+      dom_key_string =
+          GetStringForKeyboardCode(key_code, /*remap_positional_key=*/false);
+    }
+
     // If the |key_code| has no mapped |dom_key_string|, we use alternative
     // string to indicate that the shortcut is not supported by current keyboard
     // layout.
@@ -95,11 +112,11 @@
       has_invalid_dom_key = true;
       break;
     }
-    replacement_strings.push_back(dom_key_string);
 
     std::u16string accessible_name = GetAccessibleNameForKeyboardCode(key_code);
     accessible_names.push_back(accessible_name.empty() ? dom_key_string
                                                        : accessible_name);
+    replacement_strings.push_back(std::move(dom_key_string));
   }
 
   int shortcut_message_id;
diff --git a/ash/system/holding_space/holding_space_tray_unittest.cc b/ash/system/holding_space/holding_space_tray_unittest.cc
index 12b69195..5aab4597 100644
--- a/ash/system/holding_space/holding_space_tray_unittest.cc
+++ b/ash/system/holding_space/holding_space_tray_unittest.cc
@@ -2490,8 +2490,9 @@
   testing::Mock::VerifyAndClearExpectations(client());
 }
 
+// TODO(crbug.com/1208501): Fix flakes and re-enable.
 // Verifies that the holding space tray animates in and out as expected.
-TEST_F(HoldingSpaceTrayTest, EnterAndExitAnimations) {
+TEST_F(HoldingSpaceTrayTest, DISABLED_EnterAndExitAnimations) {
   ui::ScopedAnimationDurationScaleMode scoped_animation_duration_scale_mode(
       ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
 
diff --git a/ash/system/network/network_list_view.cc b/ash/system/network/network_list_view.cc
index 67e018f..cfebefe 100644
--- a/ash/system/network/network_list_view.cc
+++ b/ash/system/network/network_list_view.cc
@@ -131,40 +131,37 @@
 
 // Returns color for cellular network item text label.
 SkColor GetCellularNetworkPrimaryTextColor(const NetworkInfo& info) {
-  SkColor text_label_primary_color =
-      AshColorProvider::Get()->GetContentLayerColor(
-          AshColorProvider::ContentLayerType::kTextColorPrimary);
-
-  // When inihibited or when SIM is locked and user is not logged in, network
-  // row is disabled, return disabled color.
-  if (info.inhibited ||
-      (info.sim_locked &&
-       !Shell::Get()->session_controller()->IsActiveUserSessionStarted())) {
-    return AshColorProvider::GetDisabledColor(text_label_primary_color);
-  }
-
-  return text_label_primary_color;
+  return AshColorProvider::Get()->GetContentLayerColor(
+      AshColorProvider::ContentLayerType::kTextColorPrimary);
 }
 
 // Returns color for cellular network item sub text label.
 SkColor GetCellularNetworkSubTextColor(const NetworkInfo& info) {
-  if (info.inhibited) {
-    return AshColorProvider::GetDisabledColor(
-        AshColorProvider::Get()->GetContentLayerColor(
-            AshColorProvider::ContentLayerType::kTextColorPositive));
+  return AshColorProvider::Get()->GetContentLayerColor(
+      AshColorProvider::ContentLayerType::kTextColorWarning);
+}
+
+// Updates the cellular list item's label text colors to disabled if the item is
+// disabled.
+void SetupCellularListItem(HoverHighlightView* view, const NetworkInfo& info) {
+  //  The network row is disabled if inhibited or when SIM is locked and user is
+  //  not logged in.
+  if (!info.inhibited &&
+      !(info.sim_locked &&
+        !Shell::Get()->session_controller()->IsActiveUserSessionStarted())) {
+    return;
   }
 
-  SkColor text_label_warning_color =
-      AshColorProvider::Get()->GetContentLayerColor(
-          AshColorProvider::ContentLayerType::kTextColorWarning);
-
-  // If user is not logged in network row is disabled, return disabled color.
-  if (info.sim_locked &&
-      !Shell::Get()->session_controller()->IsActiveUserSessionStarted()) {
-    return AshColorProvider::GetDisabledColor(text_label_warning_color);
+  if (view->text_label()) {
+    SkColor primary_text_color = view->text_label()->GetEnabledColor();
+    view->text_label()->SetEnabledColor(
+        AshColorProvider::GetDisabledColor(primary_text_color));
   }
-
-  return text_label_warning_color;
+  if (view->sub_text_label()) {
+    SkColor sub_text_color = view->sub_text_label()->GetEnabledColor();
+    view->sub_text_label()->SetEnabledColor(
+        AshColorProvider::GetDisabledColor(sub_text_color));
+  }
 }
 
 void SetupCellularListItemWithSubtext(HoverHighlightView* view,
@@ -176,6 +173,7 @@
   }
   view->SetSubText(l10n_util::GetStringUTF16(cellular_subtext_message_id));
   view->sub_text_label()->SetEnabledColor(GetCellularNetworkSubTextColor(info));
+  SetupCellularListItem(view, info);
 }
 
 bool ComputeNetworkDisabledProperty(const NetworkStatePropertiesPtr& network,
@@ -488,10 +486,15 @@
   int cellular_subtext_message_id = GetCellularNetworkSubText(info);
   if (cellular_subtext_message_id) {
     SetupCellularListItemWithSubtext(view, info, cellular_subtext_message_id);
-  } else if (StateIsConnected(info.connection_state)) {
-    SetupConnectedScrollListItem(view);
-  } else if (info.connection_state == ConnectionStateType::kConnecting) {
-    SetupConnectingScrollListItem(view);
+  } else {
+    if (StateIsConnected(info.connection_state)) {
+      SetupConnectedScrollListItem(view);
+    } else if (info.connection_state == ConnectionStateType::kConnecting) {
+      SetupConnectingScrollListItem(view);
+    }
+    if (NetworkTypeMatchesType(info.type, NetworkType::kCellular)) {
+      SetupCellularListItem(view, info);
+    }
   }
   view->SetTooltipText(info.tooltip);
 
diff --git a/ash/system/power/backlights_forced_off_setter.cc b/ash/system/power/backlights_forced_off_setter.cc
index bb54110..ecd86ec 100644
--- a/ash/system/power/backlights_forced_off_setter.cc
+++ b/ash/system/power/backlights_forced_off_setter.cc
@@ -38,8 +38,9 @@
   observers_.RemoveObserver(observer);
 }
 
-ScreenState BacklightsForcedOffSetter::GetScreenState() const {
-  return screen_state_;
+ScreenBacklightState BacklightsForcedOffSetter::GetScreenBacklightState()
+    const {
+  return screen_backlight_state_;
 }
 
 std::unique_ptr<ScopedBacklightsForcedOff>
@@ -59,21 +60,22 @@
       change.cause() ==
       power_manager::BacklightBrightnessChange_Cause_USER_REQUEST;
 
-  const ScreenState old_state = screen_state_;
+  const ScreenBacklightState old_state = screen_backlight_state_;
   if (change.percent() > 0.0)
-    screen_state_ = ScreenState::ON;
+    screen_backlight_state_ = ScreenBacklightState::ON;
   else
-    screen_state_ = user_initiated ? ScreenState::OFF : ScreenState::OFF_AUTO;
+    screen_backlight_state_ = user_initiated ? ScreenBacklightState::OFF
+                                             : ScreenBacklightState::OFF_AUTO;
 
-  if (screen_state_ != old_state) {
+  if (screen_backlight_state_ != old_state) {
     for (auto& observer : observers_)
-      observer.OnScreenStateChanged(screen_state_);
+      observer.OnScreenBacklightStateChanged(screen_backlight_state_);
   }
 
   // Disable the touchscreen when the screen is turned off due to inactivity:
   // https://crbug.com/743291
-  if ((screen_state_ == ScreenState::OFF_AUTO) !=
-          (old_state == ScreenState::OFF_AUTO) &&
+  if ((screen_backlight_state_ == ScreenBacklightState::OFF_AUTO) !=
+          (old_state == ScreenBacklightState::OFF_AUTO) &&
       disable_touchscreen_while_screen_off_) {
     UpdateTouchscreenStatus();
   }
@@ -156,10 +158,11 @@
   // kernel blocks wake up events from internal input devices when the screen is
   // off or is in the suspended state.
   // See https://crbug/797411 for more details.
-  const bool disable_touchscreen = backlights_forced_off_.value_or(false) ||
-                                   (screen_state_ == ScreenState::OFF_AUTO &&
-                                    disable_touchscreen_while_screen_off_ &&
-                                    !display::HasExternalTouchscreenDevice());
+  const bool disable_touchscreen =
+      backlights_forced_off_.value_or(false) ||
+      (screen_backlight_state_ == ScreenBacklightState::OFF_AUTO &&
+       disable_touchscreen_while_screen_off_ &&
+       !display::HasExternalTouchscreenDevice());
   Shell::Get()->touch_devices_controller()->SetTouchscreenEnabled(
       !disable_touchscreen, TouchDeviceEnabledSource::GLOBAL);
 }
diff --git a/ash/system/power/backlights_forced_off_setter.h b/ash/system/power/backlights_forced_off_setter.h
index e8a77da..6b869f2 100644
--- a/ash/system/power/backlights_forced_off_setter.h
+++ b/ash/system/power/backlights_forced_off_setter.h
@@ -38,7 +38,7 @@
   // ScreenBacklight:
   void AddObserver(ScreenBacklightObserver* observer) override;
   void RemoveObserver(ScreenBacklightObserver* observer) override;
-  ScreenState GetScreenState() const override;
+  ScreenBacklightState GetScreenBacklightState() const override;
 
   // Forces the backlights off. The backlights will be kept in the forced-off
   // state until all requests have been destroyed.
@@ -76,7 +76,7 @@
 
   // Enables or disables the touchscreen by updating the global touchscreen
   // enabled status. The touchscreen is disabled when backlights are forced off
-  // or |screen_state_| is OFF_AUTO.
+  // or |screen_backlight_state_| is OFF_AUTO.
   void UpdateTouchscreenStatus();
 
   // Controls whether the touchscreen is disabled when the screen is turned off
@@ -87,7 +87,7 @@
   base::Optional<bool> backlights_forced_off_;
 
   // Current screen state.
-  ScreenState screen_state_ = ScreenState::ON;
+  ScreenBacklightState screen_backlight_state_ = ScreenBacklightState::ON;
 
   // Number of active backlights forced off requests.
   int active_backlights_forced_off_count_ = 0;
diff --git a/ash/system/power/power_button_controller.cc b/ash/system/power/power_button_controller.cc
index b29e47b..e111771 100644
--- a/ash/system/power/power_button_controller.cc
+++ b/ash/system/power/power_button_controller.cc
@@ -408,8 +408,9 @@
   DismissMenu();
 }
 
-void PowerButtonController::OnScreenStateChanged(ScreenState screen_state) {
-  if (screen_state != ScreenState::ON)
+void PowerButtonController::OnScreenBacklightStateChanged(
+    ScreenBacklightState screen_backlight_state) {
+  if (screen_backlight_state != ScreenBacklightState::ON)
     DismissMenu();
 }
 
diff --git a/ash/system/power/power_button_controller.h b/ash/system/power/power_button_controller.h
index b2831b1..3a20c0d 100644
--- a/ash/system/power/power_button_controller.h
+++ b/ash/system/power/power_button_controller.h
@@ -143,7 +143,8 @@
 
   // BacklightsForcedOffSetter::Observer:
   void OnBacklightsForcedOffChanged(bool forced_off) override;
-  void OnScreenStateChanged(ScreenState screen_state) override;
+  void OnScreenBacklightStateChanged(
+      ScreenBacklightState screen_backlight_state) override;
 
   // TabletModeObserver:
   void OnTabletModeStarted() override;
diff --git a/ash/system/power/power_button_display_controller.cc b/ash/system/power/power_button_display_controller.cc
index b590f141..6171b604 100644
--- a/ash/system/power/power_button_display_controller.cc
+++ b/ash/system/power/power_button_display_controller.cc
@@ -47,7 +47,8 @@
 }
 
 bool PowerButtonDisplayController::IsScreenOn() const {
-  return backlights_forced_off_setter_->GetScreenState() == ScreenState::ON;
+  return backlights_forced_off_setter_->GetScreenBacklightState() ==
+         ScreenBacklightState::ON;
 }
 
 void PowerButtonDisplayController::SetBacklightsForcedOff(bool forced_off) {
@@ -82,8 +83,8 @@
   send_accessibility_alert_on_backlights_forced_off_change_ = false;
 }
 
-void PowerButtonDisplayController::OnScreenStateChanged(
-    ScreenState screen_state) {
+void PowerButtonDisplayController::OnScreenBacklightStateChanged(
+    ScreenBacklightState screen_backlight_state) {
   screen_state_last_changed_ = tick_clock_->NowTicks();
 }
 
diff --git a/ash/system/power/power_button_display_controller.h b/ash/system/power/power_button_display_controller.h
index 1196160..8721554 100644
--- a/ash/system/power/power_button_display_controller.h
+++ b/ash/system/power/power_button_display_controller.h
@@ -52,7 +52,8 @@
 
   // Overridden from ScreenBacklightObserver:
   void OnBacklightsForcedOffChanged(bool forced_off) override;
-  void OnScreenStateChanged(ScreenState screen_state) override;
+  void OnScreenBacklightStateChanged(
+      ScreenBacklightState screen_backlight_state) override;
 
   // Overridden from chromeos::PowerManagerClient::Observer:
   void SuspendDone(base::TimeDelta sleep_duration) override;
diff --git a/ash/wm/desks/desk_animation_impl.cc b/ash/wm/desks/desk_animation_impl.cc
index 1937c376..caa037d 100644
--- a/ash/wm/desks/desk_animation_impl.cc
+++ b/ash/wm/desks/desk_animation_impl.cc
@@ -138,8 +138,7 @@
   }
 
   // Activate the target desk and take a screenshot.
-  // TODO(crbug.com/1134390): Convert back to DCHECK when the issue is fixed.
-  CHECK_EQ(pending_animators.size(), desk_switch_animators_.size());
+  DCHECK_EQ(pending_animators.size(), desk_switch_animators_.size());
   PrepareDeskForScreenshot(new_ending_desk_index);
   for (auto* animator : pending_animators)
     animator->TakeEndingDeskScreenshot();
diff --git a/ash/wm/overview/overview_animation_state_waiter.cc b/ash/wm/overview/overview_animation_state_waiter.cc
index 04346ce2..f370f6b3 100644
--- a/ash/wm/overview/overview_animation_state_waiter.cc
+++ b/ash/wm/overview/overview_animation_state_waiter.cc
@@ -6,8 +6,6 @@
 
 #include "ash/shell.h"
 #include "ash/wm/overview/overview_controller.h"
-#include "base/threading/sequenced_task_runner_handle.h"
-#include "base/time/time.h"
 
 namespace ash {
 
diff --git a/ash/wm/overview/overview_animation_state_waiter.h b/ash/wm/overview/overview_animation_state_waiter.h
index 02f0b84..6712651 100644
--- a/ash/wm/overview/overview_animation_state_waiter.h
+++ b/ash/wm/overview/overview_animation_state_waiter.h
@@ -9,7 +9,6 @@
 #include "ash/public/cpp/overview_test_api.h"
 #include "ash/wm/overview/overview_observer.h"
 #include "base/callback.h"
-#include "base/macros.h"
 
 namespace ash {
 
@@ -19,10 +18,13 @@
  public:
   // Type of the callback. It receives true when the overview animation finishes
   // properly.
-  typedef base::OnceCallback<void(bool)> DoneCallback;
+  using DoneCallback = base::OnceCallback<void(bool)>;
 
   OverviewAnimationStateWaiter(OverviewAnimationState expected_state,
                                DoneCallback callback);
+  OverviewAnimationStateWaiter(const OverviewAnimationStateWaiter&) = delete;
+  OverviewAnimationStateWaiter& operator=(const OverviewAnimationStateWaiter&) =
+      delete;
   ~OverviewAnimationStateWaiter() override;
 
   // Cancels the ongoing observation of the overview animation and invokes
@@ -36,8 +38,6 @@
 
   OverviewAnimationState expected_state_;
   DoneCallback callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(OverviewAnimationStateWaiter);
 };
 
 }  // namespace ash
diff --git a/ash/wm/splitview/split_view_controller.h b/ash/wm/splitview/split_view_controller.h
index 07a7dde..5674006 100644
--- a/ash/wm/splitview/split_view_controller.h
+++ b/ash/wm/splitview/split_view_controller.h
@@ -97,9 +97,7 @@
   // window and it does not matter. For code that only applies to tablet mode,
   // you may simply use the primary root (see |Shell::GetPrimaryRootWindow|).
   // The user actually can go to the display settings while in tablet mode and
-  // choose extend; we just are not yet trying to support it really well. When
-  // the |ash::features::kMultiDisplayOverviewAndSplitView| feature flag is
-  // disabled, |window| is ignored as there is only one |SplitViewController|.
+  // choose extend; we just are not yet trying to support it really well.
   static SplitViewController* Get(const aura::Window* window);
 
   // The return values of these two functions together indicate what actual
diff --git a/ash/wm/splitview/split_view_utils.h b/ash/wm/splitview/split_view_utils.h
index 51226d5..5009211 100644
--- a/ash/wm/splitview/split_view_utils.h
+++ b/ash/wm/splitview/split_view_utils.h
@@ -127,19 +127,12 @@
 // snapped windows based on the MRU windows snapped states.
 void MaybeRestoreSplitView(bool refresh_snapped_windows);
 
-// Returns true if we allow dragging an overview window to snap to split view in
-// clamshell mode.
-ASH_EXPORT bool IsClamshellSplitViewModeEnabled();
-
-// Checks multi-display support for overview and split view.
-ASH_EXPORT bool AreMultiDisplayOverviewAndSplitViewEnabled();
-
 // Returns true if split view mode is supported.
 ASH_EXPORT bool ShouldAllowSplitView();
 
 // Displays a toast notifying users the application selected for split view is
 // not compatible.
-ASH_EXPORT void ShowAppCannotSnapToast();
+void ShowAppCannotSnapToast();
 
 // Calculates the snap position for a dragged window at |location_in_screen|,
 // ignoring any properties of the window itself. The |root_window| is of the
@@ -151,7 +144,7 @@
 // it's dragged into a suitable edge of the work area of |root_window| (i.e.,
 // |horizontal_edge_inset| if dragged horizontally to snap, or
 // |vertical_edge_inset| if dragged vertically).
-ASH_EXPORT SplitViewController::SnapPosition GetSnapPositionForLocation(
+SplitViewController::SnapPosition GetSnapPositionForLocation(
     aura::Window* root_window,
     const gfx::Point& location_in_screen,
     const base::Optional<gfx::Point>& initial_location_in_screen,
diff --git a/ash/wm/window_cycle/window_cycle_controller_unittest.cc b/ash/wm/window_cycle/window_cycle_controller_unittest.cc
index 1c62d2e..4591bfa 100644
--- a/ash/wm/window_cycle/window_cycle_controller_unittest.cc
+++ b/ash/wm/window_cycle/window_cycle_controller_unittest.cc
@@ -134,8 +134,33 @@
   return offset;
 }
 
+const WindowCycleList* GetCycleList() {
+  return Shell::Get()->window_cycle_controller()->window_cycle_list();
+}
+
 }  // namespace
 
+// Wrapper for WindowCycleList that exposes internal state to test functions.
+class WindowCycleListTestApi {
+ public:
+  explicit WindowCycleListTestApi(const WindowCycleList* cycle_list)
+      : cycle_list_(cycle_list) {}
+  WindowCycleListTestApi(const WindowCycleListTestApi&) = delete;
+  WindowCycleListTestApi& operator=(const WindowCycleListTestApi&) = delete;
+  ~WindowCycleListTestApi() = default;
+
+  const aura::Window::Windows& windows() const { return cycle_list_->windows_; }
+
+  const views::Widget* widget() const { return cycle_list_->cycle_ui_widget_; }
+
+  WindowCycleView* cycle_view() const { return cycle_list_->cycle_view_; }
+
+  int current_index() const { return cycle_list_->current_index_; }
+
+ private:
+  const WindowCycleList* const cycle_list_;
+};
+
 using aura::Window;
 using aura::test::CreateTestWindowWithId;
 using aura::test::TestWindowDelegate;
@@ -157,56 +182,35 @@
   }
 
   const aura::Window::Windows GetWindows(WindowCycleController* controller) {
-    return controller->window_cycle_list()->windows();
+    return WindowCycleListTestApi(controller->window_cycle_list()).windows();
   }
 
   const views::Widget* GetWindowCycleListWidget() const {
-    return Shell::Get()
-        ->window_cycle_controller()
-        ->window_cycle_list()
-        ->widget();
+    return WindowCycleListTestApi(GetCycleList()).widget();
   }
 
   const views::View::Views& GetWindowCycleItemViews() const {
-    return Shell::Get()
-        ->window_cycle_controller()
-        ->window_cycle_list()
-        ->GetWindowCycleItemViewsForTesting();
+    return GetCycleList()->GetWindowCycleItemViewsForTesting();
   }
 
   const views::View::Views& GetWindowCycleTabSliderButtons() const {
-    return Shell::Get()
-        ->window_cycle_controller()
-        ->window_cycle_list()
-        ->GetWindowCycleTabSliderButtonsForTesting();
+    return GetCycleList()->GetWindowCycleTabSliderButtonsForTesting();
   }
 
   const views::Label* GetWindowCycleNoRecentItemsLabel() const {
-    return Shell::Get()
-        ->window_cycle_controller()
-        ->window_cycle_list()
-        ->GetWindowCycleNoRecentItemsLabelForTesting();
+    return GetCycleList()->GetWindowCycleNoRecentItemsLabelForTesting();
   }
 
   const aura::Window* GetTargetWindow() const {
-    return Shell::Get()
-        ->window_cycle_controller()
-        ->window_cycle_list()
-        ->GetTargetWindowForTesting();
+    return GetCycleList()->GetTargetWindowForTesting();
   }
 
   bool CycleViewExists() const {
-    return Shell::Get()
-        ->window_cycle_controller()
-        ->window_cycle_list()
-        ->cycle_view_for_testing();
+    return WindowCycleListTestApi(GetCycleList()).cycle_view();
   }
 
   int GetCurrentIndex() const {
-    return Shell::Get()
-        ->window_cycle_controller()
-        ->window_cycle_list()
-        ->current_index_for_testing();
+    return WindowCycleListTestApi(GetCycleList()).current_index();
   }
 
   void CompleteCycling(WindowCycleController* controller) {
@@ -2851,28 +2855,19 @@
   }
 
   const aura::Window::Windows GetWindows(WindowCycleController* controller) {
-    return controller->window_cycle_list()->windows();
+    return WindowCycleListTestApi(controller->window_cycle_list()).windows();
   }
 
   const views::View::Views& GetWindowCycleItemViews() const {
-    return Shell::Get()
-        ->window_cycle_controller()
-        ->window_cycle_list()
-        ->GetWindowCycleItemViewsForTesting();
+    return GetCycleList()->GetWindowCycleItemViewsForTesting();
   }
 
   const views::View::Views& GetWindowCycleTabSliderButtons() const {
-    return Shell::Get()
-        ->window_cycle_controller()
-        ->window_cycle_list()
-        ->GetWindowCycleTabSliderButtonsForTesting();
+    return GetCycleList()->GetWindowCycleTabSliderButtonsForTesting();
   }
 
   const aura::Window* GetTargetWindow() const {
-    return Shell::Get()
-        ->window_cycle_controller()
-        ->window_cycle_list()
-        ->GetTargetWindowForTesting();
+    return GetCycleList()->GetTargetWindowForTesting();
   }
 
   void CompleteCycling(WindowCycleController* controller) {
diff --git a/ash/wm/window_cycle/window_cycle_list.cc b/ash/wm/window_cycle/window_cycle_list.cc
index 88a87fc2..d3672789 100644
--- a/ash/wm/window_cycle/window_cycle_list.cc
+++ b/ash/wm/window_cycle/window_cycle_list.cc
@@ -275,8 +275,8 @@
                         public ui::ImplicitAnimationObserver,
                         public ui::CompositorAnimationObserver {
  public:
-  explicit WindowCycleView(aura::Window* root_window,
-                           const WindowCycleList::WindowList& windows)
+  WindowCycleView(aura::Window* root_window,
+                  const WindowCycleList::WindowList& windows)
       : root_window_(root_window) {
     const bool is_interactive_alt_tab_mode_allowed =
         Shell::Get()
diff --git a/ash/wm/window_cycle/window_cycle_list.h b/ash/wm/window_cycle/window_cycle_list.h
index 1d2acbe..75af85e 100644
--- a/ash/wm/window_cycle/window_cycle_list.h
+++ b/ash/wm/window_cycle/window_cycle_list.h
@@ -100,19 +100,14 @@
     user_did_accept_ = user_did_accept;
   }
 
-  bool HasWindowTargeter() { return !!window_targeter_; }
-
  private:
-  friend class WindowCycleControllerTest;
-  friend class MultiUserWindowCycleControllerTest;
-  friend class InteractiveWindowCycleListGestureHandlerTest;
   friend class ModeSelectionWindowCycleControllerTest;
+  friend class MultiUserWindowCycleControllerTest;
+  friend class WindowCycleListTestApi;
+  friend class WindowCycleControllerTest;
 
   static void DisableInitialDelayForTesting();
 
-  const WindowList& windows() const { return windows_; }
-  const views::Widget* widget() const { return cycle_ui_widget_; }
-
   // aura::WindowObserver:
   // There is a chance a window is destroyed, for example by JS code. We need to
   // take care of that even if it is not intended for the user to close a window
@@ -166,10 +161,6 @@
   // Returns whether the cycle view is animating.
   bool IsCycleViewAnimatingForTesting() const;
 
-  WindowCycleView* cycle_view_for_testing() const { return cycle_view_; }
-
-  int current_index_for_testing() const { return current_index_; }
-
   // List of weak pointers to windows to use while cycling with the keyboard.
   // List is built when the user initiates the gesture (i.e. hits alt-tab the
   // first time) and is emptied when the gesture is complete (i.e. releases the
diff --git a/ash/wm/window_finder.cc b/ash/wm/window_finder.cc
index 3abe8e0..0bd49b0 100644
--- a/ash/wm/window_finder.cc
+++ b/ash/wm/window_finder.cc
@@ -53,14 +53,15 @@
     const gfx::Point& screen_point,
     aura::Window* window,
     aura::WindowTargeter* targeter,
-    const std::set<aura::Window*> ignore) {
+    const std::set<aura::Window*>& ignore) {
   if (!window->IsVisible())
     return nullptr;
 
-  if (window->GetId() == ash::kShellWindowId_PhantomWindow ||
-      window->GetId() == ash::kShellWindowId_OverlayContainer ||
-      window->GetId() == ash::kShellWindowId_MouseCursorContainer)
+  if (window->GetId() == kShellWindowId_PhantomWindow ||
+      window->GetId() == kShellWindowId_OverlayContainer ||
+      window->GetId() == kShellWindowId_MouseCursorContainer) {
     return nullptr;
+  }
 
   if (IsTopLevelWindow(window)) {
     if (IsWindowTargeted(window, screen_point, targeter))
@@ -88,12 +89,11 @@
 aura::Window* GetToplevelWindowInOverviewAtPoint(
     const gfx::Point& screen_point,
     const std::set<aura::Window*>& ignore) {
-  ash::OverviewController* overview_controller =
-      ash::Shell::Get()->overview_controller();
+  OverviewController* overview_controller = Shell::Get()->overview_controller();
   if (!overview_controller->InOverviewSession())
     return nullptr;
 
-  ash::OverviewGrid* grid =
+  OverviewGrid* grid =
       overview_controller->overview_session()->GetGridWithRootWindow(
           window_util::GetRootWindowAt(screen_point));
   if (!grid)
diff --git a/ash/wm/wm_default_layout_manager.cc b/ash/wm/wm_default_layout_manager.cc
index c1bc29b..eff51539 100644
--- a/ash/wm/wm_default_layout_manager.cc
+++ b/ash/wm/wm_default_layout_manager.cc
@@ -4,11 +4,7 @@
 
 #include "ash/wm/wm_default_layout_manager.h"
 
-#include "ash/public/cpp/shell_window_ids.h"
-#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
-#include "ui/wm/core/window_properties.h"
-#include "ui/wm/core/window_util.h"
 
 namespace ash {
 
diff --git a/ash/wm/wm_shadow_controller_delegate.h b/ash/wm/wm_shadow_controller_delegate.h
index 5a92448..fbfcd57 100644
--- a/ash/wm/wm_shadow_controller_delegate.h
+++ b/ash/wm/wm_shadow_controller_delegate.h
@@ -5,7 +5,6 @@
 #ifndef ASH_WM_WM_SHADOW_CONTROLLER_DELEGATE_H_
 #define ASH_WM_WM_SHADOW_CONTROLLER_DELEGATE_H_
 
-#include "base/macros.h"
 #include "ui/wm/core/shadow_controller_delegate.h"
 
 namespace aura {
@@ -16,18 +15,18 @@
 
 // WmShadowControllerDelegate is a delegate for showing the shadow for window
 // management purposes.
-class WmShadowControllerDelegate : public ::wm::ShadowControllerDelegate {
+class WmShadowControllerDelegate : public wm::ShadowControllerDelegate {
  public:
   WmShadowControllerDelegate();
+  WmShadowControllerDelegate(const WmShadowControllerDelegate&) = delete;
+  WmShadowControllerDelegate& operator=(const WmShadowControllerDelegate&) =
+      delete;
   ~WmShadowControllerDelegate() override;
 
-  // ::wm::ShadowControllerDelegate:
+  // wm::ShadowControllerDelegate:
   bool ShouldShowShadowForWindow(const aura::Window* window) override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(WmShadowControllerDelegate);
 };
 
 }  // namespace ash
 
-#endif  // ASH_WM_WM_SHADOW_CONTROLLER_DELEGATE_H_
\ No newline at end of file
+#endif  // ASH_WM_WM_SHADOW_CONTROLLER_DELEGATE_H_
diff --git a/base/callback_helpers.h b/base/callback_helpers.h
index 8ba5e62..20b3436d5 100644
--- a/base/callback_helpers.h
+++ b/base/callback_helpers.h
@@ -116,6 +116,11 @@
 template <typename... Args>
 std::pair<OnceCallback<void(Args...)>, OnceCallback<void(Args...)>>
 SplitOnceCallback(OnceCallback<void(Args...)> callback) {
+  if (!callback) {
+    // Empty input begets two empty outputs.
+    return std::make_pair(OnceCallback<void(Args...)>(),
+                          OnceCallback<void(Args...)>());
+  }
   using Helper = internal::OnceCallbackHolder<Args...>;
   auto wrapped_once = base::BindRepeating(
       &Helper::Run, std::make_unique<Helper>(std::move(callback),
diff --git a/base/callback_helpers_unittest.cc b/base/callback_helpers_unittest.cc
index 2d2853c..87e135b 100644
--- a/base/callback_helpers_unittest.cc
+++ b/base/callback_helpers_unittest.cc
@@ -194,6 +194,20 @@
   EXPECT_EQ(1, count);
 }
 
+TEST(CallbackHelpersTest, SplitOnceCallback_EmptyCallback) {
+  base::OnceCallback<void(int*)> cb = base::NullCallback();
+  EXPECT_FALSE(cb);
+
+  auto split = base::SplitOnceCallback(std::move(cb));
+
+  static_assert(std::is_same<decltype(split),
+                             std::pair<base::OnceCallback<void(int*)>,
+                                       base::OnceCallback<void(int*)>>>::value,
+                "");
+  EXPECT_FALSE(split.first);
+  EXPECT_FALSE(split.second);
+}
+
 TEST(CallbackHelpersTest, SplitOnceCallback_FirstCallback) {
   int count = 0;
   base::OnceCallback<void(int*)> cb =
diff --git a/base/debug/elf_reader.cc b/base/debug/elf_reader.cc
index a3b4684..c0c1fb8 100644
--- a/base/debug/elf_reader.cc
+++ b/base/debug/elf_reader.cc
@@ -191,8 +191,8 @@
 
   // Assume the virtual addresses in the image start at 0, so the offset is
   // from 0 to the actual mapped base address.
-  return static_cast<size_t>(reinterpret_cast<const char*>(elf_mapped_base) -
-                             reinterpret_cast<const char*>(0));
+  return static_cast<size_t>(reinterpret_cast<uintptr_t>(elf_mapped_base) -
+                             reinterpret_cast<uintptr_t>(nullptr));
 }
 
 }  // namespace debug
diff --git a/base/process/process_metrics.cc b/base/process/process_metrics.cc
index d6be93f..e4df342 100644
--- a/base/process/process_metrics.cc
+++ b/base/process/process_metrics.cc
@@ -8,7 +8,7 @@
 // process_metrics.h is a widely included header and its size impacts build
 // time. Try not to raise this limit unless necessary. See
 // https://chromium.googlesource.com/chromium/src/+/HEAD/docs/wmax_tokens.md
-#pragma clang max_tokens_here 400000
+#pragma clang max_tokens_here 405200
 #endif  // defined(OS_LINUX)
 
 #include <utility>
diff --git a/base/values.h b/base/values.h
index 3f8d95a8..98ded4fe 100644
--- a/base/values.h
+++ b/base/values.h
@@ -964,15 +964,16 @@
   void Swap(ListValue* other);
 
   // Iteration.
-  // DEPRECATED, use `GetList()::begin()` instead.
-  iterator begin() { return GetList().begin(); }
-  // DEPRECATED, use `GetList()::end()` instead.
-  iterator end() { return GetList().end(); }
-
-  // DEPRECATED, use `GetList()::begin()` instead.
-  const_iterator begin() const { return GetList().begin(); }
-  // DEPRECATED, use `GetList()::end()` instead.
-  const_iterator end() const { return GetList().end(); }
+  //
+  // ListValue no longer supports iteration. Instead, use GetList() to get the
+  // underlying list:
+  //
+  // for (const auto& entry : list_value.GetList()) {
+  //   ...
+  //
+  // for (auto it = list_value.GetList().begin();
+  //      it != list_value.GetList().end(); ++it) {
+  //   ...
 
   // DEPRECATED, use `Value::Clone()` instead.
   // TODO(crbug.com/646113): Delete this and migrate callsites.
diff --git a/build/config/chromeos/rules.gni b/build/config/chromeos/rules.gni
index c8693bab..7d793e2f 100644
--- a/build/config/chromeos/rules.gni
+++ b/build/config/chromeos/rules.gni
@@ -454,10 +454,6 @@
     # https://source.chromium.org/chromium/chromium/src/+/master:third_party/chromite/scripts/deploy_chrome.py;l=80;drc=86f1234a4be8e9574442e076cdc835897f7bea61
     tast_vars = [ "lacrosDeployedBinary=/usr/local/lacros-chrome" ]
 
-    # Lacros tast tests may have different test expectations based on whether
-    # they're for Chromium or Chrome.
-    tast_vars += [ "lacrosIsChromeBranded=$is_chrome_branded" ]
-
     data_deps = [
       "//chrome",  # Builds the browser.
 
diff --git a/build/config/fuchsia/config.gni b/build/config/fuchsia/config.gni
index 8e9e2be..5a00cc5 100644
--- a/build/config/fuchsia/config.gni
+++ b/build/config/fuchsia/config.gni
@@ -5,7 +5,7 @@
 assert(is_fuchsia)
 
 # Compute the AEMU path.
-aemu_root = "//third_party/aemu-${host_os}-${host_cpu}"
+aemu_root = "//third_party/aemu-${host_os}-${target_cpu}"
 
 # Compute the path to the arch-specific boot image directory.
 boot_image_root = "//third_party/fuchsia-sdk/images/${target_cpu}"
diff --git a/build/config/fuchsia/generate_runner_scripts.gni b/build/config/fuchsia/generate_runner_scripts.gni
index 7fac16f..d9a67521 100644
--- a/build/config/fuchsia/generate_runner_scripts.gni
+++ b/build/config/fuchsia/generate_runner_scripts.gni
@@ -159,8 +159,8 @@
         "//third_party/qemu-${host_os}-${test_host_cpu}/",
       ]
 
-      # Include AEMU for x64 emulator hosts.
-      if (test_host_cpu == "x64") {
+      # Include AEMU for x64 emulator hosts and for arm64 hosts.
+      if (test_host_cpu == "x64" || test_host_cpu == "arm64") {
         data += [ "${aemu_root}/" ]
       }
     }
diff --git a/build/fuchsia/aemu_target.py b/build/fuchsia/aemu_target.py
index 321feb5b..249fbf0 100644
--- a/build/fuchsia/aemu_target.py
+++ b/build/fuchsia/aemu_target.py
@@ -34,9 +34,6 @@
           self).__init__(out_dir, target_cpu, system_log_file, cpu_cores,
                          require_kvm, ram_size_mb, fuchsia_out_dir)
 
-    # TODO(crbug.com/1000907): Enable AEMU for arm64.
-    if platform.machine() == 'aarch64':
-      raise Exception('AEMU does not support arm64 hosts.')
     self._enable_graphics = enable_graphics
     self._hardware_gpu = hardware_gpu
 
@@ -103,10 +100,12 @@
 
     aemu_command.extend([
       '-vga', 'none',
-      '-device', 'isa-debug-exit,iobase=0xf4,iosize=0x04',
       '-device', 'virtio-keyboard-pci',
       '-device', 'virtio_input_multi_touch_pci_1',
       '-device', 'ich9-ahci,id=ahci'])
+    if platform.machine() == 'x86_64':
+      aemu_command.extend(['-device', 'isa-debug-exit,iobase=0xf4,iosize=0x04'])
+
     logging.info(' '.join(aemu_command))
     return aemu_command
 
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index c4ba435..76f0ea07 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-4.20210513.1.1
+4.20210513.3.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index c4ba435..76f0ea07 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-4.20210513.1.1
+4.20210513.3.1
diff --git a/buildtools/checkdeps/builddeps.py b/buildtools/checkdeps/builddeps.py
index 2fe48b2..a0df3284 100755
--- a/buildtools/checkdeps/builddeps.py
+++ b/buildtools/checkdeps/builddeps.py
@@ -9,10 +9,13 @@
 See README.md for the format of the deps file.
 """
 
+from __future__ import print_function
+
 import copy
 import os.path
 import posixpath
 import subprocess
+import sys
 
 from rules import Rule, Rules
 
@@ -58,11 +61,10 @@
   # FIXME: Use a context manager in Python 3.2+
   popen = subprocess.Popen(git_ls_files_cmd,
                            stdout=subprocess.PIPE,
-                           bufsize=1,  # line buffering, since read by line
                            cwd=base_directory)
   try:
     try:
-      for line in popen.stdout:
+      for line in popen.stdout.read().decode('utf-8').splitlines():
         dir_path = os.path.join(base_directory, os.path.dirname(line))
         dir_path_norm = NormalizePath(dir_path)
         # Add the directory as well as all the parent directories,
@@ -180,7 +182,7 @@
     if self._ignore_specific_rules:
       return rules
 
-    for regexp, specific_rules in specific_includes.iteritems():
+    for regexp, specific_rules in specific_includes.items():
       for rule_str in specific_rules:
         ApplyOneRule(rule_str, regexp)
 
@@ -210,7 +212,7 @@
 
     # Check the DEPS file in this directory.
     if self.verbose:
-      print 'Applying rules from', dir_path_local_abs
+      print('Applying rules from', dir_path_local_abs)
     def FromImpl(*_):
       pass  # NOP function so "From" doesn't fail.
 
@@ -248,9 +250,16 @@
     if os.path.isfile(deps_file_path) and not (
         self._under_test and
         os.path.basename(dir_path_local_abs) == 'checkdeps'):
-      execfile(deps_file_path, global_scope, local_scope)
+      if sys.version_info.major == 2:
+        execfile(deps_file_path, global_scope, local_scope)
+      else:
+        try:
+          exec(open(deps_file_path).read(), global_scope, local_scope)
+        except Exception as e:
+          print(' Error reading %s: %s' % (deps_file_path, str(e)))
+          raise
     elif self.verbose:
-      print '  No deps file found in', dir_path_local_abs
+      print('  No deps file found in', dir_path_local_abs)
 
     # Even if a DEPS file does not exist we still invoke ApplyRules
     # to apply the implicit "allow" rule for the current directory
diff --git a/buildtools/checkdeps/checkdeps.py b/buildtools/checkdeps/checkdeps.py
index 4713dc0f..24cb58a 100755
--- a/buildtools/checkdeps/checkdeps.py
+++ b/buildtools/checkdeps/checkdeps.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # Copyright 2012 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.
@@ -12,6 +12,8 @@
 See README.md for a detailed description of the DEPS format.
 """
 
+from __future__ import print_function
+
 import os
 import optparse
 import re
@@ -68,7 +70,7 @@
     if self.results_formatter.GetResults():
       self.results_formatter.PrintResults()
       return 1
-    print '\nSUCCESS\n'
+    print('\nSUCCESS\n')
     return 0
 
   def CheckDirectory(self, start_dir):
@@ -149,14 +151,16 @@
     return self.CheckIncludesAndImports(
         added_includes, cpp_checker.CppChecker(self.verbose))
 
-  def CheckAddedJavaImports(self, added_imports, allow_multiple_definitions=None):
+  def CheckAddedJavaImports(self, added_imports,
+                            allow_multiple_definitions=None):
     """This is used from PRESUBMIT.py to check new import statements added in
     the change being presubmit checked.
 
     Args:
       added_imports: ((file_path, (import_line, import_line, ...), ...)
-      allow_multiple_definitions: [file_name, file_name, ...]. List of java file
-                                  names allowing multipe definition in presubmit check.
+      allow_multiple_definitions: [file_name, file_name, ...]. List of java
+                                  file names allowing multiple definitions in
+                                  presubmit check.
 
     Return:
       A list of tuples, (bad_file_path, rule_type, rule_description)
@@ -185,7 +189,7 @@
             verbose=self.verbose, root_dir=self.base_directory))
 
 def PrintUsage():
-  print """Usage: python checkdeps.py [--root <root>] [tocheck]
+  print("""Usage: python checkdeps.py [--root <root>] [tocheck]
 
   --root ROOT Specifies the repository root. This defaults to "../../.."
               relative to the script file. This will be correct given the
@@ -198,7 +202,7 @@
 
 Examples:
   python checkdeps.py
-  python checkdeps.py --root c:\\source chrome"""
+  python checkdeps.py --root c:\\source chrome""")
 
 
 def main():
@@ -266,12 +270,12 @@
     return 1
 
   if not start_dir.startswith(deps_checker.base_directory):
-    print 'Directory to check must be a subdirectory of the base directory,'
-    print 'but %s is not a subdirectory of %s' % (start_dir, base_directory)
+    print('Directory to check must be a subdirectory of the base directory,')
+    print('but %s is not a subdirectory of %s' % (start_dir, base_directory))
     return 1
 
-  print 'Using base directory:', base_directory
-  print 'Checking:', start_dir
+  print('Using base directory:', base_directory)
+  print('Checking:', start_dir)
 
   if options.generate_temp_rules:
     deps_checker.results_formatter = results.TemporaryRulesFormatter()
diff --git a/buildtools/checkdeps/cpp_checker.py b/buildtools/checkdeps/cpp_checker.py
index 3efad974..0f9df9f 100644
--- a/buildtools/checkdeps/cpp_checker.py
+++ b/buildtools/checkdeps/cpp_checker.py
@@ -4,6 +4,8 @@
 
 """Checks C++ and Objective-C files for illegal includes."""
 
+from __future__ import print_function
+
 import codecs
 import os
 import re
@@ -64,7 +66,7 @@
       # Don't fail when no directory is specified. We may want to be more
       # strict about this in the future.
       if self._verbose:
-        print ' WARNING: include specified with no directory: ' + include_path
+        print(' WARNING: include specified with no directory: ' + include_path)
       return True, None
 
     if self._resolve_dotdot and '../' in include_path:
@@ -80,7 +82,7 @@
 
   def CheckFile(self, rules, filepath):
     if self._verbose:
-      print 'Checking: ' + filepath
+      print('Checking: ' + filepath)
 
     dependee_status = results.DependeeStatus(filepath)
     ret_val = ''  # We'll collect the error messages in here
diff --git a/buildtools/checkdeps/java_checker.py b/buildtools/checkdeps/java_checker.py
index a5b1db73f..e92a6c5 100644
--- a/buildtools/checkdeps/java_checker.py
+++ b/buildtools/checkdeps/java_checker.py
@@ -4,6 +4,8 @@
 
 """Checks Java files for illegal imports."""
 
+from __future__ import print_function
+
 import codecs
 import os
 import re
@@ -112,21 +114,21 @@
 
   def _PrescanFile(self, filepath, added_classset):
     if self._verbose:
-      print 'Prescanning: ' + filepath
+      print('Prescanning: ' + filepath)
     full_class_name = self._GetClassFullName(filepath)
     if full_class_name:
       if full_class_name in self._classmap:
         if self._verbose or full_class_name in added_classset:
           if not any(re.match(i, filepath) for i in
                      self._allow_multiple_definitions):
-            print 'WARNING: multiple definitions of %s:' % full_class_name
-            print '    ' + filepath
-            print '    ' + self._classmap[full_class_name]
-            print
+            print('WARNING: multiple definitions of %s:' % full_class_name)
+            print('    ' + filepath)
+            print('    ' + self._classmap[full_class_name])
+            print()
       else:
         self._classmap[full_class_name] = filepath
     elif self._verbose:
-      print 'WARNING: no package definition found in %s' % filepath
+      print('WARNING: no package definition found in %s' % filepath)
 
   def CheckLine(self, rules, line, filepath, fail_on_temp_allow=False):
     """Checks the given line with the given rule set.
@@ -157,7 +159,7 @@
 
   def CheckFile(self, rules, filepath):
     if self._verbose:
-      print 'Checking: ' + filepath
+      print('Checking: ' + filepath)
 
     dependee_status = results.DependeeStatus(filepath)
     with codecs.open(filepath, encoding='utf-8') as f:
diff --git a/buildtools/checkdeps/proto_checker.py b/buildtools/checkdeps/proto_checker.py
index a90628a6c..a073ec6 100644
--- a/buildtools/checkdeps/proto_checker.py
+++ b/buildtools/checkdeps/proto_checker.py
@@ -4,6 +4,8 @@
 
 """Checks protobuf files for illegal imports."""
 
+from __future__ import print_function
+
 import codecs
 import os
 import re
@@ -67,7 +69,7 @@
       # Don't fail when no directory is specified. We may want to be more
       # strict about this in the future.
       if self._verbose:
-        print ' WARNING: import specified with no directory: ' + import_path
+        print(' WARNING: import specified with no directory: ' + import_path)
       return True, None
 
     if self._resolve_dotdot and '../' in import_path:
@@ -87,7 +89,7 @@
 
   def CheckFile(self, rules, filepath):
     if self._verbose:
-      print 'Checking: ' + filepath
+      print('Checking: ' + filepath)
 
     dependee_status = results.DependeeStatus(filepath)
     last_import = 0
diff --git a/buildtools/checkdeps/results.py b/buildtools/checkdeps/results.py
index b52880c..929e160 100644
--- a/buildtools/checkdeps/results.py
+++ b/buildtools/checkdeps/results.py
@@ -2,9 +2,9 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-
 """Results object and results formatters for checkdeps tool."""
 
+from __future__ import print_function
 
 import json
 
@@ -96,9 +96,9 @@
 
   def PrintResults(self):
     for result in self.results:
-      print result
+      print(result)
     if self.results:
-      print '\nFAILED\n'
+      print('\nFAILED\n')
 
 
 class JSONResultsFormatter(ResultsFormatter):
@@ -133,7 +133,7 @@
       self.wrapped_formatter.PrintResults()
       return
 
-    print self.results
+    print(self.results)
 
 
 class TemporaryRulesFormatter(ResultsFormatter):
@@ -154,7 +154,7 @@
 
   def PrintResults(self):
     for result in self.GetResults():
-      print result
+      print(result)
 
 
 class CountViolationsFormatter(ResultsFormatter):
@@ -175,4 +175,4 @@
     return '%d' % self.count
 
   def PrintResults(self):
-    print self.count
+    print(self.count)
diff --git a/buildtools/checkdeps/rules.py b/buildtools/checkdeps/rules.py
index bafcf66..1180111 100644
--- a/buildtools/checkdeps/rules.py
+++ b/buildtools/checkdeps/rules.py
@@ -112,7 +112,7 @@
   def __str__(self):
     result = ['Rules = {\n    (apply to all files): [\n%s\n    ],' % '\n'.join(
         '      %s' % x for x in self._general_rules)]
-    for regexp, rules in self._specific_rules.iteritems():
+    for regexp, rules in self._specific_rules.items():
       result.append('    (limited to files matching %s): [\n%s\n    ]' % (
           regexp, '\n'.join('      %s' % x for x in rules)))
     result.append('  }')
@@ -132,7 +132,7 @@
     if include_general_rules:
       AddDependencyTuplesImpl(deps, self._general_rules)
     if include_specific_rules:
-      for regexp, rules in self._specific_rules.iteritems():
+      for regexp, rules in self._specific_rules.items():
         AddDependencyTuplesImpl(deps, rules, "/" + regexp)
     return deps
 
@@ -175,7 +175,7 @@
     file located at |dependee_path|.
     """
     dependee_filename = os.path.basename(dependee_path)
-    for regexp, specific_rules in self._specific_rules.iteritems():
+    for regexp, specific_rules in self._specific_rules.items():
       if re.match(regexp, dependee_filename):
         for rule in specific_rules:
           if rule.ChildOrMatch(include_path):
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index c025067..381ef2b 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -1323,6 +1323,8 @@
     "//components/infobars/core:infobar_enums_java",
     "//components/installedapp/android:javatests",
     "//components/javascript_dialogs/android:java",
+    "//components/language/android:language_bridge_java",
+    "//components/language/android:language_bridge_javatests",
     "//components/location/android:location_java",
     "//components/media_router/browser/android:java",
     "//components/media_router/browser/android:test_support_java",
@@ -3526,6 +3528,7 @@
     "java/src/org/chromium/chrome/browser/init/NativeStartupBridge.java",
     "java/src/org/chromium/chrome/browser/instantapps/InstantAppsSettings.java",
     "java/src/org/chromium/chrome/browser/javascript/WebContextFetcher.java",
+    "java/src/org/chromium/chrome/browser/lens/LensDebugBridge.java",
     "java/src/org/chromium/chrome/browser/lens/LensPolicyUtils.java",
     "java/src/org/chromium/chrome/browser/locale/LocaleManager.java",
     "java/src/org/chromium/chrome/browser/locale/LocaleTemplateUrlLoader.java",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 9bad554..ead5d1f 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -736,6 +736,7 @@
   "java/src/org/chromium/chrome/browser/invalidation/SessionsInvalidationManager.java",
   "java/src/org/chromium/chrome/browser/javascript/WebContextFetcher.java",
   "java/src/org/chromium/chrome/browser/language/LanguageAskPrompt.java",
+  "java/src/org/chromium/chrome/browser/lens/LensDebugBridge.java",
   "java/src/org/chromium/chrome/browser/lens/LensPolicyUtils.java",
   "java/src/org/chromium/chrome/browser/locale/LocaleManager.java",
   "java/src/org/chromium/chrome/browser/locale/LocaleTemplateUrlLoader.java",
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni
index 842a7412..116b2d6 100644
--- a/chrome/android/chrome_test_java_sources.gni
+++ b/chrome/android/chrome_test_java_sources.gni
@@ -264,6 +264,7 @@
   "javatests/src/org/chromium/chrome/browser/jsdialog/JavascriptAppModalDialogTest.java",
   "javatests/src/org/chromium/chrome/browser/jsdialog/JavascriptTabModalDialogTest.java",
   "javatests/src/org/chromium/chrome/browser/language/AppLocaleUtilsTest.java",
+  "javatests/src/org/chromium/chrome/browser/language/GlobalAppLocaleControllerTest.java",
   "javatests/src/org/chromium/chrome/browser/language/settings/LanguageSettingsTest.java",
   "javatests/src/org/chromium/chrome/browser/locale/LocaleManagerReferralTest.java",
   "javatests/src/org/chromium/chrome/browser/locale/LocaleManagerTest.java",
diff --git a/chrome/android/features/cablev2_authenticator/BUILD.gn b/chrome/android/features/cablev2_authenticator/BUILD.gn
index f3bb6ea..1ed3714 100644
--- a/chrome/android/features/cablev2_authenticator/BUILD.gn
+++ b/chrome/android/features/cablev2_authenticator/BUILD.gn
@@ -22,6 +22,8 @@
     "$google_play_services_package:google_play_services_vision_common_java",
     "$google_play_services_package:google_play_services_vision_java",
     "//base:base_java",
+    "//chrome/android:chrome_java",
+    "//components/browser_ui/notifications/android:java",
     "//content/public/android:content_java",
     "//third_party/android_deps:android_support_v7_appcompat_java",
     "//third_party/androidx:androidx_annotation_annotation_java",
@@ -67,12 +69,12 @@
     "java/res/drawable/header.xml",
     "java/res/drawable/ic_lock_googblue_48dp.xml",
     "java/res/drawable/usb_conn_disconnect.xml",
+    "java/res/layout-sw600dp/cablev2_error.xml",
+    "java/res/layout-sw600dp/cablev2_serverlink.xml",
     "java/res/layout/cablev2_error.xml",
     "java/res/layout/cablev2_qr_dialog.xml",
     "java/res/layout/cablev2_qr_scan.xml",
     "java/res/layout/cablev2_serverlink.xml",
-    "java/res/layout-sw600dp/cablev2_serverlink.xml",
-    "java/res/layout-sw600dp/cablev2_error.xml",
     "java/res/layout/cablev2_usb_attached.xml",
     "java/res/values/attrs.xml",
     "java/res/values/styles.xml",
diff --git a/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticatorUI.java b/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticatorUI.java
index 0828fd95..954d9e9 100644
--- a/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticatorUI.java
+++ b/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticatorUI.java
@@ -9,8 +9,7 @@
 import android.annotation.TargetApi;
 import android.app.Activity;
 import android.app.KeyguardManager;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
+import android.app.Notification;
 import android.app.PendingIntent;
 import android.bluetooth.BluetoothAdapter;
 import android.content.Context;
@@ -43,6 +42,9 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.ThreadUtils;
+import org.chromium.chrome.browser.notifications.NotificationConstants;
+import org.chromium.chrome.browser.notifications.NotificationWrapperBuilderFactory;
+import org.chromium.chrome.browser.notifications.channels.ChromeChannelDefinitions;
 import org.chromium.ui.base.ActivityAndroidPermissionDelegate;
 import org.chromium.ui.base.AndroidPermissionDelegate;
 import org.chromium.ui.widget.Toast;
@@ -64,6 +66,10 @@
     // for before being replaced with a prompt to connect via USB cable.
     private static final int USB_PROMPT_TIMEOUT_SECS = 20;
 
+    // NOTIFICATION_TIMEOUT_SECS is the number of seconds that a notification
+    // will exist for. This stop ignored notifications hanging around.
+    private static final int NOTIFICATION_TIMEOUT_SECS = 60;
+
     private static final String FCM_EXTRA = "org.chromium.chrome.modules.cablev2_authenticator.FCM";
     private static final String NETWORK_CONTEXT_EXTRA =
             "org.chromium.chrome.modules.cablev2_authenticator.NetworkContext";
@@ -73,8 +79,6 @@
             "org.chromium.chrome.modules.cablev2_authenticator.Secret";
     private static final String SERVER_LINK_EXTRA =
             "org.chromium.chrome.browser.webauth.authenticator.ServerLink";
-    private static final String NOTIFICATION_CHANNEL_ID =
-            "chrome.android.features.cablev2_authenticator";
 
     // These entries duplicate some of the enum values from
     // device::cablev2::authenticator::Platform::Error. They must be kept in
@@ -532,22 +536,6 @@
         Context context = ContextUtils.getApplicationContext();
         Resources resources = context.getResources();
 
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-            // Register a channel for this notification. Registering the same
-            // channel twice is harmless.
-            CharSequence name = "Security key activations";
-            // TODO: finalise string and translate.
-            String description =
-                    "Notifications that appear when you attempt to log in on another device";
-            int importance = NotificationManager.IMPORTANCE_HIGH;
-            NotificationChannel channel =
-                    new NotificationChannel(NOTIFICATION_CHANNEL_ID, name, importance);
-            channel.setDescription(description);
-            NotificationManager notificationManager =
-                    context.getSystemService(NotificationManager.class);
-            notificationManager.createNotificationChannel(channel);
-        }
-
         Intent intent;
         try {
             intent = new Intent(context, Class.forName(activityClassName));
@@ -577,17 +565,23 @@
                 break;
         }
 
-        NotificationCompat.Builder builder =
-                new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
-                        .setSmallIcon(android.R.drawable.stat_sys_download_done)
-                        .setContentTitle(title)
-                        .setContentText(body)
-                        .setPriority(NotificationCompat.PRIORITY_HIGH)
-                        .setAutoCancel(true)
-                        .setContentIntent(pendingIntent)
-                        .setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
+        Notification notification = NotificationWrapperBuilderFactory
+                                            .createNotificationWrapperBuilder(
+                                                    /*preferCompat=*/true,
+                                                    ChromeChannelDefinitions.ChannelId.SECURITY_KEY)
+                                            .setAutoCancel(true)
+                                            .setCategory(Notification.CATEGORY_MESSAGE)
+                                            .setContentIntent(pendingIntent)
+                                            .setContentText(body)
+                                            .setContentTitle(title)
+                                            .setPriorityBeforeO(NotificationCompat.PRIORITY_MAX)
+                                            .setSmallIcon(org.chromium.chrome.R.drawable.ic_chrome)
+                                            .setTimeoutAfter(NOTIFICATION_TIMEOUT_SECS * 1000)
+                                            .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
+                                            .build();
 
         NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
-        notificationManager.notify(NOTIFICATION_CHANNEL_ID, ID, builder.build());
+        notificationManager.notify(
+                NotificationConstants.NOTIFICATION_ID_SECURITY_KEY, notification);
     }
 }
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
index 4034da9d..dfc5642 100644
--- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
+++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
@@ -513,7 +513,6 @@
         onViewWaiting(withId(R.id.search_box_text));
         TextView urlBar = cta.findViewById(R.id.url_bar);
         Assert.assertFalse(urlBar.isFocused());
-        waitForStableView(urlBar);
         waitForStableView(cta.findViewById(R.id.search_box_text));
         onView(withId(R.id.search_box_text)).perform(click());
         Assert.assertTrue(TextUtils.isEmpty(urlBar.getText()));
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTestUtils.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTestUtils.java
index bd7cc6b..163d3430 100644
--- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTestUtils.java
+++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTestUtils.java
@@ -218,6 +218,10 @@
      * @param cta The ChromeTabbedActivity under test.
      */
     public static void scrollToolbar(ChromeTabbedActivity cta) {
+        // Toolbar layout should be hidden if start surface toolbar is shown on the top of the
+        // screen.
+        onView(withId(R.id.toolbar))
+                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));
         // The home button shouldn't show on homepage.
         onView(withId(R.id.home_button))
                 .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksView.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksView.java
index 271c2f0a..5136a17 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksView.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksView.java
@@ -28,6 +28,7 @@
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.ntp.IncognitoDescriptionView;
 import org.chromium.chrome.browser.ntp.search.SearchBoxCoordinator;
+import org.chromium.chrome.browser.omnibox.SearchEngineLogoUtils;
 import org.chromium.chrome.tab_ui.R;
 import org.chromium.components.browser_ui.styles.ChromeColors;
 import org.chromium.components.browser_ui.widget.CoordinatorLayoutForPointer;
@@ -54,6 +55,7 @@
             CookieControlsEnforcement.NO_ENFORCEMENT;
     private View.OnClickListener mIncognitoCookieControlsIconClickListener;
     private UiConfig mUiConfig;
+    private boolean mIsIncognito;
 
     /** Default constructor needed to inflate via XML. */
     public TasksView(Context context, AttributeSet attrs) {
@@ -166,6 +168,7 @@
                 ? ApiCompatibilityUtils.getColor(resources, R.color.locationbar_light_hint_text)
                 : ApiCompatibilityUtils.getColor(resources, R.color.locationbar_dark_hint_text);
         mSearchBoxCoordinator.setSearchBoxHintColor(hintTextColor);
+        mIsIncognito = isIncognito;
     }
 
     /**
@@ -348,12 +351,13 @@
             int toolbarContainerTopMargin =
                     getResources().getDimensionPixelSize(R.dimen.location_bar_vertical_margin);
             View fakeSearchBoxView = findViewById(R.id.search_box);
+            View searchTextView = findViewById(R.id.search_box_text);
             if (fakeSearchBoxView == null) return;
             // If fake search box view is not null when creating this animation, it will not change.
             // So checking it once above is enough.
             mFakeSearchBoxShrinkAnimation = (appbarLayout, headerVerticalOffset)
                     -> updateFakeSearchBoxShrinkAnimation(headerVerticalOffset, fakeSearchBoxHeight,
-                            toolbarContainerTopMargin, fakeSearchBoxView);
+                            toolbarContainerTopMargin, fakeSearchBoxView, searchTextView);
         }
         mHeaderView.addOnOffsetChangedListener(mFakeSearchBoxShrinkAnimation);
     }
@@ -379,9 +383,11 @@
      * @param originalFakeSearchBoxHeight The height of fake search box.
      * @param toolbarContainerTopMargin The top margin of toolbar container view.
      * @param fakeSearchBox The fake search box in start surface homepage.
+     * @param searchTextView  The search text view in fake search box.
      */
     private void updateFakeSearchBoxShrinkAnimation(int headerOffset,
-            int originalFakeSearchBoxHeight, int toolbarContainerTopMargin, View fakeSearchBox) {
+            int originalFakeSearchBoxHeight, int toolbarContainerTopMargin, View fakeSearchBox,
+            View searchTextView) {
         // When the header is scrolled up by fake search box height or so, reduce the fake search
         // box height.
         int reduceHeight = MathUtils.clamp(
@@ -401,6 +407,20 @@
                 marginLayoutParams.rightMargin, marginLayoutParams.bottomMargin);
 
         fakeSearchBox.setLayoutParams(layoutParams);
+
+        // Update the translation X of search text view to make space for the search logo.
+        SearchEngineLogoUtils searchEngineLogoUtils = SearchEngineLogoUtils.getInstance();
+        assert searchEngineLogoUtils != null;
+
+        if (!searchEngineLogoUtils.shouldShowSearchEngineLogo(mIsIncognito)) {
+            return;
+        }
+
+        int finalTranslationX =
+                getResources().getDimensionPixelSize(R.dimen.location_bar_icon_end_padding_focused)
+                - getResources().getDimensionPixelSize(R.dimen.location_bar_icon_end_padding);
+        searchTextView.setTranslationX(
+                finalTranslationX * ((float) reduceHeight / toolbarContainerTopMargin));
     }
 
     /**
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java
index bca1aea..6e0bfef 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java
@@ -561,7 +561,6 @@
             mFeedSurfaceLifecycleManager.destroy();
             mFeedSurfaceLifecycleManager = null;
             mStream = null;
-            mSectionHeaderView = null;
             mSigninPromoView = null;
 
             mEnhancedProtectionPromoView = null;
@@ -587,6 +586,8 @@
             UiUtils.removeViewFromParent(mNtpHeader);
             mScrollViewForPolicy.addView(mNtpHeader);
         }
+        mHeaderCount = 0;
+
         mRootView.addView(mScrollViewForPolicy);
         mScrollViewResizer = ViewResizer.createAndAttach(
                 mScrollViewForPolicy, mUiConfig, mDefaultMarginPixels, mWideMarginPixels);
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java
index 0de2f0a..47f36015 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java
@@ -69,6 +69,8 @@
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.ui.modelutil.MVCListAdapter;
 import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
+import org.chromium.ui.modelutil.PropertyKey;
+import org.chromium.ui.modelutil.PropertyListModel;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.mojom.WindowOpenDisposition;
 
@@ -668,6 +670,12 @@
         mPrefChangeRegistrar.removeObserver(Pref.ARTICLES_LIST_VISIBLE);
         TemplateUrlServiceFactory.get().removeObserver(this);
         mSigninManager.getIdentityManager().removeObserver(this);
+
+        PropertyListModel<PropertyModel, PropertyKey> headerList =
+                mSectionHeaderModel.get(SectionHeaderListProperties.SECTION_HEADERS_KEY);
+        if (headerList.size() > 0) {
+            headerList.removeRange(0, headerList.size());
+        }
     }
 
     /**
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceScopeDependencyProvider.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceScopeDependencyProvider.java
index b6921da..26fac70 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceScopeDependencyProvider.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceScopeDependencyProvider.java
@@ -64,6 +64,48 @@
     }
 
     @Override
+    public AutoplayPreference getAutoplayPreference() {
+        assert ThreadUtils.runningOnUiThread();
+        @VideoPreviewsType
+        int videoPreviewsType = FeedServiceBridge.getVideoPreviewsTypePreference();
+        switch (videoPreviewsType) {
+            case VideoPreviewsType.NEVER:
+                return AutoplayPreference.AUTOPLAY_DISABLED;
+            case VideoPreviewsType.WIFI_AND_MOBILE_DATA:
+                return AutoplayPreference.AUTOPLAY_ON_WIFI_AND_MOBILE_DATA;
+            case VideoPreviewsType.WIFI:
+            default:
+                return AutoplayPreference.AUTOPLAY_ON_WIFI_ONLY;
+        }
+    }
+
+    @Override
+    public void reportAutoplayEvent(AutoplayEvent event) {
+        int feedAutoplayEvent;
+        if (event == AutoplayEvent.AUTOPLAY_REQUESTED) {
+            feedAutoplayEvent = FeedAutoplayEvent.AUTOPLAY_REQUESTED;
+        } else if (event == AutoplayEvent.AUTOPLAY_STARTED) {
+            feedAutoplayEvent = FeedAutoplayEvent.AUTOPLAY_STARTED;
+        } else if (event == AutoplayEvent.AUTOPLAY_STOPPED) {
+            feedAutoplayEvent = FeedAutoplayEvent.AUTOPLAY_STOPPED;
+        } else if (event == AutoplayEvent.AUTOPLAY_ENDED) {
+            feedAutoplayEvent = FeedAutoplayEvent.AUTOPLAY_ENDED;
+        } else if (event == AutoplayEvent.AUTOPLAY_CLICKED) {
+            feedAutoplayEvent = FeedAutoplayEvent.AUTOPLAY_CLICKED;
+            NewTabPageUma.recordAction(NewTabPageUma.ACTION_OPENED_VIDEO);
+        } else {
+            Log.wtf(TAG, "Unable to map AutoplayEvent " + event.name());
+            return;
+        }
+        RecordHistogram.recordEnumeratedHistogram("ContentSuggestions.Feed.AutoplayEvent",
+                feedAutoplayEvent, FeedAutoplayEvent.NUM_ENTRIES);
+    }
+
+    /**
+     * FeedLoggingDependencyProvider implementation.
+     */
+
+    @Override
     public String getAccountName() {
         // Don't return account name if there's a signed-out session ID.
         if (!getSignedOutSessionId().isEmpty()) {
@@ -103,41 +145,12 @@
         return mFeedStream.getSignedOutSessionId();
     }
 
+    /**
+     * Stores a view FeedAction for eventual upload. 'data' is a serialized FeedAction protobuf
+     * message.
+     */
     @Override
-    public AutoplayPreference getAutoplayPreference() {
-        assert ThreadUtils.runningOnUiThread();
-        @VideoPreviewsType
-        int videoPreviewsType = FeedServiceBridge.getVideoPreviewsTypePreference();
-        switch (videoPreviewsType) {
-            case VideoPreviewsType.NEVER:
-                return AutoplayPreference.AUTOPLAY_DISABLED;
-            case VideoPreviewsType.WIFI_AND_MOBILE_DATA:
-                return AutoplayPreference.AUTOPLAY_ON_WIFI_AND_MOBILE_DATA;
-            case VideoPreviewsType.WIFI:
-            default:
-                return AutoplayPreference.AUTOPLAY_ON_WIFI_ONLY;
-        }
-    }
-
-    @Override
-    public void reportAutoplayEvent(AutoplayEvent event) {
-        int feedAutoplayEvent;
-        if (event == AutoplayEvent.AUTOPLAY_REQUESTED) {
-            feedAutoplayEvent = FeedAutoplayEvent.AUTOPLAY_REQUESTED;
-        } else if (event == AutoplayEvent.AUTOPLAY_STARTED) {
-            feedAutoplayEvent = FeedAutoplayEvent.AUTOPLAY_STARTED;
-        } else if (event == AutoplayEvent.AUTOPLAY_STOPPED) {
-            feedAutoplayEvent = FeedAutoplayEvent.AUTOPLAY_STOPPED;
-        } else if (event == AutoplayEvent.AUTOPLAY_ENDED) {
-            feedAutoplayEvent = FeedAutoplayEvent.AUTOPLAY_ENDED;
-        } else if (event == AutoplayEvent.AUTOPLAY_CLICKED) {
-            feedAutoplayEvent = FeedAutoplayEvent.AUTOPLAY_CLICKED;
-            NewTabPageUma.recordAction(NewTabPageUma.ACTION_OPENED_VIDEO);
-        } else {
-            Log.wtf(TAG, "Unable to map AutoplayEvent " + event.name());
-            return;
-        }
-        RecordHistogram.recordEnumeratedHistogram("ContentSuggestions.Feed.AutoplayEvent",
-                feedAutoplayEvent, FeedAutoplayEvent.NUM_ENTRIES);
+    public void processViewAction(byte[] data) {
+        mFeedStream.processViewAction(data);
     }
 }
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/shared/FeedFeatures.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/shared/FeedFeatures.java
index c60f4be..e997b7e 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/shared/FeedFeatures.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/shared/FeedFeatures.java
@@ -6,10 +6,8 @@
 
 import androidx.annotation.VisibleForTesting;
 
-import org.chromium.base.Log;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.preferences.Pref;
-import org.chromium.chrome.browser.preferences.PrefChangeRegistrar;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.components.prefs.PrefService;
 import org.chromium.components.user_prefs.UserPrefs;
@@ -19,38 +17,14 @@
  */
 public final class FeedFeatures {
     private static final String TAG = "FeedFeatures";
-    /**
-     * Flag that tracks whether we've ever been disabled via enterprise policy. Should only be
-     * accessed through isFeedProcessScopeEnabled().
-     */
-    private static boolean sEverDisabledForPolicy;
-
-    private static PrefChangeRegistrar sPrefChangeRegistrar;
-
     private static PrefService sFakePrefServiceForTest;
 
     /**
-     * @return Whether the feed is allowed to be used. The feed is disabled if supervised user or
-     * enterprise policy has once been added within the current session. The value returned by
-     * this function can change from true to false over the life of the application.
+     * @return Whether the feed is allowed to be used. Returns false if the feed is disabled due to
+     *         enterprise policy. The value returned should not be cached as it may change.
      */
     public static boolean isFeedEnabled() {
-        // Once true, sEverDisabledForPolicy will remain true. If it isn't true yet, we need to
-        // check the pref every time. Two reasons for this. 1) We want to notice when we start in a
-        // disabled state, shouldn't allow Feed to enabled until a restart. 2) A different
-        // subscriber to this pref change event might check in with this method, and we cannot
-        // assume who will be called first. See https://crbug.com/896468.
-        if (sEverDisabledForPolicy) return false;
-
-        if (sPrefChangeRegistrar == null) {
-            setPrefChangeRegistrar(new PrefChangeRegistrar());
-        }
-
-        if (!sEverDisabledForPolicy) {
-            sEverDisabledForPolicy = !getPrefService().getBoolean(Pref.ENABLE_SNIPPETS);
-        }
-
-        return !sEverDisabledForPolicy;
+        return getPrefService().getBoolean(Pref.ENABLE_SNIPPETS);
     }
 
     /**
@@ -61,18 +35,6 @@
                 && getPrefService().getBoolean(Pref.ENABLE_WEB_FEED_UI);
     }
 
-    private static void articlesEnabledPrefChange() {
-        // Cannot assume this is called because of an actual change. May be going from true to true.
-        if (!getPrefService().getBoolean(Pref.ENABLE_SNIPPETS)) {
-            // There have been quite a few crashes/bugs that happen when code does not correctly
-            // handle the scenario where Feed suddenly becomes disabled and the above getters start
-            // returning nulls. Having this log a warning helps diagnose this pattern from the
-            // logcat.
-            Log.w(TAG, "Disabling Feed because of policy.");
-            sEverDisabledForPolicy = true;
-        }
-    }
-
     private static PrefService getPrefService() {
         if (sFakePrefServiceForTest != null) {
             return sFakePrefServiceForTest;
@@ -80,17 +42,8 @@
         return UserPrefs.get(Profile.getLastUsedRegularProfile());
     }
 
-    private static void setPrefChangeRegistrar(PrefChangeRegistrar registrar) {
-        sPrefChangeRegistrar = registrar;
-        if (sPrefChangeRegistrar != null) {
-            sPrefChangeRegistrar.addObserver(
-                    Pref.ENABLE_SNIPPETS, FeedFeatures::articlesEnabledPrefChange);
-        }
-    }
-
     @VisibleForTesting
-    public static void setFakePrefsForTest(PrefService fakePref, PrefChangeRegistrar fakeRegistar) {
+    public static void setFakePrefsForTest(PrefService fakePref) {
         sFakePrefServiceForTest = fakePref;
-        setPrefChangeRegistrar(fakeRegistar);
     }
 }
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedStream.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedStream.java
index ce867eb8..a7991acb 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedStream.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedStream.java
@@ -17,6 +17,7 @@
 import androidx.recyclerview.widget.RecyclerView;
 
 import org.chromium.base.Callback;
+import org.chromium.base.Function;
 import org.chromium.base.Log;
 import org.chromium.base.ObserverList;
 import org.chromium.base.ThreadUtils;
@@ -80,6 +81,8 @@
 public class FeedStream implements Stream {
     private static final String TAG = "FeedStream";
 
+    Function<String, GURL> mMakeGURL = url -> new GURL(url);
+
     /**
      * Implementation of SurfaceActionsHandler methods.
      */
@@ -88,8 +91,8 @@
         @Override
         public void navigateTab(String url, View actionSourceView) {
             assert ThreadUtils.runningOnUiThread();
-            FeedStreamJni.get().reportOpenAction(
-                    mNativeFeedStream, FeedStream.this, getSliceIdFromView(actionSourceView));
+            FeedStreamJni.get().reportOpenAction(mNativeFeedStream, FeedStream.this,
+                    mMakeGURL.apply(url), getSliceIdFromView(actionSourceView));
             NewTabPageUma.recordAction(NewTabPageUma.ACTION_OPENED_SNIPPET);
 
             openUrl(url, org.chromium.ui.mojom.WindowOpenDisposition.CURRENT_TAB);
@@ -101,8 +104,8 @@
         @Override
         public void navigateNewTab(String url, View actionSourceView) {
             assert ThreadUtils.runningOnUiThread();
-            FeedStreamJni.get().reportOpenInNewTabAction(
-                    mNativeFeedStream, FeedStream.this, getSliceIdFromView(actionSourceView));
+            FeedStreamJni.get().reportOpenInNewTabAction(mNativeFeedStream, FeedStream.this,
+                    mMakeGURL.apply(url), getSliceIdFromView(actionSourceView));
             NewTabPageUma.recordAction(NewTabPageUma.ACTION_OPENED_SNIPPET);
 
             openUrl(url, org.chromium.ui.mojom.WindowOpenDisposition.NEW_BACKGROUND_TAB);
@@ -632,6 +635,10 @@
         return FeedStreamJni.get().isActivityLoggingEnabled(mNativeFeedStream, this);
     }
 
+    public void processViewAction(byte[] data) {
+        FeedStreamJni.get().processViewAction(mNativeFeedStream, this, data);
+    }
+
     @Override
     public int[] getExperimentIds() {
         assert ThreadUtils.runningOnUiThread();
@@ -1046,8 +1053,9 @@
         void reportFeedViewed(long nativeFeedStream, FeedStream caller);
         void reportSliceViewed(long nativeFeedStream, FeedStream caller, String sliceId);
         void reportPageLoaded(long nativeFeedStream, FeedStream caller, boolean inNewTab);
-        void reportOpenAction(long nativeFeedStream, FeedStream caller, String sliceId);
-        void reportOpenInNewTabAction(long nativeFeedStream, FeedStream caller, String sliceId);
+        void reportOpenAction(long nativeFeedStream, FeedStream caller, GURL url, String sliceId);
+        void reportOpenInNewTabAction(
+                long nativeFeedStream, FeedStream caller, GURL url, String sliceId);
         void reportOtherUserAction(
                 long nativeFeedStream, FeedStream caller, @FeedUserActionType int userAction);
         void reportStreamScrolled(long nativeFeedStream, FeedStream caller, int distanceDp);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
index cb7dc66d..b967159 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
@@ -51,6 +51,7 @@
 import org.chromium.chrome.browser.history.HistoryDeletionBridge;
 import org.chromium.chrome.browser.homepage.HomepageManager;
 import org.chromium.chrome.browser.incognito.IncognitoTabLauncher;
+import org.chromium.chrome.browser.language.GlobalAppLocaleController;
 import org.chromium.chrome.browser.media.MediaCaptureNotificationServiceImpl;
 import org.chromium.chrome.browser.media.MediaViewerUtils;
 import org.chromium.chrome.browser.metrics.LaunchMetrics;
@@ -407,6 +408,8 @@
                 ()
                         -> AssistantVoiceSearchService.reportStartupUserEligibility(
                                 ContextUtils.getApplicationContext()));
+        deferredStartupHandler.addDeferredTask(
+                () -> GlobalAppLocaleController.getInstance().recordOverrideLangauge());
     }
 
     private void initChannelsAsync() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/lens/LensDebugBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/lens/LensDebugBridge.java
new file mode 100644
index 0000000..e8597dd
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/lens/LensDebugBridge.java
@@ -0,0 +1,31 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.lens;
+
+import org.chromium.base.annotations.CalledByNative;
+
+/**
+ * Bridge class to allow for Java <-> Native communication for Lens integrations. Currently used to
+ * support communication required to populate the Lens Internals page.
+ */
+public class LensDebugBridge {
+    /** Start collecting proactive debug data for future requests. */
+    @CalledByNative
+    public static void startProactiveDebugMode() {
+        LensController.getInstance().enableDebugMode();
+    }
+
+    /** Stop collecting proactive debug data for future requests. */
+    @CalledByNative
+    public static void stopProactiveDebugMode() {
+        LensController.getInstance().disableDebugMode();
+    }
+
+    /** Fetch all collected debug data for past requests for when the mode was enabled. */
+    @CalledByNative
+    public static String[][] refreshDebugData() {
+        return LensController.getInstance().getDebugData();
+    }
+}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteController.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteController.java
index 33d810ef..5def2ac 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteController.java
@@ -49,7 +49,7 @@
     private boolean mUseCachedZeroSuggestResults;
     private boolean mWaitingForSuggestionsToCache;
     private Profile mProfile;
-    private @NonNull AutocompleteResult mAutocompleteResult;
+    private @NonNull AutocompleteResult mAutocompleteResult = AutocompleteResult.EMPTY_RESULT;
 
     /**
      * Listener for receiving OmniboxSuggestions.
@@ -60,7 +60,6 @@
     }
 
     public AutocompleteController(@NonNull Callback<Profile> spareRendererCreator) {
-        mAutocompleteResult = new AutocompleteResult(null, null);
         mSpareRendererCreator = spareRendererCreator;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java
index d4a4dce4..da7c3bc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java
@@ -81,8 +81,8 @@
     private final PropertyModel mListPropertyModel;
     private final ModelList mSuggestionModels;
     private final Handler mHandler;
-    @Nullable
-    private AutocompleteResult mAutocompleteResult;
+    @NonNull
+    private AutocompleteResult mAutocompleteResult = AutocompleteResult.EMPTY_RESULT;
     @Nullable
     private Runnable mCurrentAutocompleteRequest;
     @Nullable
@@ -137,9 +137,6 @@
      */
     private String mUrlTextAfterSuggestionsReceived;
 
-    private DeferredOnSelectionRunnable mDeferredOnSelection;
-
-    private boolean mShowCachedZeroSuggestResults;
     private boolean mShouldPreventOmniboxAutocomplete;
 
     private long mLastActionUpTimestamp;
@@ -178,7 +175,6 @@
         mBringTabToFrontCallback = bringTabToFrontCallback;
         mTabWindowManagerSupplier = tabWindowManagerSupplier;
         mSuggestionModels = mListPropertyModel.get(SuggestionListProperties.SUGGESTION_MODELS);
-        mAutocompleteResult = new AutocompleteResult(null, null);
         mDropdownViewInfoListBuilder = new DropdownItemViewInfoListBuilder(
                 mAutocomplete, activityTabSupplier, bookmarkState);
         mDropdownViewInfoListBuilder.setShareDelegateSupplier(shareDelegateSupplier);
@@ -304,8 +300,7 @@
      * @param showCachedZeroSuggestResults Whether cached zero suggest should be shown.
      */
     void setShowCachedZeroSuggestResults(boolean showCachedZeroSuggestResults) {
-        mShowCachedZeroSuggestResults = showCachedZeroSuggestResults;
-        if (mShowCachedZeroSuggestResults) mAutocomplete.startCachedZeroSuggest();
+        if (showCachedZeroSuggestResults) mAutocomplete.startCachedZeroSuggest();
     }
 
     /** Notify the mediator that a item selection is pending and should be accepted. */
@@ -449,13 +444,11 @@
     @Override
     public void onSuggestionClicked(
             @NonNull AutocompleteMatch suggestion, int position, @NonNull GURL url) {
-        if (mShowCachedZeroSuggestResults && !mNativeInitialized) {
-            mDeferredOnSelection = new DeferredOnSelectionRunnable(suggestion, position) {
-                @Override
-                public void run() {
-                    onSuggestionClicked(mSuggestion, mPosition, url);
-                }
-            };
+        if (mAutocompleteResult.isFromCachedResult() && !mNativeInitialized) {
+            // clang-format off
+            mDeferredLoadAction = () -> loadUrlForOmniboxMatch(
+                            position, suggestion, url, mLastActionUpTimestamp, true);
+            // clang-format on
             return;
         }
 
@@ -714,21 +707,7 @@
             return;
         }
 
-        // This is a callback from a listener that is set up by onNativeLibraryReady,
-        // so can only be called once the native side is set up unless we are showing
-        // cached java-only suggestions.
-        assert mNativeInitialized
-                || mShowCachedZeroSuggestResults
-            : "Native suggestions received before native side intialialized";
-
         final List<AutocompleteMatch> newSuggestions = autocompleteResult.getSuggestionsList();
-        if (mDeferredOnSelection != null) {
-            mDeferredOnSelection.setShouldLog(newSuggestions.size() > mDeferredOnSelection.mPosition
-                    && mDeferredOnSelection.mSuggestion.equals(
-                            newSuggestions.get(mDeferredOnSelection.mPosition)));
-            mDeferredOnSelection.run();
-            mDeferredOnSelection = null;
-        }
         String userText = mUrlBarEditingTextProvider.getTextWithoutAutocomplete();
         mUrlTextAfterSuggestionsReceived = userText + inlineAutocompleteText;
 
@@ -817,6 +796,9 @@
             @NonNull GURL url, long inputStart, boolean inVisibleSuggestionList) {
         SuggestionsMetrics.recordFocusToOpenTime(System.currentTimeMillis() - mUrlFocusTime);
 
+        // Clear the deferred site load action in case it executes. Reclaims a bit of memory.
+        mDeferredLoadAction = null;
+
         mOmniboxFocusResultedInNavigation = true;
         url = updateSuggestionUrlIfNeeded(suggestion, matchPosition, url, !inVisibleSuggestionList);
 
@@ -826,11 +808,7 @@
         int transition = suggestion.getTransition();
         int type = suggestion.getType();
 
-        boolean shouldSkipNativeLog = mShowCachedZeroSuggestResults
-                && (mDeferredOnSelection != null) && !mDeferredOnSelection.shouldLog();
-        if (!shouldSkipNativeLog) {
-            recordMetrics(matchPosition, WindowOpenDisposition.CURRENT_TAB, suggestion);
-        }
+        recordMetrics(matchPosition, WindowOpenDisposition.CURRENT_TAB, suggestion);
         if (((transition & PageTransition.CORE_MASK) == PageTransition.TYPED)
                 && TextUtils.equals(url.getSpec(), mDataProvider.getCurrentUrl())) {
             // When the user hit enter on the existing permanent URL, treat it like a
@@ -913,7 +891,7 @@
         stopAutocomplete(true);
 
         mDropdownViewInfoListManager.clear();
-        mAutocompleteResult = new AutocompleteResult(null, null);
+        mAutocompleteResult = AutocompleteResult.EMPTY_RESULT;
         updateOmniboxSuggestionsVisibility();
     }
 
@@ -951,32 +929,6 @@
         mDropdownViewInfoListBuilder.setAutocompleteControllerForTest(controller);
     }
 
-    private abstract static class DeferredOnSelectionRunnable implements Runnable {
-        protected final AutocompleteMatch mSuggestion;
-        protected final int mPosition;
-        protected boolean mShouldLog;
-
-        public DeferredOnSelectionRunnable(AutocompleteMatch suggestion, int position) {
-            this.mSuggestion = suggestion;
-            this.mPosition = position;
-        }
-
-        /**
-         * Set whether the selection matches with native results for logging to make sense.
-         * @param log Whether the selection should be logged in native code.
-         */
-        public void setShouldLog(boolean log) {
-            mShouldLog = log;
-        }
-
-        /**
-         * @return Whether the selection should be logged in native code.
-         */
-        public boolean shouldLog() {
-            return mShouldLog;
-        }
-    }
-
     /**
      * Respond to Suggestion list height change and update list of presented suggestions.
      *
@@ -1011,6 +963,13 @@
      * @param suggestion The suggestion selected.
      */
     private void recordMetrics(int matchPosition, int disposition, AutocompleteMatch suggestion) {
+        SuggestionsMetrics.recordUsedSuggestionFromCache(mAutocompleteResult.isFromCachedResult());
+
+        // Do not attempt to record other metrics for cached suggestions if the source of the list
+        // is local cache. These suggestions do not have corresponding native objects and will fail
+        // validation.
+        if (mAutocompleteResult.isFromCachedResult()) return;
+
         String currentPageUrl = mDataProvider.getCurrentUrl();
         int pageClassification =
                 mDataProvider.getPageClassification(mDelegate.didFocusUrlFromFakebox());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/CachedZeroSuggestionsManager.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/CachedZeroSuggestionsManager.java
index eaac857..ff7dfa7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/CachedZeroSuggestionsManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/CachedZeroSuggestionsManager.java
@@ -66,7 +66,7 @@
         SparseArray<GroupDetails> groupsDetails =
                 CachedZeroSuggestionsManager.readCachedGroupsDetails(manager);
         removeInvalidSuggestionsAndGroupsDetails(suggestions, groupsDetails);
-        return new AutocompleteResult(suggestions, groupsDetails);
+        return AutocompleteResult.fromCache(suggestions, groupsDetails);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionsMetrics.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionsMetrics.java
index 18567e25..a046c0c50 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionsMetrics.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionsMetrics.java
@@ -111,4 +111,14 @@
         RecordHistogram.recordMediumTimesHistogram(
                 "Omnibox.FocusToOpenTimeAnyPopupState3", focusToOpenTimeInMillis);
     }
+
+    /**
+     * Record whether the used suggestion originates from Cache or Autocomplete subsystem.
+     *
+     * @param isFromCache Whether the suggestion selected by the User comes from suggestion cache.
+     */
+    static final void recordUsedSuggestionFromCache(boolean isFromCache) {
+        RecordHistogram.recordBooleanHistogram(
+                "Android.Omnibox.UsedSuggestionFromCache", isFromCache);
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
index d11b1e3..a9987fcc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
@@ -59,7 +59,6 @@
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.WebContentsAccessibility;
 import org.chromium.content_public.browser.navigation_controller.UserAgentOverrideOption;
-import org.chromium.ui.base.DeviceFormFactor;
 import org.chromium.ui.base.PageTransition;
 import org.chromium.ui.base.ViewAndroidDelegate;
 import org.chromium.ui.base.WindowAndroid;
@@ -1664,13 +1663,14 @@
                 ? false
                 : getWebContents().getNavigationController().getUseDesktopUserAgent();
 
-        if (!mUserForcedUserAgent && DeviceFormFactor.isNonMultiDisplayContextOnTablet(getContext())
+        // We only calculate the user agent when users did not manually choose one.
+        if (!mUserForcedUserAgent
                 && ChromeFeatureList.isEnabled(ChromeFeatureList.REQUEST_DESKTOP_SITE_FOR_TABLETS)
                 && ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean(
                         ChromeFeatureList.REQUEST_DESKTOP_SITE_FOR_TABLETS,
                         REQUEST_DESKTOP_ENABLED_PARAM, false)) {
             // We only do the following logic to choose the desktop/mobile user agent if
-            // 1. User never manually made choice in app menu for requesting desktop site or not.
+            // 1. User never manually made a choice in app menu for requesting desktop site.
             // 2. The browser is running in tablets.
             boolean shouldRequestDesktopSite = TabUtils.isTabLargeEnoughForDesktopSite(this);
 
@@ -1678,13 +1678,14 @@
                 RecordHistogram.recordBooleanHistogram(
                         "Android.RequestDesktopSite.UseDesktopUserAgent", shouldRequestDesktopSite);
 
-                // The user is not forcing any mode and we determined that we need to change,
-                // therefore we are using TRUE or FALSE option. On Android TRUE mean override to
-                // Desktop user agent, while FALSE means go with Mobile version.
+                // The user is not forcing any mode and we determined that we need to
+                // change, therefore we are using TRUE or FALSE option. On Android TRUE mean
+                // override to Desktop user agent, while FALSE means go with Mobile version.
                 return shouldRequestDesktopSite ? UserAgentOverrideOption.TRUE
                                                 : UserAgentOverrideOption.FALSE;
             }
         }
+
         RecordHistogram.recordBooleanHistogram(
                 "Android.RequestDesktopSite.UseDesktopUserAgent", currentRequestDesktopSite);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUtils.java
index 29fb7c9..fe2fefb1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUtils.java
@@ -17,6 +17,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.ui.base.DeviceFormFactor;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.display.DisplayAndroidManager;
 
@@ -89,10 +90,16 @@
     }
 
     /**
+     * Check if the tab is large enough for displaying desktop sites. This method will only check
+     * for tablets, if the device is a phone, will return false regardless of tab size.
      * @param tab The tab to be checked if the size is large enough for desktop site.
      * @return Whether or not the screen size is large enough for desktop sites.
      */
     public static boolean isTabLargeEnoughForDesktopSite(Tab tab) {
+        if (!DeviceFormFactor.isNonMultiDisplayContextOnTablet(tab.getContext())) {
+            // The device is a phone, do not check the tab size.
+            return false;
+        }
         Activity activity = ((TabImpl) tab).getActivity();
         if (activity == null) {
             // It is possible that we are in custom tabs or tests, and need to access the activity
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index ae93a17..6306ad5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -860,18 +860,20 @@
         mFindToolbarManager = findToolbarManager;
         mFindToolbarManager.addObserver(mFindToolbarObserver);
 
+        int toolbarHeight =
+                mActivity.getResources().getDimensionPixelOffset(R.dimen.toolbar_height_no_shadow);
         startSurfaceSupplier.onAvailable(mCallbackController.makeCancelable((startSurface) -> {
             mStartSurface = startSurface;
             mStartSurfaceStateObserver = (newState, shouldShowToolbar) -> {
                 assert StartSurfaceConfiguration.isStartSurfaceEnabled();
                 mStartSurfaceState = newState;
-                mToolbar.updateStartSurfaceToolbarState(newState, shouldShowToolbar);
+                mToolbar.updateStartSurfaceToolbarState(newState, shouldShowToolbar, toolbarHeight);
             };
             mStartSurface.addStateChangeObserver(mStartSurfaceStateObserver);
 
             mStartSurfaceHeaderOffsetChangeListener = (appbarLayout, verticalOffset) -> {
                 assert StartSurfaceConfiguration.isStartSurfaceEnabled();
-                mToolbar.onStartSurfaceHeaderOffsetChanged(verticalOffset);
+                mToolbar.onStartSurfaceHeaderOffsetChanged(verticalOffset, toolbarHeight);
             };
             mStartSurface.addHeaderOffsetChangeListener(mStartSurfaceHeaderOffsetChangeListener);
         }));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarCoordinator.java
index 9dbb9f2..d73adffa 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarCoordinator.java
@@ -228,14 +228,15 @@
 
     /**
      * @param toolbarHeight The height of start surface toolbar.
-     * @return Whether or not toolbar layout view should be hidden.
+     * @return Whether or not toolbar phone layout view should be shown.
      */
-    boolean shouldHideToolbarLayout(int toolbarHeight) {
-        return mToolbarMediator.shouldHideToolbarLayout(toolbarHeight);
+    boolean shouldShowRealSearchBox(int toolbarHeight) {
+        return mToolbarMediator.shouldShowRealSearchBox(toolbarHeight);
     }
 
-    boolean isToolbarOnScreenTop() {
-        return mToolbarMediator.isToolbarOnScreenTop();
+    /** Returns whether it's on the start surface homepage.*/
+    boolean isOnHomepage() {
+        return mToolbarMediator.isOnHomepage();
     }
 
     void onNativeLibraryReady() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java
index 6b2f7a1..16779d6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java
@@ -175,23 +175,54 @@
         updateTranslationY(verticalOffset);
     }
 
-    boolean shouldHideToolbarLayout(int toolbarHeight) {
-        // If it's on the non-incognito homepage, start surface toolbar is visible (omnibox has no
-        // focus), and scrolling offset is smaller than toolbar's height, we need to hide toolbar
-        // layout until start surface toolbar is disappearing.
-        // When mPropertyModel.get(TRANSLATION_Y) is 0, we cannot hide toolbar layout, otherwise
-        // previous toolbar focus may be cleared.
-        return mOverviewModeState == StartSurfaceState.SHOWN_HOMEPAGE
-                && !mPropertyModel.get(IS_INCOGNITO) && mPropertyModel.get(IS_VISIBLE)
-                && -mPropertyModel.get(TRANSLATION_Y) != 0
-                && -mPropertyModel.get(TRANSLATION_Y) < toolbarHeight;
+    /**
+     * The real omnibox should be shown in three cases:
+     * 1. It's on the homepage, the url is focused and start surface toolbar is not visible.
+     * 2. It's on the homepage and the start surface toolbar is scrolled off.
+     * 3. It's on a tab.
+     *
+     * In the other cases:
+     * 1. It's on the homepage and start surface toolbar is at least partially shown -- the user
+     *    sees the fake search box.
+     * 2. It's on the tab switcher surface, there is no search box (fake or real).
+     *
+     * @param toolbarHeight The height of start surface toolbar.
+     * @return Whether toolbar layout should be shown.
+     */
+    boolean shouldShowRealSearchBox(int toolbarHeight) {
+        return isRealSearchBoxFocused() || isStartSurfaceToolbarScrolledOff(toolbarHeight)
+                || isOnATab();
     }
 
-    boolean isToolbarOnScreenTop() {
-        return (mOverviewModeState == StartSurfaceState.SHOWN_HOMEPAGE
-                       || mOverviewModeState == StartSurfaceState.SHOWN_TABSWITCHER)
-                && !mPropertyModel.get(IS_INCOGNITO) && mPropertyModel.get(IS_VISIBLE)
-                && mPropertyModel.get(TRANSLATION_Y) == 0;
+    /** Returns whether it's on the start surface homepage. */
+    boolean isOnHomepage() {
+        return mOverviewModeState == StartSurfaceState.SHOWN_HOMEPAGE;
+    }
+
+    /** Returns whether it's on a normal tab. */
+    private boolean isOnATab() {
+        return mOverviewModeState == StartSurfaceState.NOT_SHOWN;
+    }
+
+    /**
+     * When mPropertyModel.get(IS_VISIBLE) is false on the homepage, start surface toolbar and fake
+     * search box are not shown and the real search box is focused.
+     * @return Whether the real search box is focused.
+     */
+    private boolean isRealSearchBoxFocused() {
+        return isOnHomepage() && !mPropertyModel.get(IS_VISIBLE);
+    }
+
+    /**
+     * Start surface toolbar is only scrolled on the homepage. When scrolling offset is larger than
+     * toolbar height, start surface toolbar is scrolled out of the screen.
+     *
+     * @param toolbarHeight The height of start surface toolbar.
+     * @return Whether the start surface toolbar is scrolled out of the screen.
+     */
+    private boolean isStartSurfaceToolbarScrolledOff(int toolbarHeight) {
+        return mPropertyModel.get(IS_VISIBLE)
+                && -mPropertyModel.get(TRANSLATION_Y) >= toolbarHeight;
     }
 
     void setOnNewTabClickHandler(View.OnClickListener listener) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
index cf6f4a2..a7dc9275 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
@@ -605,9 +605,10 @@
 
     /**
      * Called when start surface state is changed.
+     * @param shouldBeVisible Whether toolbar layout should be visible.
      * @param isShowingStartSurface Whether start surface homepage is showing.
      */
-    void onStartSurfaceStateChanged(boolean isShowingStartSurface) {}
+    void onStartSurfaceStateChanged(boolean shouldBeVisible, boolean isShowingStartSurface) {}
 
     /**
      * Force to hide toolbar shadow.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
index 197629d9..1699bfb4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
@@ -139,7 +139,7 @@
 
     @ViewDebug.ExportedProperty(category = "chrome")
     protected int mTabSwitcherState;
-    private boolean mIsShowingStartSurface;
+    private boolean mForceExpansionOnStartSurface;
     private boolean mForceHideShadow;
 
     // This determines whether or not the toolbar draws as expected (false) or whether it always
@@ -1756,8 +1756,11 @@
     }
 
     private void updateProgressBarVisibility() {
-        getProgressBar().setVisibility(
-                mIsShowingStartSurface || mTabSwitcherState != STATIC_TAB ? INVISIBLE : VISIBLE);
+        getProgressBar().setVisibility(mTabSwitcherState != STATIC_TAB ? INVISIBLE : VISIBLE);
+    }
+
+    private void forceHideProgressBar() {
+        getProgressBar().setVisibility(INVISIBLE);
     }
 
     @Override
@@ -1854,26 +1857,38 @@
     }
 
     @Override
-    void onStartSurfaceStateChanged(boolean isShowingStartSurface) {
-        super.onStartSurfaceStateChanged(isShowingStartSurface);
-        mIsShowingStartSurface = isShowingStartSurface;
-        updateUrlExpansionState();
+    void onStartSurfaceStateChanged(boolean shouldBeVisible, boolean isShowingStartSurface) {
+        super.onStartSurfaceStateChanged(shouldBeVisible, isShowingStartSurface);
+
+        // Update visibilities of toolbar layout, progress bar and shadow.
+        setVisibility(shouldBeVisible ? VISIBLE : GONE);
+        forceHideProgressBar();
+        setForceHideShadow(!shouldBeVisible);
+        // Url bar should be focusable. This will be set in UrlBar#onDraw but there's a delay which
+        // may cause focus to fail, so set here too.
+        mLocationBar.setUrlBarFocusable(true);
+
+        // Toolbar should be expanded when it's shown on the start surface homepage.
+        boolean shouldExpandToolbar = shouldBeVisible && isShowingStartSurface;
+        if (mForceExpansionOnStartSurface != shouldExpandToolbar) {
+            mForceExpansionOnStartSurface = shouldExpandToolbar;
+            updateUrlExpansionState();
+        }
     }
 
     /**
      * Update url expansion state when start surface state is changed. If start surface homepage is
-     * showing, |mIsShowingStartSurface| is set to true, and toolbar is always expanded. Otherwise
-     * expansion state is consistent with urlHasFocus().
+     * showing and start surface toolbar is scrolled off, |mForceExpansionOnStartSurface| is set to
+     * true, and toolbar is always expanded. Otherwise expansion state is consistent with
+     * urlHasFocus().
      */
     private void updateUrlExpansionState() {
         if (mToggleTabStackButton != null) {
-            boolean isGone = mIsShowingStartSurface;
+            boolean isGone = mForceExpansionOnStartSurface;
             mToggleTabStackButton.setVisibility(isGone ? GONE : VISIBLE);
         }
 
-        getMenuButtonCoordinator().setVisibility(!mIsShowingStartSurface);
-        updateProgressBarVisibility();
-
+        getMenuButtonCoordinator().setVisibility(!mForceExpansionOnStartSurface);
         // The URL focusing animator set shouldn't be populated before native initialization. It is
         // possible that this function is called before native initialization when Instant Start
         // is enabled.
@@ -2095,7 +2110,7 @@
 
         // On start surface omnibox should be always expanded without being focused, while whether
         // the keyboard should show up or not depends on whether url has focus.
-        if (mIsShowingStartSurface) {
+        if (mForceExpansionOnStartSurface) {
             showExpandedState = true;
         }
 
@@ -2115,6 +2130,11 @@
         mUrlFocusLayoutAnimator = new AnimatorSet();
         mUrlFocusLayoutAnimator.playTogether(animators);
 
+        // If it's on start surface, the animation is processed by StartSurfaceToolbar and we only
+        // want expanded toolbar phone layout. This expansion animation will cause unnecessary
+        // flicker.
+        if (mForceExpansionOnStartSurface) mUrlFocusLayoutAnimator.setDuration(0);
+
         mUrlFocusChangeInProgress = true;
         // |showExpandedState| needs to be final when accessed within inner class.
         final boolean showExpandedStateFinal = showExpandedState;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
index 91b5dcee..b82327e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
@@ -652,39 +652,35 @@
      * Update the start surface toolbar state.
      * @param newState New Start Surface State.
      * @param requestToShow Whether or not request showing the start surface toolbar.
+     * @param toolbarHeight The height of start surface toolbar.
      */
     public void updateStartSurfaceToolbarState(
-            @StartSurfaceState int newState, boolean requestToShow) {
+            @StartSurfaceState int newState, boolean requestToShow, int toolbarHeight) {
         if (mStartSurfaceToolbarCoordinator == null
                 || mToolbarLayout.getToolbarDataProvider() == null) {
             return;
         }
         mStartSurfaceToolbarCoordinator.onStartSurfaceStateChanged(newState, requestToShow);
-        mToolbarLayout.onStartSurfaceStateChanged(newState == StartSurfaceState.SHOWN_HOMEPAGE);
-        updateToolbarLayoutVisibility();
+        updateToolbarLayoutVisibility(toolbarHeight);
     }
 
     /**
      * Triggered when the offset of start surface header view is changed.
      * @param verticalOffset The start surface header view's offset.
+     * @param toolbarHeight The height of start surface toolbar.
      */
-    public void onStartSurfaceHeaderOffsetChanged(int verticalOffset) {
+    public void onStartSurfaceHeaderOffsetChanged(int verticalOffset, int toolbarHeight) {
         if (mStartSurfaceToolbarCoordinator != null) {
             mStartSurfaceToolbarCoordinator.onStartSurfaceHeaderOffsetChanged(verticalOffset);
-            updateToolbarLayoutVisibility();
+            updateToolbarLayoutVisibility(toolbarHeight);
         }
     }
 
-    private void updateToolbarLayoutVisibility() {
+    private void updateToolbarLayoutVisibility(int toolbarHeight) {
         assert mStartSurfaceToolbarCoordinator != null;
-        boolean shouldHideToolbarLayout =
-                mStartSurfaceToolbarCoordinator.shouldHideToolbarLayout(getHeight());
-        mToolbarLayout.setVisibility(shouldHideToolbarLayout ? View.INVISIBLE : View.VISIBLE);
-        // When start surface toolbar is shown on the top of the screen, toolbar shadow is hidden.
-        // On start surface homepage, toolbar shadow should be shown only when start surface toolbar
-        // is scrolled out of screen. On tab switcher page, TabListRecyclerView handles another
-        // shadow.
-        mToolbarLayout.setForceHideShadow(mStartSurfaceToolbarCoordinator.isToolbarOnScreenTop());
+        mToolbarLayout.onStartSurfaceStateChanged(
+                mStartSurfaceToolbarCoordinator.shouldShowRealSearchBox(toolbarHeight),
+                mStartSurfaceToolbarCoordinator.isOnHomepage());
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
index b2e082e..e5794e2 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
@@ -36,6 +36,7 @@
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabObserver;
+import org.chromium.chrome.browser.tab.TabUtils;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelUtils;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
@@ -290,8 +291,8 @@
         final Tab tab = mActivityTestRule.getActivity().getActivityTab();
         TestThreadUtils.runOnUiThreadBlocking(
                 ()
-                        -> tab.getWebContents().getNavigationController().setUseDesktopUserAgent(
-                                true /* useDesktop */, true /* reloadOnChange */));
+                        -> TabUtils.switchUserAgent(
+                                tab, /* switchToDesktop */ true, /* forcedByUser */ true));
         ChromeTabUtils.waitForTabPageLoaded(tab, url1);
 
         navigateAndObserve(url2, url2);
@@ -323,8 +324,8 @@
         final Tab tab = mActivityTestRule.getActivity().getActivityTab();
         TestThreadUtils.runOnUiThreadBlocking(
                 ()
-                        -> tab.getWebContents().getNavigationController().setUseDesktopUserAgent(
-                                true /* useDesktop */, true /* reloadOnChange */));
+                        -> TabUtils.switchUserAgent(
+                                tab, /* switchToDesktop */ true, /* forcedByUser */ true));
 
         navigateAndObserve(url, url);
         ChromeTabUtils.waitForTabPageLoaded(tab, url);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/language/DEPS b/chrome/android/javatests/src/org/chromium/chrome/browser/language/DEPS
new file mode 100644
index 0000000..b2d7c09522
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/language/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+components/language/android"
+]
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/language/GlobalAppLocaleControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/language/GlobalAppLocaleControllerTest.java
new file mode 100644
index 0000000..97efba6
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/language/GlobalAppLocaleControllerTest.java
@@ -0,0 +1,50 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.language;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.components.language.AndroidLanguageMetricsBridge;
+
+/**
+ * Tests for the GlobalAppLocaleController class.
+ */
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+public class GlobalAppLocaleControllerTest {
+    private static final int EMPTY_STRING_HASH = -1895779836;
+
+    @Rule
+    public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
+
+    @Before
+    public void setUp() throws Exception {
+        mActivityTestRule.startMainActivityOnBlankPage();
+    }
+
+    @Test
+    @SmallTest
+    public void testStartupHistograms() {
+        CriteriaHelper.pollUiThread(() -> {
+            // The initial app language is the default system language recorded as the empty string.
+            Assert.assertEquals(1,
+                    RecordHistogram.getHistogramValueCountForTesting(
+                            AndroidLanguageMetricsBridge.OVERRIDE_LANGUAGE_HISTOGRAM,
+                            EMPTY_STRING_HASH));
+        });
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java
index b5adae2..8875e46d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java
@@ -297,7 +297,7 @@
         final int maximumListHeight = SUGGESTION_MIN_HEIGHT * 2;
 
         mMediator.onSuggestionDropdownHeightChanged(maximumListHeight);
-        mMediator.onSuggestionsReceived(new AutocompleteResult(mSuggestionsList, null), "");
+        mMediator.onSuggestionsReceived(AutocompleteResult.fromCache(mSuggestionsList, null), "");
 
         Assert.assertEquals(mSuggestionsList.size(), mSuggestionModels.size());
         Assert.assertTrue(mListModel.get(SuggestionListProperties.VISIBLE));
@@ -313,7 +313,7 @@
         final int maximumListHeight = SUGGESTION_MIN_HEIGHT * 7;
 
         mMediator.onSuggestionDropdownHeightChanged(maximumListHeight);
-        mMediator.onSuggestionsReceived(new AutocompleteResult(null, null), "");
+        mMediator.onSuggestionsReceived(AutocompleteResult.EMPTY_RESULT, "");
 
         Assert.assertEquals(0, mSuggestionModels.size());
         Assert.assertFalse(mListModel.get(SuggestionListProperties.VISIBLE));
@@ -329,7 +329,7 @@
         final int maximumListHeight = SUGGESTION_MIN_HEIGHT * 7;
 
         mMediator.onSuggestionDropdownHeightChanged(maximumListHeight);
-        mMediator.onSuggestionsReceived(new AutocompleteResult(new ArrayList<>(), null), "");
+        mMediator.onSuggestionsReceived(AutocompleteResult.EMPTY_RESULT, "");
 
         Assert.assertEquals(0, mSuggestionModels.size());
         Assert.assertFalse(mListModel.get(SuggestionListProperties.VISIBLE));
@@ -346,7 +346,7 @@
                 (mSuggestionsList.size() - 2) * SUGGESTION_MIN_HEIGHT;
 
         mMediator.onSuggestionDropdownHeightChanged(heightWithOneConcealedItem);
-        mMediator.onSuggestionsReceived(new AutocompleteResult(mSuggestionsList, null), "");
+        mMediator.onSuggestionsReceived(AutocompleteResult.fromCache(mSuggestionsList, null), "");
         Assert.assertTrue(
                 mMediator.getDropdownItemViewInfoListBuilderForTest().hasFullyConcealedElements());
 
@@ -391,7 +391,7 @@
         // In both cases, the updated suggestions list height should be used to estimate presence of
         // fully concealed items on the suggestions list.
         mMediator.onSuggestionDropdownHeightChanged(heightOfOAllSuggestions);
-        mMediator.onSuggestionsReceived(new AutocompleteResult(mSuggestionsList, null), "");
+        mMediator.onSuggestionsReceived(AutocompleteResult.fromCache(mSuggestionsList, null), "");
         Assert.assertFalse(
                 mMediator.getDropdownItemViewInfoListBuilderForTest().hasFullyConcealedElements());
 
@@ -402,7 +402,7 @@
         List<AutocompleteMatch> newList =
                 buildDummySuggestionsList(mSuggestionsList.size(), "SuggestionB");
         mMediator.onSuggestionDropdownHeightChanged(heightWithOneConcealedItem);
-        mMediator.onSuggestionsReceived(new AutocompleteResult(newList, null), "");
+        mMediator.onSuggestionsReceived(AutocompleteResult.fromCache(newList, null), "");
         Assert.assertTrue(
                 mMediator.getDropdownItemViewInfoListBuilderForTest().hasFullyConcealedElements());
     }
@@ -423,7 +423,7 @@
 
         // Report height change with keyboard visible
         mMediator.onSuggestionDropdownHeightChanged(heightWithOneConcealedItem);
-        mMediator.onSuggestionsReceived(new AutocompleteResult(mSuggestionsList, null), "");
+        mMediator.onSuggestionsReceived(AutocompleteResult.fromCache(mSuggestionsList, null), "");
         Assert.assertTrue(
                 mMediator.getDropdownItemViewInfoListBuilderForTest().hasFullyConcealedElements());
 
@@ -432,7 +432,7 @@
         // is active.
         when(mAutocompleteDelegate.isKeyboardActive()).thenReturn(false);
         mMediator.onSuggestionDropdownHeightChanged(heightOfOAllSuggestions);
-        mMediator.onSuggestionsReceived(new AutocompleteResult(mSuggestionsList, null), "");
+        mMediator.onSuggestionsReceived(AutocompleteResult.fromCache(mSuggestionsList, null), "");
         Assert.assertTrue(
                 mMediator.getDropdownItemViewInfoListBuilderForTest().hasFullyConcealedElements());
     }
@@ -637,12 +637,12 @@
     public void onSuggestionsReceived_sendsOnSuggestionsChanged() {
         mMediator.onNativeInitialized();
         mMediator.onSuggestionsReceived(
-                new AutocompleteResult(mSuggestionsList, null), "inline_autocomplete");
+                AutocompleteResult.fromCache(mSuggestionsList, null), "inline_autocomplete");
         verify(mAutocompleteDelegate).onSuggestionsChanged("inline_autocomplete", true);
 
         // Ensure duplicate requests are suppressed.
         mMediator.onSuggestionsReceived(
-                new AutocompleteResult(mSuggestionsList, null), "inline_autocomplete2");
+                AutocompleteResult.fromCache(mSuggestionsList, null), "inline_autocomplete2");
         verifyNoMoreInteractions(mAutocompleteDelegate);
     }
 
@@ -654,7 +654,7 @@
         mMediator.onNativeInitialized();
         mMediator.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
         mMediator.onSuggestionDropdownHeightChanged(Integer.MAX_VALUE);
-        mMediator.onSuggestionsReceived(new AutocompleteResult(mSuggestionsList, null), "");
+        mMediator.onSuggestionsReceived(AutocompleteResult.fromCache(mSuggestionsList, null), "");
         Assert.assertEquals(mSuggestionsList.size(), mSuggestionModels.size());
         for (int i = 0; i < mSuggestionModels.size(); i++) {
             Assert.assertEquals(i + "th model does not have the expected layout direction.",
@@ -671,7 +671,7 @@
     public void setLayoutDirection_afterInitialization() {
         mMediator.onNativeInitialized();
         mMediator.onSuggestionDropdownHeightChanged(Integer.MAX_VALUE);
-        mMediator.onSuggestionsReceived(new AutocompleteResult(mSuggestionsList, null), "");
+        mMediator.onSuggestionsReceived(AutocompleteResult.fromCache(mSuggestionsList, null), "");
         Assert.assertEquals(mSuggestionsList.size(), mSuggestionModels.size());
 
         mMediator.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/CachedZeroSuggestionsManagerUnitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/CachedZeroSuggestionsManagerUnitTest.java
index 8ab59c2..7501d55 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/CachedZeroSuggestionsManagerUnitTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/CachedZeroSuggestionsManagerUnitTest.java
@@ -112,7 +112,7 @@
     @UiThreadTest
     public void setNewSuggestions_cachedSuggestionsWithPostdataBeforeAndAfterAreSame() {
         AutocompleteResult dataToCache =
-                new AutocompleteResult(buildDummySuggestionsList(2, true), null);
+                AutocompleteResult.fromCache(buildDummySuggestionsList(2, true), null);
         CachedZeroSuggestionsManager.saveToCache(dataToCache);
         AutocompleteResult dataFromCache = CachedZeroSuggestionsManager.readFromCache();
         assertAutocompleteResultEquals(dataToCache, dataFromCache);
@@ -123,7 +123,7 @@
     @UiThreadTest
     public void setNewSuggestions_cachedSuggestionsWithoutPostdataBeforeAndAfterAreSame() {
         AutocompleteResult dataToCache =
-                new AutocompleteResult(buildDummySuggestionsList(2, false), null);
+                AutocompleteResult.fromCache(buildDummySuggestionsList(2, false), null);
         CachedZeroSuggestionsManager.saveToCache(dataToCache);
         AutocompleteResult dataFromCache = CachedZeroSuggestionsManager.readFromCache();
         assertAutocompleteResultEquals(dataToCache, dataFromCache);
@@ -142,8 +142,8 @@
                 Arrays.asList(createSuggestionBuilder(2, OmniboxSuggestionType.HISTORY_URL).build(),
                         createSuggestionBuilder(4, OmniboxSuggestionType.SEARCH_HISTORY).build());
 
-        AutocompleteResult dataToCache = new AutocompleteResult(mix_list, null);
-        AutocompleteResult dataToExpected = new AutocompleteResult(expected_list, null);
+        AutocompleteResult dataToCache = AutocompleteResult.fromCache(mix_list, null);
+        AutocompleteResult dataToExpected = AutocompleteResult.fromCache(expected_list, null);
         CachedZeroSuggestionsManager.saveToCache(dataToCache);
         AutocompleteResult dataFromCache = CachedZeroSuggestionsManager.readFromCache();
         assertAutocompleteResultEquals(dataToExpected, dataFromCache);
@@ -155,7 +155,7 @@
     public void groupsDetails_restoreDetailsFromEmptyCache() {
         // Note: purge cache explicitly, because tests are run on an actual device
         // and cache may hold content from other test runs.
-        AutocompleteResult dataToCache = new AutocompleteResult(null, null);
+        AutocompleteResult dataToCache = AutocompleteResult.EMPTY_RESULT;
         CachedZeroSuggestionsManager.saveToCache(dataToCache);
         AutocompleteResult dataFromCache = CachedZeroSuggestionsManager.readFromCache();
         assertAutocompleteResultEquals(dataToCache, dataFromCache);
@@ -169,7 +169,7 @@
         groupsDetails.put(10, new GroupDetails("Header For Group 10", false));
         groupsDetails.put(20, new GroupDetails("Header For Group 20", false));
         groupsDetails.put(30, new GroupDetails("Header For Group 30", false));
-        AutocompleteResult dataToCache = new AutocompleteResult(null, groupsDetails);
+        AutocompleteResult dataToCache = AutocompleteResult.fromCache(null, groupsDetails);
         CachedZeroSuggestionsManager.saveToCache(dataToCache);
         AutocompleteResult dataFromCache = CachedZeroSuggestionsManager.readFromCache();
         assertAutocompleteResultEquals(dataToCache, dataFromCache);
@@ -185,14 +185,14 @@
                 AutocompleteMatch.INVALID_GROUP, new GroupDetails("Header For Group 20", true));
         groupsDetails.put(30, new GroupDetails("", false));
 
-        AutocompleteResult dataToCache = new AutocompleteResult(null, groupsDetails);
+        AutocompleteResult dataToCache = AutocompleteResult.fromCache(null, groupsDetails);
         CachedZeroSuggestionsManager.saveToCache(dataToCache);
         AutocompleteResult dataFromCache = CachedZeroSuggestionsManager.readFromCache();
 
         SparseArray<GroupDetails> validGroupsDetails = new SparseArray<>();
         validGroupsDetails.put(10, new GroupDetails("Header For Group 10", false));
         assertAutocompleteResultEquals(
-                dataFromCache, new AutocompleteResult(null, validGroupsDetails));
+                dataFromCache, AutocompleteResult.fromCache(null, validGroupsDetails));
     }
 
     @Test
@@ -205,10 +205,10 @@
         groupsDetails.put(20, new GroupDetails("", false));
         groupsDetails.put(30, new GroupDetails("", false));
 
-        AutocompleteResult dataToCache = new AutocompleteResult(null, groupsDetails);
+        AutocompleteResult dataToCache = AutocompleteResult.fromCache(null, groupsDetails);
         CachedZeroSuggestionsManager.saveToCache(dataToCache);
         AutocompleteResult dataFromCache = CachedZeroSuggestionsManager.readFromCache();
-        assertAutocompleteResultEquals(dataFromCache, new AutocompleteResult(null, null));
+        assertAutocompleteResultEquals(dataFromCache, AutocompleteResult.EMPTY_RESULT);
     }
 
     @Test
@@ -220,7 +220,7 @@
         SparseArray<GroupDetails> groupsDetails = new SparseArray<>();
         groupsDetails.put(1, new GroupDetails("Valid Header", true));
 
-        AutocompleteResult dataToCache = new AutocompleteResult(list, groupsDetails);
+        AutocompleteResult dataToCache = AutocompleteResult.fromCache(list, groupsDetails);
         CachedZeroSuggestionsManager.saveToCache(dataToCache);
         AutocompleteResult dataFromCache = CachedZeroSuggestionsManager.readFromCache();
         assertAutocompleteResultEquals(dataToCache, dataFromCache);
@@ -234,8 +234,8 @@
         List<AutocompleteMatch> listToCache = buildDummySuggestionsList(2, false);
         listToCache.add(createSuggestionBuilder(33).setGroupId(1).build());
 
-        AutocompleteResult dataExpected = new AutocompleteResult(listExpected, null);
-        AutocompleteResult dataToCache = new AutocompleteResult(listToCache, null);
+        AutocompleteResult dataExpected = AutocompleteResult.fromCache(listExpected, null);
+        AutocompleteResult dataToCache = AutocompleteResult.fromCache(listToCache, null);
         CachedZeroSuggestionsManager.saveToCache(dataToCache);
         AutocompleteResult dataFromCache = CachedZeroSuggestionsManager.readFromCache();
         assertAutocompleteResultEquals(dataExpected, dataFromCache);
@@ -252,7 +252,7 @@
 
         // Save one valid suggestion to cache.
         AutocompleteResult dataToCache =
-                new AutocompleteResult(buildDummySuggestionsList(1, true), null);
+                AutocompleteResult.fromCache(buildDummySuggestionsList(1, true), null);
         CachedZeroSuggestionsManager.saveToCache(dataToCache);
 
         // Signal that there's actually 2 items in the cache.
@@ -261,7 +261,7 @@
         // Construct an expected raw suggestion list content. This constitutes one valid entry
         // and 1 totally empty entry.
         AutocompleteResult rawDataFromCache =
-                new AutocompleteResult(buildDummySuggestionsList(1, true), null);
+                AutocompleteResult.fromCache(buildDummySuggestionsList(1, true), null);
         rawDataFromCache.getSuggestionsList().add(new AutocompleteMatchBuilder().build());
 
         // readCachedSuggestionList makes full attempt to restore whatever could be scraped from the
@@ -269,7 +269,8 @@
         List<AutocompleteMatch> readList =
                 CachedZeroSuggestionsManager.readCachedSuggestionList(manager);
         Assert.assertEquals(2, readList.size());
-        assertAutocompleteResultEquals(new AutocompleteResult(readList, null), rawDataFromCache);
+        assertAutocompleteResultEquals(
+                AutocompleteResult.fromCache(readList, null), rawDataFromCache);
 
         // Cache recovery however should be smart here and remove items that make no sense.
         AutocompleteResult dataFromCache = CachedZeroSuggestionsManager.readFromCache();
@@ -290,7 +291,7 @@
         groupsDetails.put(12, new GroupDetails("Valid group", true));
         groupsDetails.put(34, new GroupDetails("", false));
         groupsDetails.put(AutocompleteMatch.INVALID_GROUP, new GroupDetails("Invalid group", true));
-        AutocompleteResult invalidDataToCache = new AutocompleteResult(null, groupsDetails);
+        AutocompleteResult invalidDataToCache = AutocompleteResult.fromCache(null, groupsDetails);
         CachedZeroSuggestionsManager.saveToCache(invalidDataToCache);
 
         // Report that we actually have 4 items in the cache.
@@ -313,7 +314,8 @@
         // Cache recovery however should be smart here and remove items that make no sense.
         SparseArray<GroupDetails> wantGroupsDetails = new SparseArray<>();
         wantGroupsDetails.put(12, new GroupDetails("Valid group", true));
-        AutocompleteResult wantDataFromCache = new AutocompleteResult(null, wantGroupsDetails);
+        AutocompleteResult wantDataFromCache =
+                AutocompleteResult.fromCache(null, wantGroupsDetails);
         AutocompleteResult dataFromCache = CachedZeroSuggestionsManager.readFromCache();
 
         assertAutocompleteResultEquals(dataFromCache, wantDataFromCache);
@@ -343,9 +345,9 @@
         listWithInvalidItems.add(createSuggestionBuilder(74).setGroupId(34).build());
 
         AutocompleteResult dataWithInvalidItems =
-                new AutocompleteResult(listWithInvalidItems, groupsDetailsWithInvalidItems);
+                AutocompleteResult.fromCache(listWithInvalidItems, groupsDetailsWithInvalidItems);
         AutocompleteResult dataExpected =
-                new AutocompleteResult(listExpected, groupsDetailsExpected);
+                AutocompleteResult.fromCache(listExpected, groupsDetailsExpected);
 
         CachedZeroSuggestionsManager.removeInvalidSuggestionsAndGroupsDetails(
                 dataWithInvalidItems.getSuggestionsList(), dataWithInvalidItems.getGroupsDetails());
@@ -371,7 +373,7 @@
                         .build(),
                 createSuggestionBuilder(4, OmniboxSuggestionType.SEARCH_HISTORY).build());
 
-        AutocompleteResult dataToCache = new AutocompleteResult(list, null);
+        AutocompleteResult dataToCache = AutocompleteResult.fromCache(list, null);
         CachedZeroSuggestionsManager.saveToCache(dataToCache);
         AutocompleteResult dataFromCache = CachedZeroSuggestionsManager.readFromCache();
         assertAutocompleteResultEquals(dataToCache, dataFromCache);
@@ -390,7 +392,7 @@
                         .addSubtype(17)
                         .build());
 
-        AutocompleteResult dataToCache = new AutocompleteResult(list, null);
+        AutocompleteResult dataToCache = AutocompleteResult.fromCache(list, null);
         CachedZeroSuggestionsManager.saveToCache(dataToCache);
 
         // Insert garbage for the Suggestion Subtypes.
@@ -402,7 +404,7 @@
                 garbageSubtypes);
 
         AutocompleteResult dataFromCache = CachedZeroSuggestionsManager.readFromCache();
-        assertAutocompleteResultEquals(new AutocompleteResult(null, null), dataFromCache);
+        assertAutocompleteResultEquals(AutocompleteResult.EMPTY_RESULT, dataFromCache);
     }
 
     @Test
@@ -414,7 +416,7 @@
                         .addSubtype(1)
                         .build());
 
-        AutocompleteResult dataToCache = new AutocompleteResult(list, null);
+        AutocompleteResult dataToCache = AutocompleteResult.fromCache(list, null);
         CachedZeroSuggestionsManager.saveToCache(dataToCache);
 
         final SharedPreferencesManager manager = SharedPreferencesManager.getInstance();
@@ -425,6 +427,6 @@
                 garbageSubtypes);
 
         AutocompleteResult dataFromCache = CachedZeroSuggestionsManager.readFromCache();
-        assertAutocompleteResultEquals(new AutocompleteResult(null, null), dataFromCache);
+        assertAutocompleteResultEquals(AutocompleteResult.EMPTY_RESULT, dataFromCache);
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/DropdownItemViewInfoListBuilderUnitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/DropdownItemViewInfoListBuilderUnitTest.java
index 565c074..b021b73 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/DropdownItemViewInfoListBuilderUnitTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/DropdownItemViewInfoListBuilderUnitTest.java
@@ -122,7 +122,7 @@
 
         final InOrder verifier = inOrder(mMockSuggestionProcessor, mMockHeaderProcessor);
         final List<DropdownItemViewInfo> model = mBuilder.buildDropdownViewInfoList(
-                new AutocompleteResult(actualList, groupsDetails));
+                AutocompleteResult.fromCache(actualList, groupsDetails));
 
         verifier.verify(mMockHeaderProcessor, times(1)).populateModel(any(), eq(1), eq("Header 1"));
         verifier.verify(mMockSuggestionProcessor, times(1))
@@ -172,7 +172,7 @@
 
         final InOrder verifier = inOrder(mMockSuggestionProcessor, mMockHeaderProcessor);
         final List<DropdownItemViewInfo> model = mBuilder.buildDropdownViewInfoList(
-                new AutocompleteResult(actualList, groupsDetails));
+                AutocompleteResult.fromCache(actualList, groupsDetails));
 
         verifier.verify(mMockSuggestionProcessor, times(1))
                 .populateModel(eq(suggestionWithNoGroup), any(), eq(0));
@@ -245,15 +245,15 @@
                 .thenReturn(true);
         // Create AutocompleteResult with a lot of suggestions.
         final AutocompleteMatch match = builder.build();
-        final AutocompleteResult result = new AutocompleteResult(
+        final AutocompleteResult result = AutocompleteResult.fromCache(
                 Arrays.asList(match, match, match, match, match, match, match, match, match, match),
                 null);
         Assert.assertEquals(5, mBuilder.getVisibleSuggestionsCount(result));
 
         // Same, with a shorter list of suggestions; in this case we don't know the height of the
         // dropdown view, so we assume we can comfortably fit 5 suggestions.
-        final AutocompleteResult shortResult =
-                new AutocompleteResult(Arrays.asList(match, match, match, match, match), null);
+        final AutocompleteResult shortResult = AutocompleteResult.fromCache(
+                Arrays.asList(match, match, match, match, match), null);
         Assert.assertEquals(5, mBuilder.getVisibleSuggestionsCount(shortResult));
     }
 
@@ -268,7 +268,7 @@
         final AutocompleteMatchBuilder builder =
                 AutocompleteMatchBuilder.searchWithType(OmniboxSuggestionType.SEARCH_SUGGEST);
         final AutocompleteMatch match = builder.build();
-        final AutocompleteResult result = new AutocompleteResult(
+        final AutocompleteResult result = AutocompleteResult.fromCache(
                 Arrays.asList(match, match, match, match, match, match, match, match, match, match),
                 null);
 
@@ -291,7 +291,7 @@
         when(mMockSuggestionProcessor.doesProcessSuggestion(any(AutocompleteMatch.class), anyInt()))
                 .thenReturn(true);
         final AutocompleteMatch match = builder.build();
-        final AutocompleteResult result = new AutocompleteResult(
+        final AutocompleteResult result = AutocompleteResult.fromCache(
                 Arrays.asList(match, match, match, match, match, match, match, match, match, match),
                 null);
 
@@ -317,7 +317,7 @@
         final AutocompleteMatch match2 = builder.setDescription("2").build();
         final AutocompleteMatch match3 = builder.setDescription("3").build();
         final AutocompleteResult result =
-                new AutocompleteResult(Arrays.asList(match1, match2, match3), null);
+                AutocompleteResult.fromCache(Arrays.asList(match1, match2, match3), null);
 
         // Heights reported by processors for suggestions 1, 2 and 3.
         when(mMockSuggestionProcessor.doesProcessSuggestion(eq(match1), anyInt())).thenReturn(true);
@@ -360,8 +360,8 @@
                         .build();
         final int viewHeight = 20;
 
-        final AutocompleteResult result =
-                new AutocompleteResult(Arrays.asList(suggestion, suggestion, suggestion), null);
+        final AutocompleteResult result = AutocompleteResult.fromCache(
+                Arrays.asList(suggestion, suggestion, suggestion), null);
         when(mMockSuggestionProcessor.doesProcessSuggestion(any(), anyInt())).thenReturn(true);
         when(mMockSuggestionProcessor.getMinimumViewHeight()).thenReturn(viewHeight);
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/mostvisited/MostVisitedTilesTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/mostvisited/MostVisitedTilesTest.java
index 31ce50d..35db870 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/mostvisited/MostVisitedTilesTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/mostvisited/MostVisitedTilesTest.java
@@ -133,7 +133,7 @@
         mTile3 = new NavsuggestTile(
                 "Test Server", new GURL(mTestServer.getURL("/chrome/test/data/android/test.html")));
 
-        AutocompleteResult autocompleteResult = new AutocompleteResult(null, null);
+        AutocompleteResult autocompleteResult = AutocompleteResult.fromCache(null, null);
         AutocompleteMatchBuilder builder = new AutocompleteMatchBuilder();
 
         // First suggestion is the current content of the Omnibox.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/SearchActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/SearchActivityTest.java
index 31281cc..1402d72 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/SearchActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/SearchActivityTest.java
@@ -395,7 +395,7 @@
         List<AutocompleteMatch> list = new ArrayList<>();
         list.add(mockSuggestion);
         list.add(mockSuggestion2);
-        AutocompleteResult data = new AutocompleteResult(list, null);
+        AutocompleteResult data = AutocompleteResult.fromCache(list, null);
         CachedZeroSuggestionsManager.saveToCache(data);
 
         // Wait for the activity to load, but don't let it load the native library.
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinatorTest.java
index e0fd465..38d80fa 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinatorTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinatorTest.java
@@ -193,7 +193,7 @@
 
         // Preferences to enable feed.
         FeedSurfaceMediator.setPrefForTest(mPrefChangeRegistar, mPrefService);
-        FeedFeatures.setFakePrefsForTest(mPrefService, mPrefChangeRegistar);
+        FeedFeatures.setFakePrefsForTest(mPrefService);
         when(mPrefService.getBoolean(Pref.ENABLE_SNIPPETS)).thenReturn(true);
         when(mPrefService.getBoolean(Pref.ARTICLES_LIST_VISIBLE)).thenReturn(true);
         TemplateUrlServiceFactory.setInstanceForTesting(mUrlService);
@@ -232,7 +232,7 @@
         FeedSurfaceTracker.getInstance().resetForTest();
         AppHooksImpl.setInstanceForTesting(null);
         IdentityServicesProvider.setInstanceForTests(null);
-        FeedFeatures.setFakePrefsForTest(null, null);
+        FeedFeatures.setFakePrefsForTest(null);
         FeedSurfaceMediator.setPrefForTest(null, null);
         TemplateUrlServiceFactory.setInstanceForTesting(null);
     }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/feed/v2/FeedStreamTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/feed/v2/FeedStreamTest.java
index 5348df9..9863831 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/feed/v2/FeedStreamTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/feed/v2/FeedStreamTest.java
@@ -65,6 +65,7 @@
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.components.feed.proto.FeedUiProto;
 import org.chromium.ui.base.WindowAndroid;
+import org.chromium.url.JUnitTestGURLs;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -78,7 +79,7 @@
     private static final int LOAD_MORE_TRIGGER_LOOKAHEAD = 5;
     private static final int LOAD_MORE_TRIGGER_SCROLL_DISTANCE_DP = 100;
     private static final String TEST_DATA = "test";
-    private static final String TEST_URL = "https://www.chromium.org";
+    private static final String TEST_URL = JUnitTestGURLs.EXAMPLE_URL;
     private static final String HEADER_PREFIX = "header";
 
     private Activity mActivity;
@@ -144,6 +145,7 @@
         mFeedStream = new FeedStream(mActivity, mSnackbarManager, mPageNavigationDelegate,
                 mBottomSheetController, /* isPlaceholderShown= */ false, mWindowAndroid,
                 mShareDelegateSupplier, /* isInterestFeed= */ true);
+        mFeedStream.mMakeGURL = url -> JUnitTestGURLs.getGURL(url);
         mDependencyProvider =
                 new FeedSurfaceScopeDependencyProvider(mActivity, mActivity, false, mFeedStream);
         mRecyclerView = new RecyclerView(mActivity);
@@ -543,7 +545,7 @@
     @Test
     @SmallTest
     public void testSendFeedback() {
-        final String testUrl = "https://www.chromium.org";
+        final String testUrl = TEST_URL;
         final String testTitle = "Chromium based browsers for the win!";
         final String xSurfaceCardTitle = "Card Title";
         final String cardTitle = "CardTitle";
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediatorUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediatorUnitTest.java
index e19f45f..15655c57 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediatorUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediatorUnitTest.java
@@ -28,6 +28,7 @@
 import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.MENU_IS_VISIBLE;
 import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.NEW_TAB_BUTTON_IS_VISIBLE;
 import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.TAB_SWITCHER_BUTTON_IS_VISIBLE;
+import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.TRANSLATION_Y;
 
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
@@ -229,6 +230,14 @@
         assertEquals(false, mPropertyModel.get(INCOGNITO_SWITCHER_VISIBLE));
         assertTrue(mPropertyModel.get(IN_START_SURFACE_MODE));
         assertTrue(mPropertyModel.get(IS_VISIBLE));
+
+        int toolbarHeight = 10;
+        assertEquals(0.0, mPropertyModel.get(TRANSLATION_Y), 0.0);
+        assertFalse(mMediator.shouldShowRealSearchBox(toolbarHeight));
+        assertTrue(mMediator.isOnHomepage());
+        mPropertyModel.set(TRANSLATION_Y, -toolbarHeight);
+        assertTrue(mMediator.shouldShowRealSearchBox(toolbarHeight));
+        assertTrue(mMediator.isOnHomepage());
     }
 
     @Test
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index e518d76..335a41b 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -5258,6 +5258,82 @@
   <message name="IDS_VM_STATUS_PAGE_EXPLANATION_LABEL" desc="The heading for the 'explanation' column in a VM status page table. This column provides additional information for checks that have failed.">
     Explanation
   </message>
+  <message name="IDS_VM_STATUS_PAGE_DEVICE_IS_SUPPORTED_REQUIREMENT" desc="The requirement that the device being used supports the VM software (e.g. Parallels Desktop).">
+    Device is supported
+  </message>
+  <message name="IDS_VM_STATUS_PAGE_DEVICE_IS_SUPPORTED_EXPLANATION" desc="The explanation that the device being used does not support the VM software (e.g. Parallels Desktop).">
+    <ph name="DEVICE_NAME">$1<ex>Drallion</ex></ph> is not supported.
+  </message>
+  <message name="IDS_VM_STATUS_PAGE_PROFILE_IS_SUPPORTED_REQUIREMENT" desc="The requirement that the profile the user has logged in to supports the VM software (e.g. Parallels Desktop).">
+    Profile is supported
+  </message>
+  <message name="IDS_VM_STATUS_PAGE_SECONDARY_PROFILE_EXPLANATION" desc="The explanation that secondary profiles cannot use the VM software (e.g. Parallels Desktop). The user has logged in to multiple accounts at the same time and only the account logged in to first can be used.">
+    Secondary profiles are not supported
+  </message>
+  <message name="IDS_VM_STATUS_PAGE_CHILD_PROFILE_EXPLANATION" desc="The explanation that child accounts cannot use the VM software (e.g. Parallels Desktop).">
+    Child accounts are not supported
+  </message>
+  <message name="IDS_VM_STATUS_PAGE_GUEST_PROFILE_EXPLANATION" desc="The explanation that guest accounts cannot use the VM software (e.g. Parallels Desktop). The user must be signed in.">
+    Guest profiles are not supported
+  </message>
+  <message name="IDS_VM_STATUS_PAGE_EPHEMERAL_PROFILE_EXPLANATION" desc="The explanation that device is set up to use 'ephemeral mode' so the user cannot use the VM software (e.g. Parallels Desktop).">
+    Ephemeral mode is not supported. Please contact your administrator
+  </message>
+  <message name="IDS_VM_STATUS_PAGE_UNSUPPORTED_PROFILE_EXPLANATION" desc="The explanation that the current user profile cannot use the VM software (e.g. Parallels Desktop).">
+    The profile is not supported
+  </message>
+  <message name="IDS_VM_STATUS_PAGE_POLICIES_REQUIREMENT" desc="The requirement that policies must be configured correctly before the VM software (e.g. Parallels Desktop) can be used.">
+    Policies are configured correctly
+  </message>
+  <message name="IDS_VM_STATUS_PAGE_INCORRECT_POLICIES_ERROR" desc="The error message shown when some policies are not configured correctly.">
+    One or more policies are not configured correctly. Please contact your administrator
+  </message>
+  <message name="IDS_VM_STATUS_PAGE_IMAGE_URL_POLICY_EXPLANATION" desc="The message explaining that the policy specifying the virtual machine image's URL is not configured correctly">
+    Image url is invalid
+  </message>
+  <message name="IDS_VM_STATUS_PAGE_IMAGE_HASH_POLICY_EXPLANATION" desc="The message explaining that the policy specifying the virtual machine image's hash (i.e. checksum) is not configured correctly">
+    Image hash is not set
+  </message>
+  <message name="IDS_VM_STATUS_PAGE_UNABLE_TO_CHECK_POLICIES_EXPLANATION" desc="The message explaining that we are not able to check policies">
+    Unable to check policies
+  </message>
+  <message name="IDS_VM_STATUS_PAGE_DEVICE_NOT_ENROLLED_EXPLANATION" desc="The message explaining that the device is not enterprise enrolled">
+    Device is not enrolled
+  </message>
+  <message name="IDS_VM_STATUS_PAGE_DEVICE_NOT_ENROLLED_ERROR" desc="The error message shown when the device is not enterprise enrolled">
+    You must be on an enterprise-enrolled device
+  </message>
+  <message name="IDS_VM_STATUS_PAGE_USER_NOT_AFFILIATED_EXPLANATION" desc="The message explaining that the user is not affiliated with the enterprise domain">
+    User is not affiliated with domain
+  </message>
+  <message name="IDS_VM_STATUS_PAGE_UNABLE_TO_CHECK_DEVICE_ALLOW_EXPLANATION" desc="The message explaining that we encountered an error when checking whether the device is allowed by enterprise policy to run the VM (virtual machine)">
+    Unable to check whether the device is allowed
+  </message>
+  <message name="IDS_VM_STATUS_PAGE_DEVICE_NOT_ALLOW_EXPLANATION" desc="The message explaining that the enterprise policy does not allow running the VM (virtual machine) on the device being used.">
+    Device is not allowed
+  </message>
+  <message name="IDS_VM_STATUS_PAGE_USER_NOT_ALLOW_EXPLANATION" desc="The message explaining that the enterprise policy does not allow the current user to run the VM (virtual machine)">
+    User is not allowed
+  </message>
+  <message name="IDS_VM_STATUS_PAGE_LICENSE_NOT_SET_UP_EXPLANATION" desc="The message explaining that the the license for running the VM (virtual machine) is not set up">
+    License is not set up
+  </message>
+  <message name="IDS_VM_STATUS_PAGE_DEFAULT_VM_EXISTS_REQUIREMENT" desc="The message for the requirement that a VM (virtual machine) with the default name should exist">
+    VM "<ph name="DEFAULT_VM_NAME">$1<ex>PvmDefault</ex></ph>" exists
+  </message>
+  <message name="IDS_VM_STATUS_PAGE_MISSING_DEFAULT_VM_ERROR" desc="The error message shown when the default VM (virtual machine) does not exist">
+    A required virtual machine does not exist. Please try setting up <ph name="VM_TYPE">$1<ex>Parallels Desktop</ex></ph> to continue
+  </message>
+  <message name="IDS_VM_STATUS_PAGE_FAILED_TO_CHECK_VM_EXPLANATION" desc="The message explaining that we failed to enumerate existing VMs (virtual machine)">
+    Failed to check VMs
+  </message>
+  <message name="IDS_VM_STATUS_PAGE_MISSING_DEFAULT_VM_EXPLANATION" desc="When the default VM is missing, we want to show a message listing the VM(s) that we did find. Examples are: 'No Parallels Desktop VMs found', '1 Parallels Desktop VM found: vm_name1', '3 Parallels Desktop VMs found: vm_name1, vm_name2, vm_name3' ">
+    {NUM_VMS, plural,
+      =0 {No <ph name="VM_TYPE">$1<ex>Parallels Desktop</ex></ph> VMs found}
+      =1 {1 <ph name="VM_TYPE">$1<ex>Parallels Desktop</ex></ph> VM found: <ph name="VM_NAME_LIST">$2<ex>vm_name1</ex></ph>}
+      other {{NUM_VMS} <ph name="VM_TYPE">$1<ex>Parallels Desktop</ex></ph> VMs found: <ph name="VM_NAME_LIST">$2<ex>vm_name1, vm_name2, vm_name3</ex></ph>}
+    }
+  </message>
 
   <!-- Strings for Plugin VM -->
   <message name="IDS_PLUGIN_VM_APP_NAME" desc="Product name for 'Parallels Desktop'. Should not be translated as it is a third party name." translateable="false">
diff --git a/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_CHILD_PROFILE_EXPLANATION.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_CHILD_PROFILE_EXPLANATION.png.sha1
new file mode 100644
index 0000000..041c44ea
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_CHILD_PROFILE_EXPLANATION.png.sha1
@@ -0,0 +1 @@
+173da2ead3ac8b2282f8cf742f951de5c2ec3d72
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_DEFAULT_VM_EXISTS_REQUIREMENT.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_DEFAULT_VM_EXISTS_REQUIREMENT.png.sha1
new file mode 100644
index 0000000..b5d5754
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_DEFAULT_VM_EXISTS_REQUIREMENT.png.sha1
@@ -0,0 +1 @@
+44b29698d8e552ba2c60ad00efce14966c2f54fb
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_DEVICE_IS_SUPPORTED_EXPLANATION.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_DEVICE_IS_SUPPORTED_EXPLANATION.png.sha1
new file mode 100644
index 0000000..b5d5754
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_DEVICE_IS_SUPPORTED_EXPLANATION.png.sha1
@@ -0,0 +1 @@
+44b29698d8e552ba2c60ad00efce14966c2f54fb
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_DEVICE_IS_SUPPORTED_REQUIREMENT.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_DEVICE_IS_SUPPORTED_REQUIREMENT.png.sha1
new file mode 100644
index 0000000..b5d5754
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_DEVICE_IS_SUPPORTED_REQUIREMENT.png.sha1
@@ -0,0 +1 @@
+44b29698d8e552ba2c60ad00efce14966c2f54fb
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_DEVICE_NOT_ALLOW_EXPLANATION.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_DEVICE_NOT_ALLOW_EXPLANATION.png.sha1
new file mode 100644
index 0000000..4ed294d
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_DEVICE_NOT_ALLOW_EXPLANATION.png.sha1
@@ -0,0 +1 @@
+7613b24d410d91e2f6651d589a12ac0a42d1f322
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_DEVICE_NOT_ENROLLED_ERROR.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_DEVICE_NOT_ENROLLED_ERROR.png.sha1
new file mode 100644
index 0000000..b15550ef4
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_DEVICE_NOT_ENROLLED_ERROR.png.sha1
@@ -0,0 +1 @@
+a13634e7340415a26814004a5793c302e24ee2fd
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_DEVICE_NOT_ENROLLED_EXPLANATION.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_DEVICE_NOT_ENROLLED_EXPLANATION.png.sha1
new file mode 100644
index 0000000..b15550ef4
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_DEVICE_NOT_ENROLLED_EXPLANATION.png.sha1
@@ -0,0 +1 @@
+a13634e7340415a26814004a5793c302e24ee2fd
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_EPHEMERAL_PROFILE_EXPLANATION.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_EPHEMERAL_PROFILE_EXPLANATION.png.sha1
new file mode 100644
index 0000000..fdc98bea7
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_EPHEMERAL_PROFILE_EXPLANATION.png.sha1
@@ -0,0 +1 @@
+a1309289d3683732f9c1039c3e19b0f33dafce74
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_FAILED_TO_CHECK_VM_EXPLANATION.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_FAILED_TO_CHECK_VM_EXPLANATION.png.sha1
new file mode 100644
index 0000000..7e7c2e1
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_FAILED_TO_CHECK_VM_EXPLANATION.png.sha1
@@ -0,0 +1 @@
+a0c93c969bf9efb43f03fc1e7591bf96aa611f0a
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_GUEST_PROFILE_EXPLANATION.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_GUEST_PROFILE_EXPLANATION.png.sha1
new file mode 100644
index 0000000..6c9c3d42
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_GUEST_PROFILE_EXPLANATION.png.sha1
@@ -0,0 +1 @@
+1934571d16a3a17219433afd33228492f3831dff
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_IMAGE_HASH_POLICY_EXPLANATION.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_IMAGE_HASH_POLICY_EXPLANATION.png.sha1
new file mode 100644
index 0000000..11382c4
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_IMAGE_HASH_POLICY_EXPLANATION.png.sha1
@@ -0,0 +1 @@
+5c810012fc0de4be3cda22910cbcc9820b99b06d
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_IMAGE_URL_POLICY_EXPLANATION.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_IMAGE_URL_POLICY_EXPLANATION.png.sha1
new file mode 100644
index 0000000..b5d5754
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_IMAGE_URL_POLICY_EXPLANATION.png.sha1
@@ -0,0 +1 @@
+44b29698d8e552ba2c60ad00efce14966c2f54fb
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_INCORRECT_POLICIES_ERROR.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_INCORRECT_POLICIES_ERROR.png.sha1
new file mode 100644
index 0000000..11382c4
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_INCORRECT_POLICIES_ERROR.png.sha1
@@ -0,0 +1 @@
+5c810012fc0de4be3cda22910cbcc9820b99b06d
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_LICENSE_NOT_SET_UP_EXPLANATION.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_LICENSE_NOT_SET_UP_EXPLANATION.png.sha1
new file mode 100644
index 0000000..c3cf538
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_LICENSE_NOT_SET_UP_EXPLANATION.png.sha1
@@ -0,0 +1 @@
+bf846a3ff776ab77a761e36e6a014ecea833964f
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_MISSING_DEFAULT_VM_ERROR.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_MISSING_DEFAULT_VM_ERROR.png.sha1
new file mode 100644
index 0000000..e8fb39ce
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_MISSING_DEFAULT_VM_ERROR.png.sha1
@@ -0,0 +1 @@
+8628adc167242ef189d81e62c6a51a217354329f
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_MISSING_DEFAULT_VM_EXPLANATION.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_MISSING_DEFAULT_VM_EXPLANATION.png.sha1
new file mode 100644
index 0000000..e8fb39ce
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_MISSING_DEFAULT_VM_EXPLANATION.png.sha1
@@ -0,0 +1 @@
+8628adc167242ef189d81e62c6a51a217354329f
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_POLICIES_REQUIREMENT.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_POLICIES_REQUIREMENT.png.sha1
new file mode 100644
index 0000000..b5d5754
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_POLICIES_REQUIREMENT.png.sha1
@@ -0,0 +1 @@
+44b29698d8e552ba2c60ad00efce14966c2f54fb
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_PROFILE_IS_SUPPORTED_REQUIREMENT.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_PROFILE_IS_SUPPORTED_REQUIREMENT.png.sha1
new file mode 100644
index 0000000..b5d5754
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_PROFILE_IS_SUPPORTED_REQUIREMENT.png.sha1
@@ -0,0 +1 @@
+44b29698d8e552ba2c60ad00efce14966c2f54fb
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_SECONDARY_PROFILE_EXPLANATION.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_SECONDARY_PROFILE_EXPLANATION.png.sha1
new file mode 100644
index 0000000..00031ed
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_SECONDARY_PROFILE_EXPLANATION.png.sha1
@@ -0,0 +1 @@
+60f26222d6b98ad5327a798b232cc81eeb5fe7e5
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_UNABLE_TO_CHECK_DEVICE_ALLOW_EXPLANATION.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_UNABLE_TO_CHECK_DEVICE_ALLOW_EXPLANATION.png.sha1
new file mode 100644
index 0000000..58e48b6
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_UNABLE_TO_CHECK_DEVICE_ALLOW_EXPLANATION.png.sha1
@@ -0,0 +1 @@
+46adf9fc83b1f298f550958ec91894d75b2e45d1
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_UNABLE_TO_CHECK_POLICIES_EXPLANATION.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_UNABLE_TO_CHECK_POLICIES_EXPLANATION.png.sha1
new file mode 100644
index 0000000..182a7384
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_UNABLE_TO_CHECK_POLICIES_EXPLANATION.png.sha1
@@ -0,0 +1 @@
+5b34bbd6e26ee985d319b82ef4e73b79cfd2beaf
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_UNSUPPORTED_PROFILE_EXPLANATION.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_UNSUPPORTED_PROFILE_EXPLANATION.png.sha1
new file mode 100644
index 0000000..6c95f8a
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_UNSUPPORTED_PROFILE_EXPLANATION.png.sha1
@@ -0,0 +1 @@
+6e2453abd7d7a31a90b621aa2a15cd07173978f1
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_USER_NOT_AFFILIATED_EXPLANATION.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_USER_NOT_AFFILIATED_EXPLANATION.png.sha1
new file mode 100644
index 0000000..bac8befc
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_USER_NOT_AFFILIATED_EXPLANATION.png.sha1
@@ -0,0 +1 @@
+84f1d785e29d3dbd40ed240ce0ab26d0343fd1c9
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_USER_NOT_ALLOW_EXPLANATION.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_USER_NOT_ALLOW_EXPLANATION.png.sha1
new file mode 100644
index 0000000..4b38949
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_VM_STATUS_PAGE_USER_NOT_ALLOW_EXPLANATION.png.sha1
@@ -0,0 +1 @@
+2b7b13cf0f11a169f5958d5c566dfa434498efa5
\ No newline at end of file
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index d79e937..7fe524d 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -10814,9 +10814,6 @@
       <message name="IDS_WEBAUTHN_TRANSPORT_USB" desc="Menu item text. The user selects this to use a security key (an external physical device for user authentication) plugged in to the USB port of the computer.">
         USB security key
       </message>
-      <message name="IDS_WEBAUTHN_TRANSPORT_NFC" desc="Menu item text. The user selects this to use a security key (an external physical device for user authentication) connected to the computer over Near-Field Communication.">
-        NFC security key
-      </message>
       <message name="IDS_WEBAUTHN_TRANSPORT_INTERNAL" desc="Menu item text. The user selects this to use a hardware-based authentication mechanism that is built in to the computer, such as a fingerprint reader.">
         This device
       </message>
@@ -10886,9 +10883,6 @@
       <message name="IDS_WEBAUTHN_TRANSPORT_POPUP_PAIR_PHONE" desc="Menu item text. The user selects this to begin the process of pairing with a previously unknown smartphone.">
         Pair with new phone
       </message>
-      <message name="IDS_WEBAUTHN_TRANSPORT_POPUP_NFC" desc="Menu item text. The user selects this to verify their identity on a web site (i.e. sign in) using a security key (an external physical device for user authentication) connected to the computer over Near-Field Communication.">
-        Verify via NFC
-      </message>
       <message name="IDS_WEBAUTHN_TRANSPORT_POPUP_INTERNAL" desc="Menu item text. The user selects this to verify their identity on a web site (i.e. sign in) using a hardware-based authentication mechanism that is built in to the computer, such as a fingerprint reader.">
         Use this device
       </message>
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index f576abe..0c53e8d 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -544,6 +544,9 @@
     {"text_lightness_threshold", "150"},
     {"background_lightness_threshold", "205"}};
 
+const FeatureEntry::FeatureParam kForceDark_IncreaseTextContrast[] = {
+    {"increase_text_contrast", "true"}};
+
 const FeatureEntry::FeatureVariation kForceDarkVariations[] = {
     {"with simple HSL-based inversion", kForceDark_SimpleHsl,
      base::size(kForceDark_SimpleHsl), nullptr},
@@ -558,7 +561,9 @@
      base::size(kForceDark_SelectiveElementInversion), nullptr},
     {"with selective inversion of everything",
      kForceDark_SelectiveGeneralInversion,
-     base::size(kForceDark_SelectiveGeneralInversion), nullptr}};
+     base::size(kForceDark_SelectiveGeneralInversion), nullptr},
+    {"with increased text contrast", kForceDark_IncreaseTextContrast,
+     base::size(kForceDark_IncreaseTextContrast), nullptr}};
 #endif  // !OS_CHROMEOS
 
 const FeatureEntry::FeatureParam kMBIModeLegacy[] = {{"mode", "legacy"}};
@@ -3459,6 +3464,10 @@
                                     kDesktopPWAsAttentionBadgingCrOSVariations,
                                     "DesktopPWAsAttentionBadgingCrOS")},
 #endif
+    {"enable-desktop-pwas-prefix-app-name-in-window-title",
+     flag_descriptions::kDesktopPWAsPrefixAppNameInWindowTitleName,
+     flag_descriptions::kDesktopPWAsPrefixAppNameInWindowTitleDescription,
+     kOsDesktop, FEATURE_VALUE_TYPE(features::kPrefixWebAppWindowsWithAppName)},
     {"enable-desktop-pwas-remove-status-bar",
      flag_descriptions::kDesktopPWAsRemoveStatusBarName,
      flag_descriptions::kDesktopPWAsRemoveStatusBarDescription, kOsDesktop,
@@ -5226,11 +5235,6 @@
      flag_descriptions::kSharingPreferVapidDescription, kOsAll,
      FEATURE_VALUE_TYPE(kSharingPreferVapid)},
 
-    {"sharing-qr-code-generator",
-     flag_descriptions::kSharingQRCodeGeneratorName,
-     flag_descriptions::kSharingQRCodeGeneratorDescription, kOsDesktop,
-     FEATURE_VALUE_TYPE(kSharingQRCodeGenerator)},
-
     {"sharing-send-via-sync", flag_descriptions::kSharingSendViaSyncName,
      flag_descriptions::kSharingSendViaSyncDescription, kOsAll,
      FEATURE_VALUE_TYPE(kSharingSendViaSync)},
@@ -6395,12 +6399,6 @@
      flag_descriptions::kAutofillEnableGoogleIssuedCardDescription, kOsAll,
      FEATURE_VALUE_TYPE(autofill::features::kAutofillEnableGoogleIssuedCard)},
 
-#if defined(TOOLKIT_VIEWS)
-    {"textfield-focus-on-tap-up", flag_descriptions::kTextfieldFocusOnTapUpName,
-     flag_descriptions::kTextfieldFocusOnTapUpDescription, kOsDesktop,
-     FEATURE_VALUE_TYPE(views::features::kTextfieldFocusOnTapUp)},
-#endif  // defined(TOOLKIT_VIEWS)
-
     {"permission-chip", flag_descriptions::kPermissionChipName,
      flag_descriptions::kPermissionChipDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(permissions::features::kPermissionChip)},
diff --git a/chrome/browser/android/feed/v2/feed_service_factory.h b/chrome/browser/android/feed/v2/feed_service_factory.h
index f93f5654..5c44ca9 100644
--- a/chrome/browser/android/feed/v2/feed_service_factory.h
+++ b/chrome/browser/android/feed/v2/feed_service_factory.h
@@ -24,7 +24,6 @@
   FeedServiceFactory& operator=(const FeedServiceFactory&) = delete;
 
   static FeedService* GetForBrowserContext(content::BrowserContext* context);
-
   static FeedServiceFactory* GetInstance();
 
  private:
diff --git a/chrome/browser/android/feed/v2/feed_stream.cc b/chrome/browser/android/feed/v2/feed_stream.cc
index 2e6be1b..cb59989 100644
--- a/chrome/browser/android/feed/v2/feed_stream.cc
+++ b/chrome/browser/android/feed/v2/feed_stream.cc
@@ -20,6 +20,7 @@
 #include "components/feed/core/v2/public/feed_api.h"
 #include "components/feed/core/v2/public/feed_service.h"
 #include "components/variations/variations_ids_provider.h"
+#include "url/android/gurl_android.h"
 
 using base::android::JavaParamRef;
 using base::android::JavaRef;
@@ -183,21 +184,28 @@
 
 void FeedStream::ReportOpenAction(JNIEnv* env,
                                   const JavaParamRef<jobject>& obj,
+                                  const JavaParamRef<jobject>& j_url,
                                   const JavaParamRef<jstring>& slice_id) {
   if (!feed_stream_api_)
     return;
+  std::unique_ptr<GURL> url = url::GURLAndroid::ToNativeGURL(env, j_url);
   feed_stream_api_->ReportOpenAction(
-      GetStreamType(), base::android::ConvertJavaStringToUTF8(env, slice_id));
+      url ? *url : GURL(), GetStreamType(),
+      base::android::ConvertJavaStringToUTF8(env, slice_id));
 }
 
 void FeedStream::ReportOpenInNewTabAction(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
+    const JavaParamRef<jobject>& j_url,
     const JavaParamRef<jstring>& slice_id) {
   if (!feed_stream_api_)
     return;
+  std::unique_ptr<GURL> url = url::GURLAndroid::ToNativeGURL(env, j_url);
+
   feed_stream_api_->ReportOpenInNewTabAction(
-      GetStreamType(), base::android::ConvertJavaStringToUTF8(env, slice_id));
+      url ? *url : GURL(), GetStreamType(),
+      base::android::ConvertJavaStringToUTF8(env, slice_id));
 }
 
 void FeedStream::ReportSliceViewed(JNIEnv* env,
diff --git a/chrome/browser/android/feed/v2/feed_stream.h b/chrome/browser/android/feed/v2/feed_stream.h
index 588e523..391f4a0 100644
--- a/chrome/browser/android/feed/v2/feed_stream.h
+++ b/chrome/browser/android/feed/v2/feed_stream.h
@@ -79,8 +79,7 @@
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj);
 
-  // Event reporting functions. These have no side-effect beyond recording
-  // metrics. See |FeedApi| for definitions.
+  // Event reporting functions. See |FeedApi| for definitions.
   void ReportSliceViewed(JNIEnv* env,
                          const base::android::JavaParamRef<jobject>& obj,
                          const base::android::JavaParamRef<jstring>& slice_id);
@@ -88,10 +87,12 @@
                         const base::android::JavaParamRef<jobject>& obj);
   void ReportOpenAction(JNIEnv* env,
                         const base::android::JavaParamRef<jobject>& obj,
+                        const base::android::JavaParamRef<jobject>& j_url,
                         const base::android::JavaParamRef<jstring>& slice_id);
   void ReportOpenInNewTabAction(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
+      const base::android::JavaParamRef<jobject>& j_url,
       const base::android::JavaParamRef<jstring>& slice_id);
   void ReportOpenInNewIncognitoTabAction(
       JNIEnv* env,
diff --git a/chrome/browser/apps/app_service/app_service_proxy_desktop.cc b/chrome/browser/apps/app_service/app_service_proxy_desktop.cc
index 6763f22..ed382d4 100644
--- a/chrome/browser/apps/app_service/app_service_proxy_desktop.cc
+++ b/chrome/browser/apps/app_service/app_service_proxy_desktop.cc
@@ -51,6 +51,7 @@
     fake_lacros_web_apps_host_->Init();
   } else {
     web_apps_publisher_host_ = std::make_unique<WebAppsPublisherHost>(profile_);
+    web_apps_publisher_host_->Init();
   }
 #endif
 
diff --git a/chrome/browser/apps/app_service/fake_lacros_web_apps_host.cc b/chrome/browser/apps/app_service/fake_lacros_web_apps_host.cc
index 31aadb77..1fb315b 100644
--- a/chrome/browser/apps/app_service/fake_lacros_web_apps_host.cc
+++ b/chrome/browser/apps/app_service/fake_lacros_web_apps_host.cc
@@ -7,8 +7,10 @@
 #include <utility>
 #include <vector>
 
+#include "base/notreached.h"
 #include "chromeos/lacros/lacros_service.h"
 #include "components/services/app_service/public/mojom/types.mojom.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 namespace {
 
@@ -67,4 +69,12 @@
   }
 }
 
+void FakeLacrosWebAppsHost::Uninstall(
+    const std::string& app_id,
+    apps::mojom::UninstallSource uninstall_source,
+    bool clear_site_data,
+    bool report_abuse) {
+  NOTIMPLEMENTED();
+}
+
 }  // namespace apps
diff --git a/chrome/browser/apps/app_service/fake_lacros_web_apps_host.h b/chrome/browser/apps/app_service/fake_lacros_web_apps_host.h
index 03158153..32839f6 100644
--- a/chrome/browser/apps/app_service/fake_lacros_web_apps_host.h
+++ b/chrome/browser/apps/app_service/fake_lacros_web_apps_host.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_APPS_APP_SERVICE_FAKE_LACROS_WEB_APPS_HOST_H_
 
 #include "chromeos/crosapi/mojom/app_service.mojom.h"
-#include "mojo/public/cpp/bindings/remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 
 namespace apps {
 
@@ -28,6 +28,12 @@
   void Init();
 
  private:
+  // crosapi::mojom::AppController overrides.
+  void Uninstall(const std::string& app_id,
+                 apps::mojom::UninstallSource uninstall_source,
+                 bool clear_site_data,
+                 bool report_abuse) override;
+
   mojo::Receiver<crosapi::mojom::AppController> receiver_{this};
 };
 
diff --git a/chrome/browser/apps/app_service/publishers/web_apps_chromeos.cc b/chrome/browser/apps/app_service/publishers/web_apps_chromeos.cc
index 82df1ae..0f4cc0c4 100644
--- a/chrome/browser/apps/app_service/publishers/web_apps_chromeos.cc
+++ b/chrome/browser/apps/app_service/publishers/web_apps_chromeos.cc
@@ -178,35 +178,8 @@
     return;
   }
 
-  auto origin = url::Origin::Create(web_app->start_url());
-
-  DCHECK(provider());
-  DCHECK(provider()->install_finalizer().CanUserUninstallWebApp(app_id));
-  webapps::WebappUninstallSource webapp_uninstall_source =
-      apps_util::ConvertUninstallSourceToWebAppUninstallSource(
-          uninstall_source);
-  provider()->install_finalizer().UninstallWebApp(
-      app_id, webapp_uninstall_source, base::DoNothing());
-  web_app = nullptr;
-
-  if (!clear_site_data) {
-    // TODO(loyso): Add UMA_HISTOGRAM_ENUMERATION here.
-    return;
-  }
-
-  // TODO(loyso): Add UMA_HISTOGRAM_ENUMERATION here.
-  constexpr bool kClearCookies = true;
-  constexpr bool kClearStorage = true;
-  constexpr bool kClearCache = true;
-  constexpr bool kAvoidClosingConnections = false;
-
-  content::ClearSiteData(base::BindRepeating(
-                             [](content::BrowserContext* browser_context) {
-                               return browser_context;
-                             },
-                             base::Unretained(profile())),
-                         origin, kClearCookies, kClearStorage, kClearCache,
-                         kAvoidClosingConnections, base::DoNothing());
+  apps_util::UninstallWebApp(profile(), web_app, uninstall_source,
+                             clear_site_data, report_abuse);
 }
 
 void WebAppsChromeOs::PauseApp(const std::string& app_id) {
diff --git a/chrome/browser/apps/app_service/publishers/web_apps_crosapi.cc b/chrome/browser/apps/app_service/publishers/web_apps_crosapi.cc
index 7699ff4..6012289e 100644
--- a/chrome/browser/apps/app_service/publishers/web_apps_crosapi.cc
+++ b/chrome/browser/apps/app_service/publishers/web_apps_crosapi.cc
@@ -7,12 +7,15 @@
 #include <utility>
 #include <vector>
 
+#include "ash/public/cpp/app_menu_constants.h"
 #include "base/bind.h"
 #include "chrome/browser/apps/app_service/app_icon_factory.h"
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
+#include "chrome/browser/apps/app_service/menu_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_features.h"
+#include "chrome/grit/generated_resources.h"
 #include "components/services/app_service/public/mojom/types.mojom.h"
 #include "extensions/common/constants.h"
 
@@ -75,7 +78,9 @@
                               bool allow_placeholder_icon,
                               LoadIconCallback callback) {
   // TODO(crbug.com/1144877): Implement this.
-  std::move(callback).Run(apps::mojom::IconValue::New());
+  apps::mojom::IconValuePtr icon = apps::mojom::IconValue::New();
+  icon->icon_type = apps::mojom::IconType::kStandard;
+  std::move(callback).Run(std::move(icon));
 }
 
 void WebAppsCrosapi::Launch(const std::string& app_id,
@@ -85,6 +90,30 @@
   // TODO(crbug.com/1144877): Implement this.
 }
 
+void WebAppsCrosapi::Uninstall(const std::string& app_id,
+                               apps::mojom::UninstallSource uninstall_source,
+                               bool clear_site_data,
+                               bool report_abuse) {
+  controller_->Uninstall(app_id, uninstall_source, clear_site_data,
+                         report_abuse);
+}
+
+void WebAppsCrosapi::GetMenuModel(const std::string& app_id,
+                                  apps::mojom::MenuType menu_type,
+                                  int64_t display_id,
+                                  GetMenuModelCallback callback) {
+  // TODO(crbug.com/1194709): Check if the app is installed.
+
+  // TODO(crbug.com/1194709): Add menu items, based on
+  // WebAppsChromeOs::GetMenuModel().
+  apps::mojom::MenuItemsPtr menu_items = apps::mojom::MenuItems::New();
+
+  // TODO(crbug.com/1194709): Check if the user can uninstall the web app.
+  AddCommandItem(ash::UNINSTALL, IDS_APP_LIST_UNINSTALL_ITEM, &menu_items);
+
+  std::move(callback).Run(std::move(menu_items));
+}
+
 void WebAppsCrosapi::OnApps(std::vector<apps::mojom::AppPtr> deltas) {
   if (!base::FeatureList::IsEnabled(features::kWebAppsCrosapi))
     return;
@@ -106,9 +135,11 @@
 
 void WebAppsCrosapi::OnCrosapiDisconnected() {
   receiver_.reset();
+  controller_.reset();
 }
 
 void WebAppsCrosapi::OnControllerDisconnected() {
   controller_.reset();
 }
+
 }  // namespace apps
diff --git a/chrome/browser/apps/app_service/publishers/web_apps_crosapi.h b/chrome/browser/apps/app_service/publishers/web_apps_crosapi.h
index 8c2dcfc..b6c6aee 100644
--- a/chrome/browser/apps/app_service/publishers/web_apps_crosapi.h
+++ b/chrome/browser/apps/app_service/publishers/web_apps_crosapi.h
@@ -53,6 +53,14 @@
               int32_t event_flags,
               apps::mojom::LaunchSource launch_source,
               apps::mojom::WindowInfoPtr window_info) override;
+  void Uninstall(const std::string& app_id,
+                 apps::mojom::UninstallSource uninstall_source,
+                 bool clear_site_data,
+                 bool report_abuse) override;
+  void GetMenuModel(const std::string& app_id,
+                    apps::mojom::MenuType menu_type,
+                    int64_t display_id,
+                    GetMenuModelCallback callback) override;
 
   // crosapi::mojom::AppPublisher overrides.
   void OnApps(std::vector<apps::mojom::AppPtr> deltas) override;
diff --git a/chrome/browser/apps/app_service/web_apps_publisher_host.cc b/chrome/browser/apps/app_service/web_apps_publisher_host.cc
index 05c74d8..539400e 100644
--- a/chrome/browser/apps/app_service/web_apps_publisher_host.cc
+++ b/chrome/browser/apps/app_service/web_apps_publisher_host.cc
@@ -41,15 +41,34 @@
 
 }  // namespace
 
-// static
-crosapi::mojom::AppPublisher* WebAppsPublisherHost::publisher_for_testing_ =
-    nullptr;
-
 WebAppsPublisherHost::WebAppsPublisherHost(Profile* profile)
-    : profile_(profile), provider_(web_app::WebAppProvider::Get(profile)) {
+    : profile_(profile), provider_(web_app::WebAppProvider::Get(profile)) {}
+
+WebAppsPublisherHost::~WebAppsPublisherHost() = default;
+
+void WebAppsPublisherHost::Init() {
   // Allow for web app migration tests.
-  if (!provider_->registrar().AsWebAppRegistrar())
+  if (!provider_->registrar().AsWebAppRegistrar()) {
     return;
+  }
+
+  if (!remote_publisher_) {
+    auto* service = chromeos::LacrosService::Get();
+    if (!service) {
+      return;
+    }
+    if (!service->IsAvailable<crosapi::mojom::AppPublisher>()) {
+      return;
+    }
+    if (!service->init_params()->web_apps_enabled) {
+      return;
+    }
+
+    service->GetRemote<crosapi::mojom::AppPublisher>()->RegisterAppController(
+        receiver_.BindNewPipeAndPassRemote());
+    remote_publisher_ =
+        service->GetRemote<crosapi::mojom::AppPublisher>().get();
+  }
 
   provider_->on_registry_ready().Post(
       FROM_HERE, base::BindOnce(&WebAppsPublisherHost::OnReady,
@@ -57,38 +76,17 @@
   registrar_observation_.Observe(&registrar());
 }
 
-WebAppsPublisherHost::~WebAppsPublisherHost() = default;
-
 web_app::WebAppRegistrar& WebAppsPublisherHost::registrar() const {
   return *provider_->registrar().AsWebAppRegistrar();
 }
 
-crosapi::mojom::AppPublisher* WebAppsPublisherHost::GetPublisher() const {
-  if (publisher_for_testing_) {
-    return publisher_for_testing_;
-  }
-  auto* service = chromeos::LacrosService::Get();
-  if (!service) {
-    return nullptr;
-  }
-  if (!service->IsAvailable<crosapi::mojom::AppPublisher>()) {
-    return nullptr;
-  }
-  if (!service->init_params()->web_apps_enabled) {
-    return nullptr;
-  }
-  return service->GetRemote<crosapi::mojom::AppPublisher>().get();
-}
-
-// static
 void WebAppsPublisherHost::SetPublisherForTesting(
     crosapi::mojom::AppPublisher* publisher) {
-  publisher_for_testing_ = publisher;
+  remote_publisher_ = publisher;
 }
 
 void WebAppsPublisherHost::OnReady() {
-  crosapi::mojom::AppPublisher* const publisher = GetPublisher();
-  if (!publisher || !registrar_observation_.IsObserving()) {
+  if (!remote_publisher_ || !registrar_observation_.IsObserving()) {
     return;
   }
 
@@ -96,7 +94,22 @@
   for (const web_app::WebApp& web_app : registrar().GetApps()) {
     apps.push_back(Convert(&web_app, apps::mojom::Readiness::kReady));
   }
-  publisher->OnApps(std::move(apps));
+  remote_publisher_->OnApps(std::move(apps));
+}
+
+// crosapi::mojom::AppController:
+void WebAppsPublisherHost::Uninstall(
+    const std::string& app_id,
+    apps::mojom::UninstallSource uninstall_source,
+    bool clear_site_data,
+    bool report_abuse) {
+  const web_app::WebApp* web_app = GetWebApp(app_id);
+  if (!web_app) {
+    return;
+  }
+
+  apps_util::UninstallWebApp(profile_, web_app, uninstall_source,
+                             clear_site_data, report_abuse);
 }
 
 // web_app::AppRegistrarObserver:
@@ -176,14 +189,13 @@
 }
 
 void WebAppsPublisherHost::Publish(apps::mojom::AppPtr app) {
-  crosapi::mojom::AppPublisher* const publisher = GetPublisher();
-  if (!publisher) {
+  if (!remote_publisher_) {
     return;
   }
 
   std::vector<apps::mojom::AppPtr> apps;
   apps.push_back(std::move(app));
-  publisher->OnApps(std::move(apps));
+  remote_publisher_->OnApps(std::move(apps));
 }
 
 }  // namespace apps
diff --git a/chrome/browser/apps/app_service/web_apps_publisher_host.h b/chrome/browser/apps/app_service/web_apps_publisher_host.h
index d250ec18..79dbb6e8 100644
--- a/chrome/browser/apps/app_service/web_apps_publisher_host.h
+++ b/chrome/browser/apps/app_service/web_apps_publisher_host.h
@@ -18,6 +18,7 @@
 #include "chrome/browser/web_applications/components/web_app_id.h"
 #include "chromeos/crosapi/mojom/app_service.mojom.h"
 #include "components/services/app_service/public/mojom/types.mojom.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 
 class Profile;
 
@@ -31,22 +32,29 @@
 
 // This WebAppsPublisherHost observes AppRegistrar on Lacros, and calls
 // WebAppsCrosapi to inform the Ash browser of the current set of web apps.
-class WebAppsPublisherHost : public web_app::AppRegistrarObserver {
+class WebAppsPublisherHost : public crosapi::mojom::AppController,
+                             public web_app::AppRegistrarObserver {
  public:
   explicit WebAppsPublisherHost(Profile* profile);
   WebAppsPublisherHost(const WebAppsPublisherHost&) = delete;
   WebAppsPublisherHost& operator=(const WebAppsPublisherHost&) = delete;
   ~WebAppsPublisherHost() override;
 
+  void Init();
+
   web_app::WebAppRegistrar& registrar() const;
 
-  crosapi::mojom::AppPublisher* GetPublisher() const;
-
-  static void SetPublisherForTesting(crosapi::mojom::AppPublisher* publisher);
+  void SetPublisherForTesting(crosapi::mojom::AppPublisher* publisher);
 
  private:
   void OnReady();
 
+  // crosapi::mojom::AppController:
+  void Uninstall(const std::string& app_id,
+                 apps::mojom::UninstallSource uninstall_source,
+                 bool clear_site_data,
+                 bool report_abuse) override;
+
   // web_app::AppRegistrarObserver:
   void OnWebAppInstalled(const web_app::AppId& app_id) override;
   void OnWebAppManifestUpdated(const web_app::AppId& app_id,
@@ -70,13 +78,14 @@
                               apps::mojom::Readiness readiness);
   void Publish(apps::mojom::AppPtr app);
 
-  static crosapi::mojom::AppPublisher* publisher_for_testing_;
-
   Profile* const profile_;
   web_app::WebAppProvider* const provider_;
+  crosapi::mojom::AppPublisher* remote_publisher_ = nullptr;
 
   apps_util::IncrementingIconKeyFactory icon_key_factory_;
 
+  mojo::Receiver<crosapi::mojom::AppController> receiver_{this};
+
   base::ScopedObservation<web_app::AppRegistrar, web_app::AppRegistrarObserver>
       registrar_observation_{this};
 
diff --git a/chrome/browser/apps/app_service/web_apps_publisher_host_browsertest.cc b/chrome/browser/apps/app_service/web_apps_publisher_host_browsertest.cc
index bbb2cc1..4dd35e2 100644
--- a/chrome/browser/apps/app_service/web_apps_publisher_host_browsertest.cc
+++ b/chrome/browser/apps/app_service/web_apps_publisher_host_browsertest.cc
@@ -81,10 +81,11 @@
   web_app::InstallWebAppFromManifest(
       browser(),
       embedded_test_server()->GetURL("/web_share_target/charts.html"));
-  MockAppPublisher mock_app_publisher;
-  WebAppsPublisherHost::SetPublisherForTesting(&mock_app_publisher);
 
+  MockAppPublisher mock_app_publisher;
   WebAppsPublisherHost web_apps_publisher_host(profile());
+  web_apps_publisher_host.SetPublisherForTesting(&mock_app_publisher);
+  web_apps_publisher_host.Init();
   mock_app_publisher.Wait();
   EXPECT_EQ(mock_app_publisher.get_deltas().size(), 2U);
 
@@ -92,8 +93,8 @@
       browser(),
       embedded_test_server()->GetURL("/banners/manifest_test_page.html"));
   mock_app_publisher.Wait();
-  // We may receive more than one delta for the new app.
-  EXPECT_GE(mock_app_publisher.get_deltas().size(), 3U);
+
+  EXPECT_EQ(mock_app_publisher.get_deltas().size(), 3U);
   EXPECT_EQ(mock_app_publisher.get_deltas().back()->app_id, app_id);
   EXPECT_EQ(mock_app_publisher.get_deltas().back()->readiness,
             apps::mojom::Readiness::kReady);
@@ -118,12 +119,13 @@
 
 IN_PROC_BROWSER_TEST_F(WebAppsPublisherHostBrowserTest, LaunchTime) {
   ASSERT_TRUE(embedded_test_server()->Start());
-  MockAppPublisher mock_app_publisher;
-  WebAppsPublisherHost::SetPublisherForTesting(&mock_app_publisher);
-
   web_app::AppId app_id = web_app::InstallWebAppFromManifest(
       browser(), embedded_test_server()->GetURL("/web_apps/basic.html"));
+
+  MockAppPublisher mock_app_publisher;
   WebAppsPublisherHost web_apps_publisher_host(profile());
+  web_apps_publisher_host.SetPublisherForTesting(&mock_app_publisher);
+  web_apps_publisher_host.Init();
   mock_app_publisher.Wait();
   ASSERT_TRUE(
       mock_app_publisher.get_deltas().back()->last_launch_time.has_value());
@@ -145,9 +147,9 @@
       embedded_test_server()->GetURL("app.site.com", "/simple.html");
 
   MockAppPublisher mock_app_publisher;
-  WebAppsPublisherHost::SetPublisherForTesting(&mock_app_publisher);
-
   WebAppsPublisherHost web_apps_publisher_host(profile());
+  web_apps_publisher_host.SetPublisherForTesting(&mock_app_publisher);
+  web_apps_publisher_host.Init();
 
   web_app::AppId app_id;
   {
@@ -192,9 +194,6 @@
   const GURL app_url =
       embedded_test_server()->GetURL("app.site.com", "/simple.html");
 
-  MockAppPublisher mock_app_publisher;
-  WebAppsPublisherHost::SetPublisherForTesting(&mock_app_publisher);
-
   web_app::AppId app_id;
   {
     const std::u16string description = u"Web App";
@@ -212,7 +211,10 @@
                                    /*is_locally_installed=*/false);
   }
 
+  MockAppPublisher mock_app_publisher;
   WebAppsPublisherHost web_apps_publisher_host(profile());
+  web_apps_publisher_host.SetPublisherForTesting(&mock_app_publisher);
+  web_apps_publisher_host.Init();
   mock_app_publisher.Wait();
   EXPECT_EQ(mock_app_publisher.get_deltas().back()->icon_key->icon_effects,
             static_cast<IconEffects>(IconEffects::kRoundCorners |
diff --git a/chrome/browser/apps/app_service/web_apps_utils.cc b/chrome/browser/apps/app_service/web_apps_utils.cc
index 9d95a2cb..47bcea0 100644
--- a/chrome/browser/apps/app_service/web_apps_utils.cc
+++ b/chrome/browser/apps/app_service/web_apps_utils.cc
@@ -4,16 +4,22 @@
 
 #include "chrome/browser/apps/app_service/web_apps_utils.h"
 
+#include "base/bind.h"
+#include "base/callback_helpers.h"
 #include "base/containers/contains.h"
 #include "base/feature_list.h"
 #include "chrome/browser/apps/app_service/intent_util.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/web_applications/components/install_finalizer.h"
 #include "chrome/browser/web_applications/web_app.h"
+#include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/common/chrome_features.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/services/app_service/public/cpp/publisher_base.h"
+#include "content/public/browser/clear_site_data_utils.h"
+#include "url/origin.h"
 
 namespace apps_util {
 
@@ -181,4 +187,41 @@
   }
 }
 
+void UninstallWebApp(Profile* profile,
+                     const web_app::WebApp* web_app,
+                     apps::mojom::UninstallSource uninstall_source,
+                     bool clear_site_data,
+                     bool report_abuse) {
+  auto origin = url::Origin::Create(web_app->start_url());
+
+  web_app::WebAppProvider* provider = web_app::WebAppProvider::Get(profile);
+  DCHECK(provider);
+  DCHECK(
+      provider->install_finalizer().CanUserUninstallWebApp(web_app->app_id()));
+  webapps::WebappUninstallSource webapp_uninstall_source =
+      ConvertUninstallSourceToWebAppUninstallSource(uninstall_source);
+  provider->install_finalizer().UninstallWebApp(
+      web_app->app_id(), webapp_uninstall_source, base::DoNothing());
+  web_app = nullptr;
+
+  if (!clear_site_data) {
+    // TODO(crbug.com/1062885): Add UMA_HISTOGRAM_ENUMERATION here.
+    return;
+  }
+
+  // TODO(crbug.com/1062885): Add UMA_HISTOGRAM_ENUMERATION here.
+  constexpr bool kClearCookies = true;
+  constexpr bool kClearStorage = true;
+  constexpr bool kClearCache = true;
+  constexpr bool kAvoidClosingConnections = false;
+
+  content::ClearSiteData(base::BindRepeating(
+                             [](content::BrowserContext* browser_context) {
+                               return browser_context;
+                             },
+                             base::Unretained(profile)),
+                         origin, kClearCookies, kClearStorage, kClearCache,
+                         kAvoidClosingConnections, base::DoNothing());
+}
+
 }  // namespace apps_util
diff --git a/chrome/browser/apps/app_service/web_apps_utils.h b/chrome/browser/apps/app_service/web_apps_utils.h
index 17ed1a5..0959e76 100644
--- a/chrome/browser/apps/app_service/web_apps_utils.h
+++ b/chrome/browser/apps/app_service/web_apps_utils.h
@@ -51,6 +51,17 @@
 webapps::WebappUninstallSource ConvertUninstallSourceToWebAppUninstallSource(
     apps::mojom::UninstallSource uninstall_source);
 
+// Directly uninstalls |web_app| without prompting the user.
+// If |clear_site_data| is true, any site data associated with the app will
+// be removed.
+// If |report_abuse| is true, the app will be reported for abuse to the Web
+// Store.
+void UninstallWebApp(Profile* profile,
+                     const web_app::WebApp* web_app,
+                     apps::mojom::UninstallSource uninstall_source,
+                     bool clear_site_data,
+                     bool report_abuse);
+
 }  // namespace apps_util
 
 #endif  // CHROME_BROWSER_APPS_APP_SERVICE_WEB_APPS_UTILS_H_
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
index 3f4e3fe..c7c2e64 100644
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -49,6 +49,7 @@
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/recently_audible_helper.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/chrome_paths.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
@@ -531,6 +532,8 @@
       geolocation_overrider_ =
           std::make_unique<device::ScopedGeolocationOverrider>(10, 20);
     }
+
+    host_resolver()->AddRule("*", "127.0.0.1");
   }
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
@@ -4713,6 +4716,34 @@
   DevToolsWindowTesting::CloseDevToolsWindowSync(devtools);
 }
 
+// Tests that random extensions cannot inject content scripts into a platform
+// app's own webview, but the owner platform app can. Regression test for
+// crbug.com/1205675.
+IN_PROC_BROWSER_TEST_F(WebViewTest, NoExtensionScriptsInjectedInWebview) {
+  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
+
+  // Load an extension which injects a content script at document_end. The
+  // script injects a new element into the DOM.
+  LoadExtension(
+      test_data_dir_.AppendASCII("api_test/content_scripts/inject_div"));
+
+  // Load a platform app which creates a webview and injects a content script
+  // into it at document_idle, after document_end. The script expects that the
+  // webview's DOM has not been modified (in this case, by the extension's
+  // content script).
+  ExtensionTestMessageListener app_content_script_listener(
+      "WebViewTest.NO_ELEMENT_INJECTED", false);
+  app_content_script_listener.set_failure_message(
+      "WebViewTest.UNKNOWN_ELEMENT_INJECTED");
+  LoadAppWithGuest("web_view/a_com_webview");
+
+  // The app's content script should have been injected, but the extension's
+  // content script should not have.
+  EXPECT_TRUE(app_content_script_listener.WaitUntilSatisfied())
+      << "'" << app_content_script_listener.message()
+      << "' message was not receieved";
+}
+
 // Regression test for https://crbug.com/1014385
 // We load an extension whose background page attempts to declare variables with
 // names that are the same as guest view types. The declarations should not be
diff --git a/chrome/browser/ash/arc/arc_util_unittest.cc b/chrome/browser/ash/arc/arc_util_unittest.cc
index 1071684..00e62c6 100644
--- a/chrome/browser/ash/arc/arc_util_unittest.cc
+++ b/chrome/browser/ash/arc/arc_util_unittest.cc
@@ -31,7 +31,6 @@
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
 #include "chromeos/dbus/concierge/concierge_client.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_oobe_configuration_client.h"
 #include "chromeos/tpm/stub_install_attributes.h"
 #include "components/account_id/account_id.h"
@@ -759,7 +758,6 @@
 class ArcOobeTest : public ChromeArcUtilTest {
  public:
   ArcOobeTest() {
-    chromeos::DBusThreadManager::GetSetterForTesting();
     chromeos::ConciergeClient::InitializeFake(/*fake_cicerone_client=*/nullptr);
     oobe_configuration_ = std::make_unique<chromeos::OobeConfiguration>();
   }
@@ -770,7 +768,6 @@
     fake_login_display_host_.reset();
     oobe_configuration_.reset();
     chromeos::ConciergeClient::Shutdown();
-    chromeos::DBusThreadManager::Shutdown();
   }
 
  protected:
diff --git a/chrome/browser/ash/crostini/crostini_installer_unittest.cc b/chrome/browser/ash/crostini/crostini_installer_unittest.cc
index ce91209..f1fe829b0a0 100644
--- a/chrome/browser/ash/crostini/crostini_installer_unittest.cc
+++ b/chrome/browser/ash/crostini/crostini_installer_unittest.cc
@@ -108,7 +108,7 @@
     browser_part_.InitializeCrosComponentManager(component_manager_);
 
     chromeos::DlcserviceClient::InitializeFake();
-    chromeos::DBusThreadManager::GetSetterForTesting();
+    chromeos::DBusThreadManager::Initialize();
     chromeos::CiceroneClient::InitializeFake();
     waiting_fake_concierge_client_ =
         new WaitingFakeConciergeClient(chromeos::FakeCiceroneClient::Get());
diff --git a/chrome/browser/ash/login/wizard_controller_browsertest.cc b/chrome/browser/ash/login/wizard_controller_browsertest.cc
index ca6a4ff..5700456 100644
--- a/chrome/browser/ash/login/wizard_controller_browsertest.cc
+++ b/chrome/browser/ash/login/wizard_controller_browsertest.cc
@@ -1076,7 +1076,7 @@
     // timeout in WaitForAutoEnrollmentState on asan builds. TODO(stevenjb):
     // Determine which client(s) need to be created and extract and initialize
     // them. https://crbug.com/949063.
-    DBusThreadManager::GetSetterForTesting();
+    DBusThreadManager::Initialize();
   }
 
   void SetUpOnMainThread() override {
@@ -1085,7 +1085,7 @@
     histogram_tester_ = std::make_unique<base::HistogramTester>();
 
     // Initialize the FakeShillManagerClient. This does not happen
-    // automatically because of the `DBusThreadManager::GetSetterForTesting`
+    // automatically because of the `DBusThreadManager::Initialize`
     // call in `SetUpInProcessBrowserTestFixture`. See https://crbug.com/847422.
     // TODO(pmarko): Find a way for FakeShillManagerClient to be initialized
     // automatically (https://crbug.com/847422).
diff --git a/chrome/browser/ash/plugin_vm/plugin_vm_diagnostics.cc b/chrome/browser/ash/plugin_vm/plugin_vm_diagnostics.cc
index 699d3080d..d42c1aa 100644
--- a/chrome/browser/ash/plugin_vm/plugin_vm_diagnostics.cc
+++ b/chrome/browser/ash/plugin_vm/plugin_vm_diagnostics.cc
@@ -4,10 +4,12 @@
 
 #include "chrome/browser/ash/plugin_vm/plugin_vm_diagnostics.h"
 
+#include <string>
 #include <utility>
 
 #include "base/strings/strcat.h"
 #include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/system/sys_info.h"
 #include "base/values.h"
 #include "chrome/browser/ash/guest_os/guest_os_diagnostics.mojom.h"
@@ -18,10 +20,12 @@
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/grit/generated_resources.h"
 #include "chromeos/dbus/concierge/concierge_client.h"
 #include "chromeos/dbus/concierge/concierge_service.pb.h"
 #include "components/prefs/pref_service.h"
 #include "third_party/protobuf/src/google/protobuf/repeated_field.h"
+#include "ui/base/l10n/l10n_util.h"
 
 namespace plugin_vm {
 
@@ -75,45 +79,52 @@
     // `is_allowed_diagnostics.GetTopError()` so that we can reuse it.
 
     {
-      EntryBuilder entry("Device is supported");
+      EntryBuilder entry(l10n_util::GetStringUTF8(
+          IDS_VM_STATUS_PAGE_DEVICE_IS_SUPPORTED_REQUIREMENT));
       if (!is_allowed_diagnostics.device_supported) {
-        entry.SetFail(
-            base::StrCat({CapitalizedBoardName(), " is not supported"}));
+        entry.SetFail(l10n_util::GetStringFUTF8(
+            IDS_VM_STATUS_PAGE_DEVICE_IS_SUPPORTED_EXPLANATION,
+            base::UTF8ToUTF16(CapitalizedBoardName())));
       }
       builder_.AddEntry(std::move(entry));
     }
 
     {
-      EntryBuilder entry("Profile is supported");
+      EntryBuilder entry(l10n_util::GetStringUTF8(
+          IDS_VM_STATUS_PAGE_PROFILE_IS_SUPPORTED_REQUIREMENT));
 
       switch (is_allowed_diagnostics.profile_supported) {
         case ProfileSupported::kOk:
           break;
         case ProfileSupported::kErrorNonPrimary:
-          entry.SetFail("Secondary profiles are not supported");
+          entry.SetFail(l10n_util::GetStringUTF8(
+              IDS_VM_STATUS_PAGE_SECONDARY_PROFILE_EXPLANATION));
           break;
         case ProfileSupported::kErrorChildAccount:
-          entry.SetFail("Child accounts are not supported");
+          entry.SetFail(l10n_util::GetStringUTF8(
+              IDS_VM_STATUS_PAGE_CHILD_PROFILE_EXPLANATION));
           break;
         case ProfileSupported::kErrorOffTheRecord:
-          entry.SetFail("Guest profiles are not supported");
+          entry.SetFail(l10n_util::GetStringUTF8(
+              IDS_VM_STATUS_PAGE_GUEST_PROFILE_EXPLANATION));
           break;
         case ProfileSupported::kErrorEphemeral:
-          entry.SetFail(
-              "Ephemeral user profiles are not supported. Contact your admin");
+          entry.SetFail(l10n_util::GetStringUTF8(
+              IDS_VM_STATUS_PAGE_EPHEMERAL_PROFILE_EXPLANATION));
           break;
         case ProfileSupported::kErrorNotSupported:
-          entry.SetFail("The profile is not supported");
+          entry.SetFail(l10n_util::GetStringUTF8(
+              IDS_VM_STATUS_PAGE_UNSUPPORTED_PROFILE_EXPLANATION));
           break;
       }
       builder_.AddEntry(std::move(entry));
     }
 
     {
-      EntryBuilder entry("Policies are configured correctly");
+      EntryBuilder entry(
+          l10n_util::GetStringUTF8(IDS_VM_STATUS_PAGE_POLICIES_REQUIREMENT));
       const std::string standard_top_error =
-          "One or more policies are not configured correctly. Please contact "
-          "your administrator";
+          l10n_util::GetStringUTF8(IDS_VM_STATUS_PAGE_INCORRECT_POLICIES_ERROR);
       switch (is_allowed_diagnostics.policy_configured) {
         case PolicyConfigured::kOk: {
           // Additional check for image policy. See b/185281662#comment2.
@@ -124,34 +135,52 @@
           const base::Value* hash =
               image_policy->FindKey(prefs::kPluginVmImageHashKeyName);
           if (!url || !GURL(url->GetString()).is_valid()) {
-            entry.SetFail("Image url is invalid", standard_top_error);
+            entry.SetFail(l10n_util::GetStringUTF8(
+                              IDS_VM_STATUS_PAGE_IMAGE_URL_POLICY_EXPLANATION),
+                          standard_top_error);
           } else if (!hash || hash->GetString().empty()) {
-            entry.SetFail("Image hash is not set", standard_top_error);
+            entry.SetFail(l10n_util::GetStringUTF8(
+                              IDS_VM_STATUS_PAGE_IMAGE_HASH_POLICY_EXPLANATION),
+                          standard_top_error);
           }
         } break;
         case PolicyConfigured::kErrorUnableToCheckPolicy:
-          entry.SetFail("Unable to check policies", standard_top_error);
+          entry.SetFail(
+              l10n_util::GetStringUTF8(
+                  IDS_VM_STATUS_PAGE_UNABLE_TO_CHECK_POLICIES_EXPLANATION),
+              standard_top_error);
           break;
         case PolicyConfigured::kErrorNotEnterpriseEnrolled:
-          entry.SetFail("Device is not enrolled", /*top_error_message=*/
-                        "You must be on an enterprise-enrolled device");
+          entry.SetFail(l10n_util::GetStringUTF8(
+                            IDS_VM_STATUS_PAGE_DEVICE_NOT_ENROLLED_EXPLANATION),
+                        /*top_error_message=*/l10n_util::GetStringUTF8(
+                            IDS_VM_STATUS_PAGE_DEVICE_NOT_ENROLLED_ERROR));
           break;
         case PolicyConfigured::kErrorUserNotAffiliated:
-          entry.SetFail("User is not affiliated with domain",
+          entry.SetFail(l10n_util::GetStringUTF8(
+                            IDS_VM_STATUS_PAGE_USER_NOT_AFFILIATED_EXPLANATION),
                         standard_top_error);
           break;
         case PolicyConfigured::kErrorUnableToCheckDevicePolicy:
-          entry.SetFail("Unable to check whether device is allowed",
-                        standard_top_error);
+          entry.SetFail(
+              l10n_util::GetStringUTF8(
+                  IDS_VM_STATUS_PAGE_UNABLE_TO_CHECK_DEVICE_ALLOW_EXPLANATION),
+              standard_top_error);
           break;
         case PolicyConfigured::kErrorNotAllowedByDevicePolicy:
-          entry.SetFail("Device is not allowed", standard_top_error);
+          entry.SetFail(l10n_util::GetStringUTF8(
+                            IDS_VM_STATUS_PAGE_DEVICE_NOT_ALLOW_EXPLANATION),
+                        standard_top_error);
           break;
         case PolicyConfigured::kErrorNotAllowedByUserPolicy:
-          entry.SetFail("User is not allowed", standard_top_error);
+          entry.SetFail(l10n_util::GetStringUTF8(
+                            IDS_VM_STATUS_PAGE_USER_NOT_ALLOW_EXPLANATION),
+                        standard_top_error);
           break;
         case PolicyConfigured::kErrorLicenseNotSetUp:
-          entry.SetFail("License is not set up", standard_top_error);
+          entry.SetFail(l10n_util::GetStringUTF8(
+                            IDS_VM_STATUS_PAGE_LICENSE_NOT_SET_UP_EXPLANATION),
+                        standard_top_error);
           break;
       }
       builder_.AddEntry(std::move(entry));
@@ -182,17 +211,20 @@
   void OnListVmDisks(
       bool plugin_vm_is_allowed,
       base::Optional<vm_tools::concierge::ListVmDisksResponse> response) {
-    EntryBuilder entry(
-        base::StrCat({"VM \"", plugin_vm::kPluginVmName, "\" exists"}));
+    EntryBuilder entry(l10n_util::GetStringFUTF8(
+        IDS_VM_STATUS_PAGE_DEFAULT_VM_EXISTS_REQUIREMENT,
+        l10n_util::GetStringUTF16(IDS_PLUGIN_VM_APP_NAME)));
 
     if (plugin_vm_is_allowed) {
       if (!response.has_value()) {
-        entry.SetFail("Failed to check VMs");
+        entry.SetFail(l10n_util::GetStringUTF8(
+            IDS_VM_STATUS_PAGE_FAILED_TO_CHECK_VM_EXPLANATION));
       } else if (!HasDefaultVm(response->images())) {
         entry.SetFail(GetMissingDefaultVmExplanation(response->images()),
                       /*top_error_message=*/
-                      "A required virtual machine does not exist. Please try "
-                      "setting up Parallels to continue.");
+                      l10n_util::GetStringFUTF8(
+                          IDS_VM_STATUS_PAGE_MISSING_DEFAULT_VM_ERROR,
+                          l10n_util::GetStringUTF16(IDS_PLUGIN_VM_APP_NAME)));
       } else {
         // Everything is good. Do nothing.
       }
@@ -220,27 +252,32 @@
   }
 
   std::string GetMissingDefaultVmExplanation(const ImageListType& images) {
-    if (images.empty()) {
-      return "No Parallels Desktop VMs found";
-    }
+    std::string string_template = l10n_util::GetPluralStringFUTF8(
+        IDS_VM_STATUS_PAGE_MISSING_DEFAULT_VM_EXPLANATION, images.size());
+    std::vector<std::string> subs{
+        l10n_util::GetStringUTF8(IDS_PLUGIN_VM_APP_NAME)};
 
-    std::stringstream stream;
-    // The string looks like this:
-    //
-    // n Parallels Desktop VM(s) found: "vm1", "vm2"
-    stream << images.size() << " Parallels Desktop VM"
-           << (images.size() >= 2 ? "s" : "") << " found: ";
-    bool first_vm = true;
-    for (auto& image : images) {
-      if (!first_vm) {
-        stream << ", ";
+    if (images.size() > 0) {
+      // In this case, we have a second placeholder VM_NAME_LIST. The substitute
+      // should looke like this: `"vm1", "vm2"`. Note that the l10n tooling does
+      // not support formatting a list of strings, which is why we have to do
+      // the formatting by ourselves here. The formatting might not be ideal for
+      // all languages, but it should be good enough for its purpose.
+      std::stringstream stream;
+      bool first_vm = true;
+      for (auto& image : images) {
+        if (!first_vm) {
+          stream << ", ";
+        }
+        stream << '"' << image.name() << '"';
+
+        first_vm = false;
       }
-      stream << '"' << image.name() << '"';
 
-      first_vm = false;
+      subs.push_back(stream.str());
     }
 
-    return stream.str();
+    return base::ReplaceStringPlaceholders(string_template, subs, nullptr);
   }
 
   Profile* const active_profile_;
diff --git a/chrome/browser/ash/plugin_vm/plugin_vm_installer_unittest.cc b/chrome/browser/ash/plugin_vm/plugin_vm_installer_unittest.cc
index 787b324..080c0ea38 100644
--- a/chrome/browser/ash/plugin_vm/plugin_vm_installer_unittest.cc
+++ b/chrome/browser/ash/plugin_vm/plugin_vm_installer_unittest.cc
@@ -480,7 +480,7 @@
   StartAndRunUntil(InstallingState::kDownloadingImage);
 
   std::string guid = installer_->GetCurrentDownloadGuid();
-  base::Optional<download::DownloadParams> params =
+  const base::Optional<download::DownloadParams>& params =
       download_service_->GetDownload(guid);
   ASSERT_TRUE(params.has_value());
   EXPECT_EQ(guid, params->guid);
diff --git a/chrome/browser/ash/settings/device_settings_test_helper.cc b/chrome/browser/ash/settings/device_settings_test_helper.cc
index 27a4b6e..2194550 100644
--- a/chrome/browser/ash/settings/device_settings_test_helper.cc
+++ b/chrome/browser/ash/settings/device_settings_test_helper.cc
@@ -15,7 +15,6 @@
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/concierge/concierge_client.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/power/fake_power_manager_client.h"
 #include "chromeos/dbus/tpm_manager/tpm_manager_client.h"
 #include "chromeos/dbus/userdataauth/cryptohome_misc_client.h"
@@ -59,7 +58,6 @@
       base::WrapUnique(user_manager_));
   owner_key_util_ = new ownership::MockOwnerKeyUtil();
   device_settings_service_ = std::make_unique<DeviceSettingsService>();
-  dbus_setter_ = chromeos::DBusThreadManager::GetSetterForTesting();
   chromeos::ConciergeClient::InitializeFake(/*fake_cicerone_client=*/nullptr);
   chromeos::UserDataAuthClient::InitializeFake();
   chromeos::CryptohomeMiscClient::InitializeFake();
@@ -92,7 +90,6 @@
   chromeos::CryptohomeMiscClient::Shutdown();
   chromeos::UserDataAuthClient::Shutdown();
   chromeos::ConciergeClient::Shutdown();
-  chromeos::DBusThreadManager::Shutdown();
   device_policy_.reset();
   base::RunLoop().RunUntilIdle();
   profile_.reset();
diff --git a/chrome/browser/ash/settings/device_settings_test_helper.h b/chrome/browser/ash/settings/device_settings_test_helper.h
index 222b411..2572b5b 100644
--- a/chrome/browser/ash/settings/device_settings_test_helper.h
+++ b/chrome/browser/ash/settings/device_settings_test_helper.h
@@ -23,10 +23,6 @@
 
 class TestingProfile;
 
-namespace chromeos {
-class DBusThreadManagerSetter;
-}  // namespace chromeos
-
 namespace ash {
 
 // Wraps the singleton device settings and initializes it to the point where it
@@ -81,8 +77,6 @@
   // with the global instance (DeviceSettingsService::Get()).
   std::unique_ptr<DeviceSettingsService> device_settings_service_;
 
-  std::unique_ptr<chromeos::DBusThreadManagerSetter> dbus_setter_;
-
   std::unique_ptr<TestingProfile> profile_;
 
  private:
diff --git a/chrome/browser/browsing_data/counters/site_data_counting_helper_unittest.cc b/chrome/browser/browsing_data/counters/site_data_counting_helper_unittest.cc
index 0d586db..adfc7ce 100644
--- a/chrome/browser/browsing_data/counters/site_data_counting_helper_unittest.cc
+++ b/chrome/browser/browsing_data/counters/site_data_counting_helper_unittest.cc
@@ -12,11 +12,9 @@
 #include "base/run_loop.h"
 #include "base/task/post_task.h"
 #include "base/test/bind.h"
-#include "base/test/scoped_mock_clock_override.h"
 #include "chrome/browser/browsing_data/counters/site_data_counting_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/test/base/testing_profile.h"
-#include "components/services/storage/public/mojom/local_storage_control.mojom.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/storage_partition.h"
@@ -24,7 +22,6 @@
 #include "net/cookies/cookie_access_result.h"
 #include "services/network/public/mojom/cookie_manager.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/mojom/dom_storage/storage_area.mojom.h"
 
 class SiteDataCountingHelperTest : public testing::Test {
  public:
@@ -76,34 +73,20 @@
     run_loop.Run();
   }
 
-  // Creates local storage data with a last-modified time given by the return
-  // value of base::Time::Now().
-  void CreateLocalStorage(const std::vector<std::string>& storage_origins) {
-    storage::mojom::LocalStorageControl* local_storage_control =
-        profile()->GetDefaultStoragePartition()->GetLocalStorageControl();
+  void CreateLocalStorage(
+      base::Time creation_time,
+      const std::vector<base::FilePath::StringPieceType>& storage_origins) {
+    // Note: This test depends on details of how the dom_storage library
+    // stores data in the host file system.
+    base::FilePath storage_path =
+        profile()->GetPath().AppendASCII("Local Storage");
+    base::CreateDirectory(storage_path);
 
-    for (const std::string& origin_str : storage_origins) {
-      url::Origin origin = url::Origin::Create(GURL(origin_str));
-      ASSERT_FALSE(origin.opaque());
-      mojo::Remote<blink::mojom::StorageArea> area;
-      local_storage_control->BindStorageArea(origin,
-                                             area.BindNewPipeAndPassReceiver());
-
-      bool success = false;
-      base::RunLoop put_run_loop;
-      area->Put({'k', 'e', 'y'}, {'v', 'a', 'l', 'u', 'e'}, base::nullopt,
-                "source", base::BindLambdaForTesting([&](bool success_in) {
-                  success = success_in;
-                  put_run_loop.Quit();
-                }));
-      put_run_loop.Run();
-      ASSERT_TRUE(success);
-
-      // Flushing causes metadata to be written, so that the last-modified time
-      // is recorded now.
-      base::RunLoop flush_run_loop;
-      local_storage_control->Flush(flush_run_loop.QuitClosure());
-      flush_run_loop.Run();
+    // Write some files.
+    for (const auto& origin : storage_origins) {
+      base::WriteFile(storage_path.Append(origin), NULL, 0);
+      base::TouchFile(storage_path.Append(origin), creation_time,
+                      creation_time);
     }
   }
 
@@ -155,17 +138,14 @@
 }
 
 TEST_F(SiteDataCountingHelperTest, LocalStorage) {
-  // Override base::Time::Now() to set data "one day ago".
-  base::ScopedMockClockOverride clock_override;
-  CreateLocalStorage({"https://example.com"});
-  clock_override.Advance(base::TimeDelta::FromDays(1));
-
-  // Set more data "now".
-  CreateLocalStorage({"https://bing.com"});
-
   base::Time now = base::Time::Now();
   base::Time last_hour = now - base::TimeDelta::FromHours(1);
+  base::Time last_day = now - base::TimeDelta::FromDays(1);
   base::Time two_days_ago = now - base::TimeDelta::FromDays(2);
+  CreateLocalStorage(last_day,
+                     {FILE_PATH_LITERAL("https_example.com_443.localstorage")});
+  CreateLocalStorage(now,
+                     {FILE_PATH_LITERAL("https_bing.com_443.localstorage")});
 
   EXPECT_EQ(1, CountEntries(base::Time(), last_hour));
   EXPECT_EQ(1, CountEntries(last_hour, base::Time::Max()));
@@ -178,7 +158,9 @@
 TEST_F(SiteDataCountingHelperTest, CookiesAndLocalStorage) {
   base::Time now = base::Time::Now();
   CreateCookies(now, {"http://example.com", "https://google.com"});
-  CreateLocalStorage({"https://example.com", "https://bing.com"});
+  CreateLocalStorage(now,
+                     {FILE_PATH_LITERAL("https_example.com_443.localstorage"),
+                      FILE_PATH_LITERAL("https_bing.com_443.localstorage")});
 
   EXPECT_EQ(3, CountEntries(base::Time(), base::Time::Max()));
 }
@@ -186,7 +168,9 @@
 TEST_F(SiteDataCountingHelperTest, SameHostDifferentScheme) {
   base::Time now = base::Time::Now();
   CreateCookies(now, {"http://google.com", "https://google.com"});
-  CreateLocalStorage({"https://google.com", "http://google.com"});
+  CreateLocalStorage(now,
+                     {FILE_PATH_LITERAL("https_google.com_443.localstorage"),
+                      FILE_PATH_LITERAL("http_google.com_80.localstorage")});
 
   EXPECT_EQ(1, CountEntries(base::Time(), base::Time::Max()));
 }
diff --git a/chrome/browser/chromeos/concierge_helper_service_unittest.cc b/chrome/browser/chromeos/concierge_helper_service_unittest.cc
index b91080c..b63c2b6 100644
--- a/chrome/browser/chromeos/concierge_helper_service_unittest.cc
+++ b/chrome/browser/chromeos/concierge_helper_service_unittest.cc
@@ -11,7 +11,6 @@
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/dbus/concierge/concierge_service.pb.h"
 #include "chromeos/dbus/concierge/fake_concierge_client.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "content/public/test/browser_task_environment.h"
 #include "dbus/bus.h"
 #include "dbus/object_proxy.h"
@@ -79,14 +78,12 @@
 
   // testing::Test:
   void SetUp() override {
-    DBusThreadManager::GetSetterForTesting();
     TestConciergeClient::Initialize();
     service_ = ConciergeHelperService::GetForBrowserContext(&profile_);
   }
 
   void TearDown() override {
     ConciergeClient::Shutdown();  // deletes the client created in SetUp().
-    DBusThreadManager::Shutdown();
   }
 
  protected:
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
index 7e611360..798c47d 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
@@ -72,6 +72,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/api/file_manager_private.h"
 #include "chrome/common/pref_names.h"
+#include "chrome/test/base/test_switches.h"
 #include "chromeos/components/drivefs/drivefs_host.h"
 #include "chromeos/components/drivefs/fake_drivefs.h"
 #include "chromeos/components/drivefs/mojom/drivefs.mojom.h"
@@ -1716,10 +1717,10 @@
     disabled_features.push_back(chromeos::features::kFilesTrash);
   }
 
-  if (command_line->HasSwitch("devtools-code-coverage") &&
+  if (command_line->HasSwitch(switches::kDevtoolsCodeCoverage) &&
       options.guest_mode != IN_INCOGNITO) {
     devtools_code_coverage_dir_ =
-        command_line->GetSwitchValuePath("devtools-code-coverage");
+        command_line->GetSwitchValuePath(switches::kDevtoolsCodeCoverage);
   }
 
   // This is destroyed in |TearDown()|. We cannot initialize this in the
diff --git a/chrome/browser/chromeos/input_method/native_input_method_engine.cc b/chrome/browser/chromeos/input_method/native_input_method_engine.cc
index f2aaa47e..8ae03b68 100644
--- a/chrome/browser/chromeos/input_method/native_input_method_engine.cc
+++ b/chrome/browser/chromeos/input_method/native_input_method_engine.cc
@@ -23,7 +23,6 @@
 #include "components/prefs/pref_service.h"
 #include "ui/base/ime/chromeos/ime_bridge.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
-#include "ui/base/ime/chromeos/input_method_ukm.h"
 #include "ui/events/keycodes/dom/keycode_converter.h"
 
 namespace chromeos {
@@ -615,16 +614,6 @@
   assistive_suggester_->OnExternalSuggestionsUpdated(suggestions);
 }
 
-void NativeInputMethodEngine::ImeObserver::RecordUkm(
-    ime::mojom::UkmEntryPtr entry) {
-  if (entry->is_non_compliant_api()) {
-    ui::RecordUkmNonCompliantApi(
-        GetInputContext()->GetClientSourceForMetrics(),
-        static_cast<int>(
-            entry->get_non_compliant_api()->non_compliant_operation));
-  }
-}
-
 void NativeInputMethodEngine::ImeObserver::FlushForTesting() {
   remote_manager_.FlushForTesting();
   if (remote_to_engine_.is_bound())
diff --git a/chrome/browser/chromeos/input_method/native_input_method_engine.h b/chrome/browser/chromeos/input_method/native_input_method_engine.h
index 6bde548f..ff14b0d0 100644
--- a/chrome/browser/chromeos/input_method/native_input_method_engine.h
+++ b/chrome/browser/chromeos/input_method/native_input_method_engine.h
@@ -160,7 +160,6 @@
                             RequestSuggestionsCallback callback) override;
     void DisplaySuggestions(
         const std::vector<ime::TextSuggestion>& suggestions) override;
-    void RecordUkm(ime::mojom::UkmEntryPtr entry) override;
 
     // Called when suggestions are collected from the system via
     // suggestions_collector_.
diff --git a/chrome/browser/chromeos/input_method/native_input_method_engine_unittest.cc b/chrome/browser/chromeos/input_method/native_input_method_engine_unittest.cc
index 9d55991a..ef5f002fe 100644
--- a/chrome/browser/chromeos/input_method/native_input_method_engine_unittest.cc
+++ b/chrome/browser/chromeos/input_method/native_input_method_engine_unittest.cc
@@ -13,22 +13,15 @@
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/services/ime/mock_input_channel.h"
 #include "chromeos/services/ime/public/mojom/input_engine.mojom.h"
-#include "components/ukm/content/source_url_recorder.h"
-#include "components/ukm/test_ukm_recorder.h"
-#include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_task_environment.h"
-#include "content/public/test/navigation_simulator.h"
-#include "content/public/test/test_renderer_host.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/ime/chromeos/ime_bridge.h"
-#include "ui/base/ime/chromeos/input_method_chromeos.h"
 #include "ui/base/ime/chromeos/mock_ime_input_context_handler.h"
 #include "ui/base/ime/chromeos/mock_input_method_manager.h"
-#include "ui/base/ime/fake_text_input_client.h"
 #include "ui/base/ime/text_input_flags.h"
 #include "ui/events/keycodes/dom/dom_code.h"
 
@@ -47,7 +40,8 @@
 
 constexpr char kEngineIdUs[] = "xkb:us::eng";
 
-void SetPhysicalTypingAutocorrectEnabled(Profile& profile, bool enabled) {
+void SetPhysicalTypingAutocorrectEnabled(TestingProfile& profile,
+                                         bool enabled) {
   base::Value input_method_setting(base::Value::Type::DICTIONARY);
   input_method_setting.SetPath(
       std::string(kEngineIdUs) + ".physicalKeyboardAutoCorrectionLevel",
@@ -356,92 +350,5 @@
   InputMethodManager::Shutdown();
 }
 
-// TODO(crbug.com/1148157): Refactor NativeInputMethodEngine etc. to avoid
-// hidden dependencies on globals such as ImeBridge.
-class NativeInputMethodEngineWithRenderViewHostTest
-    : public content::RenderViewHostTestHarness {
-  void SetUp() override {
-    content::RenderViewHostTestHarness::SetUp();
-    ukm::InitializeSourceUrlRecorderForWebContents(web_contents());
-
-    feature_list_.InitWithFeatures(
-        /*enabled_features=*/{features::kAssistPersonalInfo,
-                              features::kAssistPersonalInfoEmail,
-                              features::kAssistPersonalInfoName,
-                              features::kEmojiSuggestAddition,
-                              features::kImeMojoDecoder,
-                              features::kSystemLatinPhysicalTyping},
-        /*disabled_features=*/{});
-
-    // Needed by NativeInputMethodEngine to interact with the input field.
-    ui::IMEBridge::Initialize();
-
-    // Needed by NativeInputMethodEngine for the virtual keyboard.
-    keyboard_controller_client_test_helper_ =
-        ChromeKeyboardControllerClientTestHelper::InitializeWithFake();
-  }
-
-  std::unique_ptr<content::BrowserContext> CreateBrowserContext() override {
-    return std::make_unique<TestingProfile>();
-  }
-
- private:
-  base::test::ScopedFeatureList feature_list_;
-  std::unique_ptr<ChromeKeyboardControllerClientTestHelper>
-      keyboard_controller_client_test_helper_;
-};
-
-TEST_F(NativeInputMethodEngineWithRenderViewHostTest, RecordUkmAddsUkmEntry) {
-  GURL url("https://www.example.com/");
-  content::NavigationSimulator::NavigateAndCommitFromBrowser(web_contents(),
-                                                             url);
-
-  auto* testing_profile = static_cast<TestingProfile*>(browser_context());
-  SetPhysicalTypingAutocorrectEnabled(*testing_profile, true);
-
-  testing::NiceMock<ime::MockInputChannel> mock_input_channel;
-  mojo::Remote<ime::mojom::InputChannel> remote;
-  input_method::InputMethodManager::Initialize(
-      new TestInputMethodManager(&mock_input_channel, &remote));
-  NativeInputMethodEngine engine;
-  engine.Initialize(std::make_unique<StubInputMethodEngineObserver>(),
-                    /*extension_id=*/"", testing_profile);
-  ui::IMEEngineHandlerInterface::InputContext input_context(
-      ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_MODE_DEFAULT,
-      ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_MOUSE,
-      /*should_do_learning=*/true);
-  engine.Enable(kEngineIdUs);
-  engine.FlushForTesting();
-
-  ukm::TestAutoSetUkmRecorder test_recorder;
-  test_recorder.EnableRecording(false /* extensions */);
-  ASSERT_EQ(0u, test_recorder.entries_count());
-
-  ui::InputMethodChromeOS ime(nullptr);
-  ui::FakeTextInputClient fake_text_input_client(ui::TEXT_INPUT_TYPE_TEXT);
-  fake_text_input_client.set_source_id(
-      ukm::GetSourceIdForWebContentsDocument(web_contents()));
-  ime.SetFocusedTextInputClient(&fake_text_input_client);
-  ui::IMEBridge::Get()->SetInputContextHandler(&ime);
-
-  auto entry = ime::mojom::UkmEntry::New();
-  auto metric = ime::mojom::NonCompliantApiMetric::New();
-  metric->non_compliant_operation =
-      ime::mojom::InputMethodApiOperation::kSetCompositionText;
-  entry->set_non_compliant_api(std::move(metric));
-  remote->RecordUkm(std::move(entry));
-  remote.FlushForTesting();
-
-  EXPECT_EQ(0u, test_recorder.sources_count());
-  EXPECT_EQ(1u, test_recorder.entries_count());
-  const auto entries =
-      test_recorder.GetEntriesByName("InputMethod.NonCompliantApi");
-  ukm::TestAutoSetUkmRecorder::ExpectEntryMetric(
-      entries[0], "NonCompliantOperation",
-      (int)ime::mojom::InputMethodApiOperation::kSetCompositionText);
-
-  InputMethodManager::Shutdown();
-}
-
 }  // namespace
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/policy/lock_to_single_user_manager_unittest.cc b/chrome/browser/chromeos/policy/lock_to_single_user_manager_unittest.cc
index 1061ebf..a4ea8ffe 100644
--- a/chrome/browser/chromeos/policy/lock_to_single_user_manager_unittest.cc
+++ b/chrome/browser/chromeos/policy/lock_to_single_user_manager_unittest.cc
@@ -37,10 +37,10 @@
   ~LockToSingleUserManagerTest() override = default;
 
   void SetUp() override {
-    // This setter will initialize DBusThreadManager.
-    // This is required before ArcSessionManager's constructor calls
-    // DBusThreadManager::Get().
-    chromeos::DBusThreadManager::GetSetterForTesting();
+    // This is required before Concierge tests start calling
+    // DBusThreadManager::Get() for GetAnomalyDetectorClient.
+    chromeos::DBusThreadManager::Initialize();
+
     chromeos::CiceroneClient::InitializeFake();
     chromeos::ConciergeClient::InitializeFake();
     chromeos::SeneschalClient::InitializeFake();
diff --git a/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustSignalsCoordinatorTest.java b/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustSignalsCoordinatorTest.java
index c3492df5..13c042e 100644
--- a/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustSignalsCoordinatorTest.java
+++ b/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustSignalsCoordinatorTest.java
@@ -24,23 +24,20 @@
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
-import org.junit.rules.TestRule;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
 import org.mockito.invocation.InvocationOnMock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
 import org.mockito.stubbing.Answer;
 
 import org.chromium.base.Callback;
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.Supplier;
-import org.chromium.base.test.BaseJUnit4ClassRunner;
-import org.chromium.base.test.UiThreadTest;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.DisableIf;
-import org.chromium.base.test.util.DisabledTest;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.merchant_viewer.MerchantTrustMetrics.MessageClearReason;
@@ -49,8 +46,7 @@
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabModelFilterProvider;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
-import org.chromium.chrome.test.ChromeBrowserTestRule;
-import org.chromium.chrome.test.util.browser.Features;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.components.messages.DismissReason;
@@ -70,19 +66,15 @@
  * {@link WindowAndroid} which has a dependency on android.View.Display.Mode which is not supported
  * on versions prior to Android M.
  */
-@RunWith(BaseJUnit4ClassRunner.class)
+@RunWith(ChromeJUnit4ClassRunner.class)
 @EnableFeatures({ChromeFeatureList.COMMERCE_MERCHANT_VIEWER + "<Study"})
 @CommandLineFlags.
 Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, "force-fieldtrials=Study/Group"})
 @DisableIf.Build(sdk_is_less_than = Build.VERSION_CODES.M)
 @DisableIf.Device(type = {UiDisableIf.TABLET})
-@DisabledTest(message = "crbug.com/1205485")
 public class MerchantTrustSignalsCoordinatorTest {
     @Rule
-    public final ChromeBrowserTestRule mBrowserTestRule = new ChromeBrowserTestRule();
-
-    @Rule
-    public TestRule mProcessor = new Features.InstrumentationProcessor();
+    public MockitoRule mMockitoRule = MockitoJUnit.rule();
 
     @Mock
     private TabModelSelector mMockTabModelSelector;
@@ -155,7 +147,6 @@
                     .build();
     @Before
     public void setUp() {
-        MockitoAnnotations.initMocks(this);
         doReturn(mTabModelFilterProvider).when(mMockTabModelSelector).getTabModelFilterProvider();
         doReturn("Test").when(mMockResources).getString(anyInt());
         doReturn("Test").when(mMockResources).getString(anyInt(), anyObject());
@@ -171,7 +162,6 @@
                 .getForLastUsedProfile();
     }
 
-    @UiThreadTest
     @SmallTest
     @Test
     @CommandLineFlags.
@@ -205,7 +195,6 @@
                 .getDataForUrl(eq(mMockGurl), any(Callback.class));
     }
 
-    @UiThreadTest
     @SmallTest
     @Test
     @CommandLineFlags.
@@ -234,7 +223,6 @@
                         any(Callback.class));
     }
 
-    @UiThreadTest
     @SmallTest
     @Test
     @CommandLineFlags.
@@ -263,7 +251,6 @@
                         any(Callback.class));
     }
 
-    @UiThreadTest
     @SmallTest
     @Test
     @CommandLineFlags.
@@ -292,7 +279,6 @@
                         any(Callback.class));
     }
 
-    @UiThreadTest
     @SmallTest
     @Test
     public void testMaybeDisplayMessageWithScheduledMessage() {
@@ -309,7 +295,6 @@
                 .expedite(mOnMessageEnqueuedCallbackCaptor.capture());
     }
 
-    @UiThreadTest
     @SmallTest
     @Test
     public void testMaybeDisplayMessageWithScheduledMessageForDifferentHost() {
@@ -333,7 +318,6 @@
                         any(Callback.class));
     }
 
-    @UiThreadTest
     @SmallTest
     @Test
     public void testMaybeDisplayMessageWithInvalidStorage() {
diff --git a/chrome/browser/commerce/price_tracking/android/javatests/src/org/chromium/chrome/browser/price_tracking/PriceDropNotificationManagerTest.java b/chrome/browser/commerce/price_tracking/android/javatests/src/org/chromium/chrome/browser/price_tracking/PriceDropNotificationManagerTest.java
index 8084f2f..759a8b69 100644
--- a/chrome/browser/commerce/price_tracking/android/javatests/src/org/chromium/chrome/browser/price_tracking/PriceDropNotificationManagerTest.java
+++ b/chrome/browser/commerce/price_tracking/android/javatests/src/org/chromium/chrome/browser/price_tracking/PriceDropNotificationManagerTest.java
@@ -6,6 +6,7 @@
 
 import static androidx.test.espresso.intent.Intents.intended;
 import static androidx.test.espresso.intent.matcher.IntentMatchers.hasAction;
+import static androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent;
 import static androidx.test.espresso.intent.matcher.IntentMatchers.hasData;
 
 import static org.hamcrest.Matchers.allOf;
@@ -187,7 +188,8 @@
     public void testOnNotificationClicked() {
         Intents.init();
         mPriceDropNotificationManager.onNotificationClicked(TEST_URL);
-        intended(allOf(hasAction(Intent.ACTION_VIEW), hasData(TEST_URL)));
+        intended(allOf(hasAction(Intent.ACTION_VIEW), hasData(TEST_URL),
+                hasComponent(ChromeLauncherActivity.class.getName())));
         Intents.release();
     }
 
@@ -197,7 +199,8 @@
         Intents.init();
         mPriceDropNotificationManager.onNotificationActionClicked(
                 ACTION_ID_VISIT_SITE, TEST_URL, null);
-        intended(allOf(hasAction(Intent.ACTION_VIEW), hasData(TEST_URL)));
+        intended(allOf(hasAction(Intent.ACTION_VIEW), hasData(TEST_URL),
+                hasComponent(ChromeLauncherActivity.class.getName())));
         Intents.release();
     }
 }
diff --git a/chrome/browser/content_creation/notes/internal/android/BUILD.gn b/chrome/browser/content_creation/notes/internal/android/BUILD.gn
index 5ea16977..f2b1b02 100644
--- a/chrome/browser/content_creation/notes/internal/android/BUILD.gn
+++ b/chrome/browser/content_creation/notes/internal/android/BUILD.gn
@@ -18,6 +18,9 @@
     "java/src/org/chromium/chrome/browser/content_creation/notes/NoteCreationMediator.java",
     "java/src/org/chromium/chrome/browser/content_creation/notes/NoteProperties.java",
     "java/src/org/chromium/chrome/browser/content_creation/notes/NoteServiceFactory.java",
+    "java/src/org/chromium/chrome/browser/content_creation/notes/fonts/GoogleFontService.java",
+    "java/src/org/chromium/chrome/browser/content_creation/notes/fonts/TypefaceRequest.java",
+    "java/src/org/chromium/chrome/browser/content_creation/notes/fonts/TypefaceResponse.java",
     "java/src/org/chromium/chrome/browser/content_creation/notes/top_bar/TopBarCoordinator.java",
     "java/src/org/chromium/chrome/browser/content_creation/notes/top_bar/TopBarView.java",
   ]
@@ -29,6 +32,7 @@
     "//chrome/browser/profiles/android:java",
     "//components/browser_ui/styles/android:java_resources",
     "//components/content_creation/notes/android:java",
+    "//content/public/android:content_java_resources",
     "//third_party/android_deps:android_support_v7_appcompat_java",
     "//ui/android:ui_java",
   ]
diff --git a/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/NoteCreationCoordinatorImpl.java b/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/NoteCreationCoordinatorImpl.java
index 211d2b75..2c08ecb 100644
--- a/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/NoteCreationCoordinatorImpl.java
+++ b/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/NoteCreationCoordinatorImpl.java
@@ -9,6 +9,7 @@
 
 import androidx.fragment.app.FragmentActivity;
 
+import org.chromium.chrome.browser.content_creation.notes.fonts.GoogleFontService;
 import org.chromium.chrome.browser.content_creation.notes.top_bar.TopBarCoordinator;
 import org.chromium.components.content_creation.notes.NoteService;
 import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
@@ -29,7 +30,8 @@
 
         mListModel = new ModelList();
 
-        mMediator = new NoteCreationMediator(mListModel, noteService);
+        mMediator =
+                new NoteCreationMediator(mListModel, new GoogleFontService(mActivity), noteService);
 
         mDialog = new NoteCreationDialog();
         mDialog.initDialog(this::onViewCreated);
diff --git a/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/NoteCreationMediator.java b/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/NoteCreationMediator.java
index 94f74fc..8ff5052 100644
--- a/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/NoteCreationMediator.java
+++ b/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/NoteCreationMediator.java
@@ -4,13 +4,23 @@
 
 package org.chromium.chrome.browser.content_creation.notes;
 
+import android.graphics.Typeface;
+import android.os.Looper;
+
+import org.chromium.chrome.browser.content_creation.notes.fonts.GoogleFontService;
+import org.chromium.chrome.browser.content_creation.notes.fonts.TypefaceRequest;
+import org.chromium.chrome.browser.content_creation.notes.fonts.TypefaceResponse;
 import org.chromium.components.content_creation.notes.NoteService;
 import org.chromium.components.content_creation.notes.models.NoteTemplate;
 import org.chromium.ui.modelutil.MVCListAdapter.ListItem;
 import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
 import org.chromium.ui.modelutil.PropertyModel;
 
+import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * Mediator for the note creation component.
@@ -18,31 +28,97 @@
 public class NoteCreationMediator {
     private final ModelList mListModel;
     private final NoteService mNoteService;
+    private final GoogleFontService mFontService;
 
     /**
      * Constructor which will also kick-off the asynchronous retrieval of Note
      * templates.
      */
-    public NoteCreationMediator(ModelList listModel, NoteService noteService) {
+    public NoteCreationMediator(
+            ModelList listModel, GoogleFontService fontService, NoteService noteService) {
         mListModel = listModel;
         mNoteService = noteService;
+        mFontService = fontService;
 
-        mNoteService.getTemplates(this::populateList);
+        mNoteService.getTemplates(this::resolveTypefaces);
     }
 
-    private void populateList(List<NoteTemplate> templates) {
-        assert mListModel.size() == 0;
+    private void resolveTypefaces(List<NoteTemplate> templates) {
+        // Build an association between the templates and their typeface request
+        // while maintaining the templates' ordering.
+        List<RequestTuple> requestTuples = new ArrayList<>();
         for (NoteTemplate template : templates) {
-            ListItem listItem =
-                    new ListItem(NoteProperties.NOTE_VIEW_TYPE, buildModelFromTemplate(template));
+            requestTuples.add(new RequestTuple(template));
+        }
+
+        // Extract the set of typeface requests and resolve them.
+        Set<TypefaceRequest> requests = new HashSet<>();
+        for (RequestTuple tuple : requestTuples) {
+            requests.add(tuple.typefaceRequest);
+        }
+
+        mFontService.fetchFonts(requests, new GoogleFontService.GoogleFontRequestCallback() {
+            @Override
+            public void onResponsesReceived(Map<TypefaceRequest, TypefaceResponse> resultsMap) {
+                populateList(requestTuples, resultsMap);
+            }
+        });
+    }
+
+    private void populateList(
+            List<RequestTuple> requestTuples, Map<TypefaceRequest, TypefaceResponse> resultsMap) {
+        // The list should still be empty.
+        assert mListModel.size() == 0;
+
+        // Ensure that this code is running on the main thread.
+        assert Looper.getMainLooper() == Looper.myLooper();
+
+        // Only add a template to the ModelList when a Typeface has successfully been loaded for it.
+        for (RequestTuple tuple : requestTuples) {
+            TypefaceResponse response = getOrDefault(resultsMap, tuple.typefaceRequest, null);
+            if (response == null) {
+                // TODO (crbug.com/1194168): Log this case.
+                continue;
+            }
+
+            if (response.isError()) {
+                // TODO (crbug.com/1194168): Log this case.
+                continue;
+            }
+
+            ListItem listItem = new ListItem(
+                    NoteProperties.NOTE_VIEW_TYPE, buildModel(tuple.template, response.typeface));
             mListModel.add(listItem);
         }
     }
 
-    private PropertyModel buildModelFromTemplate(NoteTemplate template) {
+    private PropertyModel buildModel(NoteTemplate template, Typeface typeface) {
         PropertyModel.Builder builder = new PropertyModel.Builder(NoteProperties.ALL_KEYS)
-                                                .with(NoteProperties.TEMPLATE, template);
+                                                .with(NoteProperties.TEMPLATE, template)
+                                                .with(NoteProperties.TYPEFACE, typeface);
 
         return builder.build();
     }
+
+    private <T, U> T getOrDefault(Map<U, T> map, U key, T defaultValue) {
+        if (map == null || !map.containsKey(key)) {
+            return defaultValue;
+        }
+
+        T value = map.get(key);
+        return value == null ? defaultValue : value;
+    }
+
+    /**
+     * Tuple object holding a NoteTemplate along with its TypefaceRequest.
+     */
+    private class RequestTuple {
+        public final NoteTemplate template;
+        public final TypefaceRequest typefaceRequest;
+
+        public RequestTuple(NoteTemplate template) {
+            this.template = template;
+            this.typefaceRequest = TypefaceRequest.createFromTextStyle(template.textStyle);
+        }
+    }
 }
diff --git a/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/NoteProperties.java b/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/NoteProperties.java
index b0cb2578..5f6b80b 100644
--- a/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/NoteProperties.java
+++ b/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/NoteProperties.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.content_creation.notes;
 
+import android.graphics.Typeface;
+
 import org.chromium.components.content_creation.notes.models.NoteTemplate;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey;
@@ -16,5 +18,8 @@
     static final WritableObjectPropertyKey<NoteTemplate> TEMPLATE =
             new WritableObjectPropertyKey<>();
 
-    static final PropertyKey[] ALL_KEYS = new PropertyKey[] {TEMPLATE};
+    /** The Typeface instance that has been loaded for the associated template. */
+    static final WritableObjectPropertyKey<Typeface> TYPEFACE = new WritableObjectPropertyKey<>();
+
+    static final PropertyKey[] ALL_KEYS = new PropertyKey[] {TEMPLATE, TYPEFACE};
 }
\ No newline at end of file
diff --git a/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/fonts/GoogleFontService.java b/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/fonts/GoogleFontService.java
new file mode 100644
index 0000000..0539c3c7
--- /dev/null
+++ b/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/fonts/GoogleFontService.java
@@ -0,0 +1,103 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.content_creation.notes.fonts;
+
+import android.app.Activity;
+import android.graphics.Typeface;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+
+import androidx.core.provider.FontRequest;
+import androidx.core.provider.FontsContractCompat;
+
+import org.chromium.content.R;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Service in charge of using Android's Downloadable Fonts APIs to load Google
+ * Fonts Typeface instances.
+ */
+public class GoogleFontService {
+    private static final String THREAD_NAME = "GoogleFontHandlerThread";
+
+    private final Activity mActivity;
+
+    public GoogleFontService(Activity activity) {
+        this.mActivity = activity;
+    }
+
+    /**
+     * Fetches Google Fonts Typeface instances based on the provided set of |requests|.
+     * Asynchronously returns the responses as a Map from the original requests to
+     * their responses via the |resultsCallback|.
+     */
+    public void fetchFonts(
+            Set<TypefaceRequest> requests, GoogleFontRequestCallback resultsCallback) {
+        if (requests == null || requests.isEmpty() || resultsCallback == null) {
+            return;
+        }
+
+        HandlerThread handlerThread = new HandlerThread(THREAD_NAME);
+        handlerThread.start();
+
+        Map<TypefaceRequest, TypefaceResponse> results = new HashMap<>();
+
+        for (TypefaceRequest request : requests) {
+            FontRequest fontRequest =
+                    new FontRequest("com.google.android.gms.fonts", "com.google.android.gms",
+                            request.toQuery(), R.array.ui_com_google_android_gms_fonts_certs);
+
+            FontsContractCompat.FontRequestCallback fetchingCallback =
+                    new FontsContractCompat.FontRequestCallback() {
+                        @Override
+                        public void onTypefaceRetrieved(Typeface typeface) {
+                            results.put(request, new TypefaceResponse(typeface));
+                            onResultsUpdated(
+                                    results, requests.size(), resultsCallback, handlerThread);
+                        }
+
+                        @Override
+                        public void onTypefaceRequestFailed(int reason) {
+                            results.put(request, new TypefaceResponse(reason));
+                            onResultsUpdated(
+                                    results, requests.size(), resultsCallback, handlerThread);
+                        }
+                    };
+
+            Handler handler = new Handler(handlerThread.getLooper());
+            FontsContractCompat.requestFont(this.mActivity, fontRequest, fetchingCallback, handler);
+        }
+    }
+
+    private void onResultsUpdated(Map<TypefaceRequest, TypefaceResponse> resultsMap,
+            int nbExpectedResults, GoogleFontRequestCallback callback,
+            HandlerThread handlerThread) {
+        if (resultsMap.size() != nbExpectedResults) {
+            // Still missing results, wait for more to come in.
+            return;
+        }
+
+        // Make sure the results are returned on the main thread, and exit the
+        // worker thread.
+        new Handler(Looper.getMainLooper()).post(() -> {
+            callback.onResponsesReceived(resultsMap);
+        });
+        handlerThread.quitSafely();
+    }
+
+    /**
+     * Callback type for asynchronously receiving the results of fetching
+     * Google Fonts typefaces.
+     */
+    public static class GoogleFontRequestCallback {
+        public void onResponsesReceived(Map<TypefaceRequest, TypefaceResponse> resultsMap) {
+            // No-op.
+        }
+    }
+}
diff --git a/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/fonts/TypefaceRequest.java b/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/fonts/TypefaceRequest.java
new file mode 100644
index 0000000..cf33a29a
--- /dev/null
+++ b/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/fonts/TypefaceRequest.java
@@ -0,0 +1,58 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.content_creation.notes.fonts;
+
+import org.chromium.components.content_creation.notes.models.TextStyle;
+
+import java.util.Locale;
+import java.util.Objects;
+
+/**
+ * Class used to represent queries used to load fonts.
+ */
+public class TypefaceRequest {
+    public final String fontName;
+    public final int weight;
+
+    public static TypefaceRequest createFromTextStyle(TextStyle textStyle) {
+        return new TypefaceRequest(textStyle.fontName, textStyle.weight);
+    }
+
+    public TypefaceRequest(String fontName, int weight) {
+        this.fontName = fontName;
+        this.weight = weight;
+    }
+
+    /**
+     * Returns a string containing a query used to load fonts.
+     * The query format is provided by the official Google Fonts documentation:
+     * https://developers.google.com/fonts/docs/android#query_format
+     */
+    public String toQuery() {
+        return String.format((Locale) null, "name=%s&weight=%d", this.fontName, this.weight);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (other == this) {
+            return true;
+        }
+
+        if (!(other instanceof TypefaceRequest)) {
+            return false;
+        }
+
+        TypefaceRequest otherRequest = (TypefaceRequest) other;
+
+        // If the queries are the same, then the requests are effectively the
+        // same as well.
+        return toQuery().equalsIgnoreCase(otherRequest.toQuery());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(toQuery());
+    }
+}
\ No newline at end of file
diff --git a/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/fonts/TypefaceResponse.java b/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/fonts/TypefaceResponse.java
new file mode 100644
index 0000000..f8677e5
--- /dev/null
+++ b/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/fonts/TypefaceResponse.java
@@ -0,0 +1,36 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.content_creation.notes.fonts;
+
+import android.graphics.Typeface;
+
+/**
+ * Response object for font loading requests which will either carry a Typeface
+ * instance or an error code.
+ */
+public class TypefaceResponse {
+    private static final int SUCCESS_REASON = -1;
+
+    public final Typeface typeface;
+    public final int reason;
+
+    public TypefaceResponse(Typeface typeface) {
+        this.typeface = typeface;
+        this.reason = SUCCESS_REASON;
+    }
+
+    public TypefaceResponse(int reason) {
+        this.typeface = null;
+        this.reason = reason;
+    }
+
+    /**
+     * Returns true if the response represents an error, false if it has a
+     * Typeface instance.
+     */
+    public boolean isError() {
+        return this.reason != SUCCESS_REASON || typeface == null;
+    }
+}
\ No newline at end of file
diff --git a/chrome/browser/devtools/protocol/devtools_protocol_browsertest.cc b/chrome/browser/devtools/protocol/devtools_protocol_browsertest.cc
index 59e0cc92..b1917e3 100644
--- a/chrome/browser/devtools/protocol/devtools_protocol_browsertest.cc
+++ b/chrome/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -6,9 +6,15 @@
 
 #include "base/base64.h"
 #include "base/bind.h"
+#include "base/path_service.h"
+#include "base/strings/string_util.h"
 #include "base/values.h"
 #include "chrome/browser/devtools/protocol/devtools_protocol_test_support.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_util.h"
+#include "chrome/browser/extensions/unpacked_installer.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/common/chrome_paths.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/navigation_entry.h"
@@ -16,6 +22,10 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
+#include "extensions/browser/extension_host.h"
+#include "extensions/browser/extension_system.h"
+#include "extensions/browser/process_manager.h"
+#include "extensions/browser/test_extension_registry_observer.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/ssl/ssl_cipher_suite_names.h"
 #include "net/ssl/ssl_connection_status_flags.h"
@@ -287,3 +297,75 @@
 
   ASSERT_FALSE(params.FindPath("visibleSecurityState.safetyTipInfo"));
 }
+
+namespace {
+
+class ExtensionProtocolTest : public DevToolsProtocolTest {
+ protected:
+  void SetUpOnMainThread() override {
+    DevToolsProtocolTest::SetUpOnMainThread();
+    Profile* profile = browser()->profile();
+    extension_service_ =
+        extensions::ExtensionSystem::Get(profile)->extension_service();
+    extension_registry_ = extensions::ExtensionRegistry::Get(profile);
+  }
+
+  content::WebContents* web_contents() override {
+    return background_web_contents_;
+  }
+
+  const extensions::Extension* LoadExtension(base::FilePath extension_path) {
+    extensions::TestExtensionRegistryObserver observer(extension_registry_);
+    extensions::UnpackedInstaller::Create(extension_service_)
+        ->Load(extension_path);
+    observer.WaitForExtensionLoaded();
+
+    std::string extension_path_str = extension_path.AsUTF8Unsafe();
+
+    const extensions::Extension* extension = nullptr;
+    for (const auto& enabled_extension :
+         extension_registry_->enabled_extensions()) {
+      if (base::EndsWith(enabled_extension->path().AsUTF8Unsafe(),
+                         extension_path_str)) {
+        extension = enabled_extension.get();
+        break;
+      }
+    }
+    auto* process_manager =
+        extensions::ProcessManager::Get(browser()->profile());
+    extensions::ExtensionHost* host =
+        process_manager->GetBackgroundHostForExtension(extension->id());
+    background_web_contents_ = host->host_contents();
+    return extension;
+  }
+
+  void ReloadExtension(const std::string extension_id) {
+    extensions::TestExtensionRegistryObserver observer(extension_registry_);
+    extension_service_->ReloadExtension(extension_id);
+    observer.WaitForExtensionLoaded();
+  }
+
+ private:
+  extensions::ExtensionService* extension_service_;
+  extensions::ExtensionRegistry* extension_registry_;
+  content::WebContents* background_web_contents_;
+};
+
+}  // namespace
+
+IN_PROC_BROWSER_TEST_F(ExtensionProtocolTest, ReloadTracedExtension) {
+  base::FilePath extension_path =
+      base::PathService::CheckedGet(chrome::DIR_TEST_DATA)
+          .AppendASCII("devtools")
+          .AppendASCII("extensions")
+          .AppendASCII("simple_background_page");
+  auto* extension = LoadExtension(extension_path);
+  ASSERT_TRUE(extension);
+  Attach();
+  ReloadExtension(extension->id());
+  base::DictionaryValue params;
+  params.SetStringPath("categories", "-*");
+  SendCommandSync("Tracing.start", std::move(params));
+  SendCommand("Tracing.end");
+  base::Value tracing_complete = WaitForNotification("Tracing.tracingComplete");
+}
diff --git a/chrome/browser/devtools/protocol/devtools_protocol_test_support.h b/chrome/browser/devtools/protocol/devtools_protocol_test_support.h
index af1bcfe4..e8ccb6a 100644
--- a/chrome/browser/devtools/protocol/devtools_protocol_test_support.h
+++ b/chrome/browser/devtools/protocol/devtools_protocol_test_support.h
@@ -54,7 +54,7 @@
   void Attach();
   void Detach();
 
-  content::WebContents* web_contents();
+  virtual content::WebContents* web_contents();
 
   base::Value WaitForNotification(const std::string& notification);
   base::Value WaitForMatchingNotification(const std::string& notification,
diff --git a/chrome/browser/dom_distiller/tab_utils_browsertest.cc b/chrome/browser/dom_distiller/tab_utils_browsertest.cc
index ff8e1060..a12d9e0 100644
--- a/chrome/browser/dom_distiller/tab_utils_browsertest.cc
+++ b/chrome/browser/dom_distiller/tab_utils_browsertest.cc
@@ -8,6 +8,7 @@
 
 #include "base/command_line.h"
 #include "base/run_loop.h"
+#include "base/scoped_observation.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
@@ -86,7 +87,7 @@
 class FaviconUpdateWaiter : public favicon::FaviconDriverObserver {
  public:
   explicit FaviconUpdateWaiter(content::WebContents* web_contents) {
-    scoped_observer_.Add(
+    scoped_observation_.Observe(
         favicon::ContentFaviconDriver::FromWebContents(web_contents));
   }
   ~FaviconUpdateWaiter() override = default;
@@ -100,7 +101,7 @@
     run_loop.Run();
   }
 
-  void StopObserving() { scoped_observer_.RemoveAll(); }
+  void StopObserving() { scoped_observation_.Reset(); }
 
  private:
   void OnFaviconUpdated(favicon::FaviconDriver* favicon_driver,
@@ -114,8 +115,9 @@
   }
 
   bool updated_ = false;
-  ScopedObserver<favicon::FaviconDriver, favicon::FaviconDriverObserver>
-      scoped_observer_{this};
+  base::ScopedObservation<favicon::FaviconDriver,
+                          favicon::FaviconDriverObserver>
+      scoped_observation_{this};
   base::OnceClosure quit_closure_;
 
   DISALLOW_COPY_AND_ASSIGN(FaviconUpdateWaiter);
diff --git a/chrome/browser/download/android/BUILD.gn b/chrome/browser/download/android/BUILD.gn
index 0ffe43a1..79395771 100644
--- a/chrome/browser/download/android/BUILD.gn
+++ b/chrome/browser/download/android/BUILD.gn
@@ -135,7 +135,9 @@
 android_library("download_java_tests") {
   testonly = true
 
+  # TODO(xingliu): Move tests in javatests/ into java/.
   sources = [
+    "java/src/org/chromium/chrome/browser/download/settings/DownloadSettingsTest.java",
     "javatests/src/org/chromium/chrome/browser/download/DownloadFileProviderTest.java",
     "javatests/src/org/chromium/chrome/browser/download/MimeUtilsTest.java",
     "javatests/src/org/chromium/chrome/browser/download/StringUtilsTest.java",
@@ -146,11 +148,17 @@
     ":java",
     "//base:base_java",
     "//base:base_java_test_support",
+    "//chrome/android:chrome_java",
     "//chrome/browser/flags:java",
+    "//chrome/browser/settings:test_support_java",
     "//chrome/test/android:chrome_java_test_support",
     "//components/browser_ui/util/android:java",
     "//components/offline_items_collection/core:core_java",
+    "//content/public/test/android:content_java_test_support",
+    "//third_party/android_deps:espresso_java",
     "//third_party/android_support_test_runner:runner_java",
+    "//third_party/androidx:androidx_annotation_annotation_java",
+    "//third_party/androidx:androidx_preference_preference_java",
     "//third_party/androidx:androidx_test_runner_java",
     "//third_party/junit",
     "//third_party/mockito:mockito_java",
diff --git a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/settings/DownloadSettings.java b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/settings/DownloadSettings.java
index 5c1d23c..afca352 100644
--- a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/settings/DownloadSettings.java
+++ b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/settings/DownloadSettings.java
@@ -29,11 +29,10 @@
  */
 public class DownloadSettings
         extends PreferenceFragmentCompat implements Preference.OnPreferenceChangeListener {
-    public static final String PREF_LOCATION_CHANGE = "location_change";
-    private static final String PREF_DOWNLOAD_LATER_PROMPT_ENABLED =
-            "download_later_prompt_enabled";
-    private static final String PREF_LOCATION_PROMPT_ENABLED = "location_prompt_enabled";
-    private static final String PREF_PREFETCHING_ENABLED = "prefetching_enabled";
+    static final String PREF_LOCATION_CHANGE = "location_change";
+    static final String PREF_DOWNLOAD_LATER_PROMPT_ENABLED = "download_later_prompt_enabled";
+    static final String PREF_LOCATION_PROMPT_ENABLED = "location_prompt_enabled";
+    static final String PREF_PREFETCHING_ENABLED = "prefetching_enabled";
 
     private PrefService mPrefService;
     private DownloadLocationPreference mLocationChangePref;
diff --git a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/settings/DownloadSettingsTest.java b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/settings/DownloadSettingsTest.java
new file mode 100644
index 0000000..8ef1204
--- /dev/null
+++ b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/settings/DownloadSettingsTest.java
@@ -0,0 +1,71 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.download.settings;
+
+import androidx.preference.Preference;
+import androidx.test.filters.MediumTest;
+
+import org.hamcrest.Matcher;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.util.Criteria;
+import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.base.test.util.Matchers;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.settings.SettingsActivityTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
+import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
+import org.chromium.content_public.browser.test.util.TestThreadUtils;
+
+/**
+ * Test for download settings.
+ */
+@RunWith(ChromeJUnit4ClassRunner.class)
+public class DownloadSettingsTest {
+    @Rule
+    public final SettingsActivityTestRule<DownloadSettings> mSettingsActivityTestRule =
+            new SettingsActivityTestRule<>(DownloadSettings.class);
+
+    private Preference assertPreference(final String preferenceKey) throws Exception {
+        return assertPreference(preferenceKey, Matchers.notNullValue());
+    }
+
+    private Preference assertPreference(final String preferenceKey, Matcher<Object> matcher)
+            throws Exception {
+        DownloadSettings downloadSettings = mSettingsActivityTestRule.getFragment();
+        CriteriaHelper.pollUiThread(() -> {
+            Criteria.checkThat("Expected valid preference for: " + preferenceKey,
+                    downloadSettings.findPreference(preferenceKey), matcher);
+        });
+
+        return TestThreadUtils.runOnUiThreadBlocking(
+                () -> downloadSettings.findPreference(preferenceKey));
+    }
+
+    @Test
+    @MediumTest
+    @EnableFeatures(ChromeFeatureList.DOWNLOAD_LATER)
+    public void testGeneralSettings() throws Exception {
+        mSettingsActivityTestRule.startSettingsActivity();
+        assertPreference(DownloadSettings.PREF_LOCATION_CHANGE);
+        assertPreference(DownloadSettings.PREF_LOCATION_PROMPT_ENABLED);
+        assertPreference(DownloadSettings.PREF_DOWNLOAD_LATER_PROMPT_ENABLED);
+        assertPreference(DownloadSettings.PREF_PREFETCHING_ENABLED);
+    }
+
+    @Test
+    @MediumTest
+    @DisableFeatures(ChromeFeatureList.DOWNLOAD_LATER)
+    public void testWithoutDownloadLater() throws Exception {
+        mSettingsActivityTestRule.startSettingsActivity();
+        assertPreference(DownloadSettings.PREF_LOCATION_CHANGE);
+        assertPreference(DownloadSettings.PREF_LOCATION_PROMPT_ENABLED);
+        assertPreference(DownloadSettings.PREF_DOWNLOAD_LATER_PROMPT_ENABLED, Matchers.nullValue());
+        assertPreference(DownloadSettings.PREF_PREFETCHING_ENABLED);
+    }
+}
diff --git a/chrome/browser/extensions/activity_log/activity_log_unittest.cc b/chrome/browser/extensions/activity_log/activity_log_unittest.cc
index aedc2f0..d0e9695ff 100644
--- a/chrome/browser/extensions/activity_log/activity_log_unittest.cc
+++ b/chrome/browser/extensions/activity_log/activity_log_unittest.cc
@@ -109,8 +109,7 @@
                                     int tab_id,
                                     bool update_origin_whitelist) override {}
   void UpdateUserScripts(base::ReadOnlySharedMemoryRegion shared_memory,
-                         mojom::HostIDPtr host_id,
-                         bool allowlisted_only) override {}
+                         mojom::HostIDPtr host_id) override {}
   void ClearTabSpecificPermissions(
       const std::vector<std::string>& extension_ids,
       int tab_id,
diff --git a/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker_unittest.cc b/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker_unittest.cc
index e5c1315..a4382679 100644
--- a/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker_unittest.cc
+++ b/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker_unittest.cc
@@ -89,8 +89,7 @@
                                     int tab_id,
                                     bool update_origin_allowlist) override {}
   void UpdateUserScripts(base::ReadOnlySharedMemoryRegion shared_memory,
-                         mojom::HostIDPtr host_id,
-                         bool allowlisted_only) override {}
+                         mojom::HostIDPtr host_id) override {}
   void ClearTabSpecificPermissions(
       const std::vector<std::string>& extension_ids,
       int tab_id,
diff --git a/chrome/browser/extensions/extension_context_menu_browsertest.cc b/chrome/browser/extensions/extension_context_menu_browsertest.cc
index 064bfae..c1d94013 100644
--- a/chrome/browser/extensions/extension_context_menu_browsertest.cc
+++ b/chrome/browser/extensions/extension_context_menu_browsertest.cc
@@ -635,6 +635,9 @@
   //   Ze Extension with multiple Context Menus
   //     Context Menu #1
   //     Context Menu #2
+  // TODO(crbug.com/1208359): Service Worker version is very flaky.
+  if (GetParam() == ContextType::kServiceWorker)
+    return;
 
   // Load extensions and wait until it's created a single menu item.
   ExtensionTestMessageListener listener1("created item", false);
diff --git a/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc b/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc
index 72038dd..2c093763 100644
--- a/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc
+++ b/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc
@@ -70,7 +70,6 @@
 #include "chrome/browser/ash/login/users/scoped_test_user_manager.h"
 #include "chrome/browser/ash/settings/scoped_cros_settings_test_helper.h"
 #include "chromeos/dbus/concierge/concierge_client.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #endif
 
 namespace extensions {
@@ -264,10 +263,6 @@
     // This is needed to create extension service under CrOS.
 #if BUILDFLAG(IS_CHROMEOS_ASH)
     test_user_manager_ = std::make_unique<ash::ScopedTestUserManager>();
-    // Creating a DBus thread manager setter has the side effect of
-    // creating a DBusThreadManager, which is needed for testing.
-    // We don't actually need the setter so we ignore the return value.
-    chromeos::DBusThreadManager::GetSetterForTesting();
     chromeos::ConciergeClient::InitializeFake(/*fake_cicerone_client=*/nullptr);
 #endif
 
diff --git a/chrome/browser/federated_learning/floc_eligibility_browsertest.cc b/chrome/browser/federated_learning/floc_eligibility_browsertest.cc
index 230aa9f..55632121 100644
--- a/chrome/browser/federated_learning/floc_eligibility_browsertest.cc
+++ b/chrome/browser/federated_learning/floc_eligibility_browsertest.cc
@@ -472,6 +472,39 @@
           .ExtractString());
 }
 
+class FlocEligibilityBrowserTestBypassIPIsPubliclyRoutableCheck
+    : public FlocEligibilityBrowserTest {
+ public:
+  FlocEligibilityBrowserTestBypassIPIsPubliclyRoutableCheck() {
+    scoped_feature_list_.Reset();
+    scoped_feature_list_.InitWithFeatures(
+        /*enabled_features=*/{blink::features::kInterestCohortFeaturePolicy,
+                              federated_learning::
+                                  kFlocBypassIPIsPubliclyRoutableCheck},
+        /*disabled_features=*/{
+            federated_learning::
+                kFlocPagesWithAdResourcesDefaultIncludedInFlocComputation});
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(
+    FlocEligibilityBrowserTestBypassIPIsPubliclyRoutableCheck,
+    EligibleForHistoryOnPrivateIP) {
+  GURL main_page_url = https_server_.GetURL(
+      "a.test", "/federated_learning/page_with_script_and_iframe.html");
+
+  // Three resources in the main frame and one favicon.
+  NavigateAndWaitForResourcesCompeletion(main_page_url, 4);
+
+  InvokeInterestCohortJsApi(web_contents());
+
+  // Expect that the navigation history is eligible for floc computation.
+  base::Optional<bool> query_floc_eligible =
+      QueryFlocEligibleForURL(main_page_url);
+  EXPECT_TRUE(query_floc_eligible);
+  EXPECT_TRUE(query_floc_eligible.value());
+}
+
 class FlocEligibilityBrowserTestPagesWithAdResourcesDefaultIncluded
     : public FlocEligibilityBrowserTest {
  public:
diff --git a/chrome/browser/federated_learning/floc_eligibility_observer.cc b/chrome/browser/federated_learning/floc_eligibility_observer.cc
index 297f61d..c55c9d41 100644
--- a/chrome/browser/federated_learning/floc_eligibility_observer.cc
+++ b/chrome/browser/federated_learning/floc_eligibility_observer.cc
@@ -48,8 +48,10 @@
 
   // If the IP was not publicly routable, the navigation history is not eligible
   // for floc. We can stop observing now.
-  if (!navigation_handle->GetSocketAddress().address().IsPubliclyRoutable())
+  if (!navigation_handle->GetSocketAddress().address().IsPubliclyRoutable() &&
+      !base::FeatureList::IsEnabled(kFlocBypassIPIsPubliclyRoutableCheck)) {
     return ObservePolicy::STOP_OBSERVING;
+  }
 
   // If the interest-cohort permissions policy in the main document disallows
   // the floc inclusion, the navigation history is not eligible for floc. We can
diff --git a/chrome/browser/federated_learning/floc_eligibility_unittest.cc b/chrome/browser/federated_learning/floc_eligibility_unittest.cc
index d49df8f..1b7e0dc 100644
--- a/chrome/browser/federated_learning/floc_eligibility_unittest.cc
+++ b/chrome/browser/federated_learning/floc_eligibility_unittest.cc
@@ -203,6 +203,27 @@
   EXPECT_FALSE(IsUrlVisitEligibleToComputeFloc(url));
 }
 
+class FlocEligibilityUnitTestkBypassIPIsPubliclyRoutableCheck
+    : public FlocEligibilityUnitTest {
+ public:
+  FlocEligibilityUnitTestkBypassIPIsPubliclyRoutableCheck() {
+    feature_list_.InitAndEnableFeature(kFlocBypassIPIsPubliclyRoutableCheck);
+  }
+
+ protected:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+TEST_F(FlocEligibilityUnitTestkBypassIPIsPubliclyRoutableCheck,
+       ContinueObservingPrivateIP) {
+  GURL url("https://foo.com");
+  NavigateToPage(url, /*publicly_routable=*/false,
+                 /*floc_permissions_policy_enabled=*/true);
+
+  GetFlocEligibilityObserver()->OnInterestCohortApiUsed();
+  EXPECT_TRUE(IsUrlVisitEligibleToComputeFloc(url));
+}
+
 class FlocEligibilityUnitTestPagesWithAdResourcesDefaultIncluded
     : public FlocEligibilityUnitTest {
  public:
diff --git a/chrome/browser/feed/android/java/res/layout/feed_management_activity.xml b/chrome/browser/feed/android/java/res/layout/feed_management_activity.xml
index e504795..b3da0a8 100644
--- a/chrome/browser/feed/android/java/res/layout/feed_management_activity.xml
+++ b/chrome/browser/feed/android/java/res/layout/feed_management_activity.xml
@@ -20,6 +20,7 @@
       android:layout_height="@dimen/feed_management_header_height"
       tools:ignore="UseCompoundDrawables" >
       <ImageView
+          android:id="@+id/feed_management_back_arrow"
           android:layout_width="@dimen/follow_arrow_size"
           android:layout_height="@dimen/follow_arrow_size"
           android:layout_margin="@dimen/follow_margin"
diff --git a/chrome/browser/feed/android/java/res/layout/follow_management_activity.xml b/chrome/browser/feed/android/java/res/layout/follow_management_activity.xml
index ea6d34b4..b101dad 100644
--- a/chrome/browser/feed/android/java/res/layout/follow_management_activity.xml
+++ b/chrome/browser/feed/android/java/res/layout/follow_management_activity.xml
@@ -19,7 +19,8 @@
       android:layout_width="match_parent"
       android:layout_height="@dimen/feed_management_header_height"
       tools:ignore="UseCompoundDrawables" >
-      <ImageView
+    <ImageView
+          android:id="@+id/follow_management_back_arrow"
           android:layout_width="@dimen/follow_arrow_size"
           android:layout_height="@dimen/follow_arrow_size"
           android:layout_margin="@dimen/follow_margin"
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/feedmanagement/FeedManagementCoordinator.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/feedmanagement/FeedManagementCoordinator.java
index 737b179..37cab95 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/feedmanagement/FeedManagementCoordinator.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/feedmanagement/FeedManagementCoordinator.java
@@ -7,8 +7,8 @@
 import android.app.Activity;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.widget.ImageView;
 import android.widget.ListView;
-import android.widget.TextView;
 
 import org.chromium.chrome.browser.feed.feedmanagement.FeedManagementMediator.FollowManagementLauncher;
 import org.chromium.chrome.browser.feed.webfeed.R;
@@ -41,8 +41,8 @@
         listView.setAdapter(adapter);
 
         // Set up a handler for the header to act as a back button.
-        TextView headerView = (TextView) mView.findViewById(R.id.feed_management_page_title);
-        headerView.setOnClickListener(this::handleHeaderClick);
+        ImageView backArrowView = (ImageView) mView.findViewById(R.id.feed_management_back_arrow);
+        backArrowView.setOnClickListener(this::handleBackArrowClick);
 
         mMediator = new FeedManagementMediator(mActivity, listItems, followManagementLauncher);
     }
@@ -51,7 +51,7 @@
         return mView;
     }
 
-    private void handleHeaderClick(View view) {
+    private void handleBackArrowClick(View view) {
         // Navigate back.
         mActivity.finish();
     }
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/followmanagement/FollowManagementCoordinator.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/followmanagement/FollowManagementCoordinator.java
index 4f258cd2..f7d02d24 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/followmanagement/FollowManagementCoordinator.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/followmanagement/FollowManagementCoordinator.java
@@ -7,7 +7,7 @@
 import android.app.Activity;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.widget.TextView;
+import android.widget.ImageView;
 
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
@@ -45,8 +45,8 @@
         recyclerView.setAdapter(adapter);
 
         // Set up a handler for the header to act as a back button.
-        TextView headerView = (TextView) mView.findViewById(R.id.follow_management_page_title);
-        headerView.setOnClickListener(this::handleHeaderClick);
+        ImageView backArrowView = (ImageView) mView.findViewById(R.id.follow_management_back_arrow);
+        backArrowView.setOnClickListener(this::handleBackArrowClick);
 
         mMediator = new FollowManagementMediator(activity, listItems, adapter,
                 new LargeIconBridge(Profile.getLastUsedRegularProfile()));
@@ -56,7 +56,7 @@
         return mView;
     }
 
-    private void handleHeaderClick(View view) {
+    private void handleBackArrowClick(View view) {
         // Navigate back.
         mActivity.finish();
     }
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedFollowIntroView.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedFollowIntroView.java
index 9be0b9b..e0ab81e 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedFollowIntroView.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedFollowIntroView.java
@@ -96,7 +96,7 @@
         TextBubble followingBubble = new TextBubble(mActivity, mMenuButtonAnchorView,
                 R.string.menu_following, R.string.menu_following, /*showArrow=*/false,
                 createRectProvider(), R.drawable.ic_done_blue, /*isRoundBubble=*/true,
-                /*inverseColor=*/true, ChromeAccessibilityUtil.get().isAccessibilityEnabled());
+                /*inverseColor=*/false, ChromeAccessibilityUtil.get().isAccessibilityEnabled());
         followingBubble.setDismissOnTouchInteraction(true);
         followingBubble.show();
     }
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 6f2661ae..cbf568a 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1649,6 +1649,11 @@
     "expiry_milestone": 98
   },
   {
+    "name": "enable-desktop-pwas-prefix-app-name-in-window-title",
+    "owners": [ "dmurph@chromium.org", "desktop-pwas-team@google.com" ],
+    "expiry_milestone": 98
+  },
+  {
     "name": "enable-desktop-pwas-protocol-handling",
     "owners": [ "samtan@microsoft.com", "desktop-pwas-team@google.com" ],
     "expiry_milestone": 95
@@ -4731,11 +4736,6 @@
     "expiry_milestone": 87
   },
   {
-    "name": "sharing-qr-code-generator",
-    "owners": [ "//components/send_tab_to_self/OWNERS" ],
-    "expiry_milestone": 90
-  },
-  {
     "name": "sharing-send-via-sync",
     "owners": [ "//chrome/browser/sharing/OWNERS" ],
     "expiry_milestone": 86
@@ -4824,16 +4824,6 @@
     "expiry_milestone": 100
   },
   {
-    "name": "smart-dim-model-v3",
-    "owners": [ "alanlxl", "amoylan", "jiameng" ],
-    "expiry_milestone": 90
-  },
-  {
-    "name": "smart-dim-new-ml-agent",
-    "owners": [ "alanlxl", "amoylan" ],
-    "expiry_milestone": 90
-  },
-  {
     "name": "smart-suggestion-for-large-downloads",
     "owners": [ "shaktisahu" ],
     "expiry_milestone": 93
@@ -4961,11 +4951,6 @@
     "expiry_milestone": 92
   },
   {
-    "name": "textfield-focus-on-tap-up",
-    "owners": [ "collinbaker" ],
-    "expiry_milestone": 86
-  },
-  {
     "name": "texture-layer-skip-wait-for-activation",
     "owners": [ "fserb@chromium.org", "aaronhk@chromium.org" ],
     "expiry_milestone": 90
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index b6cef0f..b4ec18f 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -708,6 +708,12 @@
     "Enable a different approach to saving data by configuring the back end "
     "server";
 
+const char kDesktopPWAsPrefixAppNameInWindowTitleName[] =
+    "Desktop PWAs prefix window title with app name.";
+const char kDesktopPWAsPrefixAppNameInWindowTitleDescription[] =
+    "Prefix the window title of installed PWAs with the name of the PWA. On "
+    "ChromeOS this is visible only in the window/activity switcher.";
+
 const char kDesktopPWAsAppIconShortcutsMenuName[] =
     "Desktop PWAs app icon shortcuts menu";
 const char kDesktopPWAsAppIconShortcutsMenuDescription[] =
@@ -2240,10 +2246,6 @@
 const char kSharingPreferVapidDescription[] =
     "Prefer sending Sharing message via FCM WebPush authenticated using VAPID.";
 
-const char kSharingQRCodeGeneratorName[] = "Enable sharing page via QR Code";
-const char kSharingQRCodeGeneratorDescription[] =
-    "Enables right-click UI to share the page's URL via a generated QR Code.";
-
 const char kSharingSendViaSyncName[] =
     "Enable sending Sharing message via Sync";
 const char kSharingSendViaSyncDescription[] =
@@ -4953,11 +4955,6 @@
     "InstallableInkDrop is part of an InkDrop refactoring effort. This enables "
     "the pilot implementation where available.";
 
-const char kTextfieldFocusOnTapUpName[] = "Focus UI text fields on touch-up";
-const char kTextfieldFocusOnTapUpDescription[] =
-    "When enabled, Views-based text fields take focus on touch-up instead of "
-    "touch-down. This includes the Omnibox.";
-
 #endif  // defined(TOOLKIT_VIEWS)
 
 // Random platform combinations -----------------------------------------------
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 5f227f9..b09e988a 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -450,6 +450,9 @@
 extern const char kDesktopPWAsAttentionBadgingCrOSApiOnly[];
 extern const char kDesktopPWAsAttentionBadgingCrOSNotificationsOnly[];
 
+extern const char kDesktopPWAsPrefixAppNameInWindowTitleName[];
+extern const char kDesktopPWAsPrefixAppNameInWindowTitleDescription[];
+
 extern const char kDesktopPWAsRemoveStatusBarName[];
 extern const char kDesktopPWAsRemoveStatusBarDescription[];
 
@@ -1296,9 +1299,6 @@
 extern const char kSharingPreferVapidName[];
 extern const char kSharingPreferVapidDescription[];
 
-extern const char kSharingQRCodeGeneratorName[];
-extern const char kSharingQRCodeGeneratorDescription[];
-
 extern const char kSharingSendViaSyncName[];
 extern const char kSharingSendViaSyncDescription[];
 
@@ -2894,9 +2894,6 @@
 extern const char kInstallableInkDropName[];
 extern const char kInstallableInkDropDescription[];
 
-extern const char kTextfieldFocusOnTapUpName[];
-extern const char kTextfieldFocusOnTapUpDescription[];
-
 #endif  // defined(TOOLKIT_VIEWS)
 
 // Random platform combinations -----------------------------------------------
diff --git a/chrome/browser/gcm/gcm_profile_service_unittest.cc b/chrome/browser/gcm/gcm_profile_service_unittest.cc
index 338a8977..cd120f2 100644
--- a/chrome/browser/gcm/gcm_profile_service_unittest.cc
+++ b/chrome/browser/gcm/gcm_profile_service_unittest.cc
@@ -41,7 +41,6 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chromeos/dbus/concierge/concierge_client.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #endif
 
 namespace gcm {
@@ -163,9 +162,6 @@
 
 void GCMProfileServiceTest::SetUp() {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  // Create a DBus thread manager setter for its side effect.
-  // Ignore the return value.
-  chromeos::DBusThreadManager::GetSetterForTesting();
   chromeos::ConciergeClient::InitializeFake(/*fake_cicerone_client=*/nullptr);
 #endif
   TestingProfile::Builder builder;
diff --git a/chrome/browser/history/history_tab_helper.cc b/chrome/browser/history/history_tab_helper.cc
index cf7c3050..6d65d6892 100644
--- a/chrome/browser/history/history_tab_helper.cc
+++ b/chrome/browser/history/history_tab_helper.cc
@@ -26,18 +26,54 @@
 
 #if defined(OS_ANDROID)
 #include "chrome/browser/android/background_tab_manager.h"
-#include "components/feed/feed_feature_list.h"
+#include "chrome/browser/android/feed/v2/feed_service_factory.h"
+#include "components/feed/core/v2/public/feed_api.h"
+#include "components/feed/core/v2/public/feed_service.h"
 #else
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #endif
 
+namespace {
+
+using content::NavigationEntry;
+using content::WebContents;
 #if defined(OS_ANDROID)
 using chrome::android::BackgroundTabManager;
 #endif
 
-using content::NavigationEntry;
-using content::WebContents;
+#if defined(OS_ANDROID)
+bool IsNavigationFromFeed(content::WebContents& web_contents, const GURL& url) {
+  feed::FeedService* feed_service =
+      feed::FeedServiceFactory::GetForBrowserContext(
+          web_contents.GetBrowserContext());
+  if (!feed_service)
+    return false;
+
+  return feed_service->GetStream()->WasUrlRecentlyNavigatedFromFeed(url);
+}
+
+#endif
+
+bool ShouldConsiderForNtpMostVisited(
+    content::WebContents& web_contents,
+    content::NavigationHandle* navigation_handle) {
+#if defined(OS_ANDROID)
+  // Clicks on content suggestions on the NTP should not contribute to the
+  // Most Visited tiles in the NTP.
+  DCHECK(!navigation_handle->GetRedirectChain().empty());
+  if (ui::PageTransitionCoreTypeIs(navigation_handle->GetPageTransition(),
+                                   ui::PAGE_TRANSITION_AUTO_BOOKMARK) &&
+      IsNavigationFromFeed(web_contents,
+                           navigation_handle->GetRedirectChain()[0])) {
+    return false;
+  }
+#endif
+
+  return true;
+}
+
+}  // namespace
 
 HistoryTabHelper::HistoryTabHelper(WebContents* web_contents)
     : content::WebContentsObserver(web_contents) {}
@@ -57,17 +93,6 @@
     int nav_entry_id,
     content::NavigationHandle* navigation_handle) {
   ui::PageTransition page_transition = navigation_handle->GetPageTransition();
-#if defined(OS_ANDROID)
-  // Clicks on content suggestions on the NTP should not contribute to the
-  // Most Visited tiles in the NTP.
-  const GURL& referrer_url = navigation_handle->GetReferrer().url;
-  const bool content_suggestions_navigation =
-      referrer_url == feed::GetFeedReferrerUrl() &&
-      ui::PageTransitionCoreTypeIs(page_transition,
-                                   ui::PAGE_TRANSITION_AUTO_BOOKMARK);
-#else
-  const bool content_suggestions_navigation = false;
-#endif
 
   const bool status_code_is_error =
       navigation_handle->GetResponseHeaders() &&
@@ -104,7 +129,8 @@
       navigation_handle->GetReferrer().url,
       navigation_handle->GetRedirectChain(), page_transition, hidden,
       history::SOURCE_BROWSED, navigation_handle->DidReplaceEntry(),
-      !content_suggestions_navigation, /*floc_allowed=*/false,
+      ShouldConsiderForNtpMostVisited(*web_contents(), navigation_handle),
+      /*floc_allowed=*/false,
       navigation_handle->IsSameDocument()
           ? base::Optional<std::u16string>(
                 navigation_handle->GetWebContents()->GetTitle())
diff --git a/chrome/browser/history/history_tab_helper_unittest.cc b/chrome/browser/history/history_tab_helper_unittest.cc
index d21296e..cd77784c 100644
--- a/chrome/browser/history/history_tab_helper_unittest.cc
+++ b/chrome/browser/history/history_tab_helper_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "base/test/bind.h"
+#include "build/build_config.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
@@ -16,13 +17,29 @@
 #include "components/history/core/browser/history_service.h"
 #include "components/history/core/browser/history_types.h"
 #include "components/history/core/browser/url_row.h"
+#include "content/public/browser/browser_context.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/web_contents_tester.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/page_transition_types.h"
+
+#if defined(OS_ANDROID)
+#include "chrome/browser/android/feed/v2/feed_service_factory.h"
+#include "components/feed/core/v2/public/feed_service.h"
+#include "components/feed/core/v2/public/test/stub_feed_api.h"
+#endif
 
 namespace {
 
+#if defined(OS_ANDROID)
+class TestFeedApi : public feed::StubFeedApi {
+ public:
+  MOCK_METHOD1(WasUrlRecentlyNavigatedFromFeed, bool(const GURL&));
+};
+#endif
+
 class HistoryTabHelperTest : public ChromeRenderViewHostTestHarness {
  protected:
   HistoryTabHelperTest() {}
@@ -30,6 +47,15 @@
   // ChromeRenderViewHostTestHarness:
   void SetUp() override {
     ChromeRenderViewHostTestHarness::SetUp();
+#if defined(OS_ANDROID)
+    feed::FeedServiceFactory::GetInstance()->SetTestingFactory(
+        profile(),
+        base::BindLambdaForTesting([&](content::BrowserContext* context) {
+          std::unique_ptr<KeyedService> result =
+              feed::FeedService::CreateForTesting(&test_feed_api_);
+          return result;
+        }));
+#endif
     ASSERT_TRUE(profile()->CreateHistoryService());
     history_service_ = HistoryServiceFactory::GetForProfile(
         profile(), ServiceAccessType::IMPLICIT_ACCESS);
@@ -66,11 +92,37 @@
     return title;
   }
 
+  history::MostVisitedURLList QueryMostVisitedURLs() {
+    history::MostVisitedURLList result;
+    std::string title;
+    base::RunLoop loop;
+    history_service_->QueryMostVisitedURLs(
+        /*result_count=*/10, /*days_back=*/1,
+        base::BindLambdaForTesting([&](history::MostVisitedURLList v) {
+          result = v;
+          loop.Quit();
+        }),
+        &tracker_);
+    loop.Run();
+    return result;
+  }
+
+  std::set<GURL> GetMostVisistedURLSet() {
+    std::set<GURL> result;
+    for (const history::MostVisitedURL& mv_url : QueryMostVisitedURLs()) {
+      result.insert(mv_url.url);
+    }
+    return result;
+  }
+
   const GURL page_url_ = GURL("http://foo.com");
 
- private:
+ protected:
   base::CancelableTaskTracker tracker_;
   history::HistoryService* history_service_;
+#if defined(OS_ANDROID)
+  TestFeedApi test_feed_api_;
+#endif
 
   DISALLOW_COPY_AND_ASSIGN(HistoryTabHelperTest);
 };
@@ -107,4 +159,30 @@
   EXPECT_EQ("title10", QueryPageTitleFromHistory(page_url_));
 }
 
+#if defined(OS_ANDROID)
+
+TEST_F(HistoryTabHelperTest, NonFeedNavigationsDoContributeToMostVisited) {
+  GURL new_url("http://newurl.com");
+
+  EXPECT_CALL(test_feed_api_, WasUrlRecentlyNavigatedFromFeed(new_url))
+      .WillOnce(testing::Return(false));
+  web_contents_tester()->NavigateAndCommit(new_url,
+                                           ui::PAGE_TRANSITION_AUTO_BOOKMARK);
+
+  EXPECT_THAT(GetMostVisistedURLSet(), testing::Contains(new_url));
+}
+
+TEST_F(HistoryTabHelperTest, FeedNavigationsDoNotContributeToMostVisited) {
+  GURL new_url("http://newurl.com");
+  EXPECT_CALL(test_feed_api_, WasUrlRecentlyNavigatedFromFeed(new_url))
+      .WillOnce(testing::Return(true));
+  web_contents_tester()->NavigateAndCommit(new_url,
+                                           ui::PAGE_TRANSITION_AUTO_BOOKMARK);
+
+  EXPECT_THAT(GetMostVisistedURLSet(),
+              testing::Not(testing::Contains(new_url)));
+}
+
+#endif
+
 }  // namespace
diff --git a/chrome/browser/lacros/holding_space_service_lacros_browsertest.cc b/chrome/browser/lacros/holding_space_service_lacros_browsertest.cc
index b6a4686c..8d3beb8 100644
--- a/chrome/browser/lacros/holding_space_service_lacros_browsertest.cc
+++ b/chrome/browser/lacros/holding_space_service_lacros_browsertest.cc
@@ -25,7 +25,10 @@
 class MockHoldingSpaceService : public crosapi::mojom::HoldingSpaceService {
  public:
   // crosapi::mojom::HoldingSpaceService:
-  MOCK_METHOD(void, AddPrintedPdf, (const base::FilePath&), (override));
+  MOCK_METHOD(void,
+              AddPrintedPdf,
+              (const base::FilePath& file_path, bool from_incognito_profile),
+              (override));
 };
 
 }  // namespace
@@ -71,9 +74,10 @@
 // HoldingSpaceServicePrintToPdfIntegrationBrowserTest -------------------------
 
 // Base class for tests of print-to-PDF integration with the holding space
-// service.
+// service. Parameterized by whether tests should use an incognito browser.
 class HoldingSpaceServicePrintToPdfIntegrationBrowserTest
-    : public HoldingSpaceServiceBrowserTest {
+    : public HoldingSpaceServiceBrowserTest,
+      public testing::WithParamInterface<bool> {
  public:
   // Starts a job to print an empty PDF to the specified `file_path`.
   // NOTE: This method will not return until the print job completes.
@@ -91,6 +95,9 @@
     run_loop.Run();
   }
 
+  // Returns true if the test should use an incognito browser, false otherwise.
+  bool UseIncognitoBrowser() const { return GetParam(); }
+
  private:
   // HoldingSpaceServiceBrowserTest:
   void SetUpOnMainThread() override {
@@ -102,17 +109,30 @@
       return;
 
     // Create the PDF printer handler.
+    Browser* browser = GetBrowserForPdfPrinterHandler();
     pdf_printer_handler_ = std::make_unique<printing::PdfPrinterHandler>(
-        browser()->profile(),
-        browser()->tab_strip_model()->GetActiveWebContents(),
+        browser->profile(), browser->tab_strip_model()->GetActiveWebContents(),
         /*sticky_settings=*/nullptr);
   }
 
+  Browser* GetBrowserForPdfPrinterHandler() {
+    if (!UseIncognitoBrowser())
+      return browser();
+    if (!incognito_browser_)
+      incognito_browser_ = CreateIncognitoBrowser(browser()->profile());
+    return incognito_browser_;
+  }
+
   std::unique_ptr<printing::PdfPrinterHandler> pdf_printer_handler_;
+  Browser* incognito_browser_ = nullptr;
 };
 
+INSTANTIATE_TEST_SUITE_P(All,
+                         HoldingSpaceServicePrintToPdfIntegrationBrowserTest,
+                         testing::Bool());
+
 // Verifies that print-to-PDF adds an associated item to holding space.
-IN_PROC_BROWSER_TEST_F(HoldingSpaceServicePrintToPdfIntegrationBrowserTest,
+IN_PROC_BROWSER_TEST_P(HoldingSpaceServicePrintToPdfIntegrationBrowserTest,
                        AddPrintedPdfItem) {
   // If holding space service interface is not available on this version of
   // ash-chrome, this test suite will no-op.
@@ -128,6 +148,8 @@
   // expected that this will result in an interaction with the holding space
   // `service()` to create a printed PDF item.
   base::FilePath file_path = temp_dir.GetPath().Append("foo.pdf");
-  EXPECT_CALL(service(), AddPrintedPdf(testing::Eq(file_path)));
+  EXPECT_CALL(service(), AddPrintedPdf(testing::Eq(file_path),
+                                       /*from_incognito_profile=*/testing::Eq(
+                                           UseIncognitoBrowser())));
   StartPrintToPdfAndWaitForSave(u"job_title", file_path);
 }
diff --git a/chrome/browser/language/android/BUILD.gn b/chrome/browser/language/android/BUILD.gn
index 5685e58..8decc4e 100644
--- a/chrome/browser/language/android/BUILD.gn
+++ b/chrome/browser/language/android/BUILD.gn
@@ -14,6 +14,7 @@
   deps = [
     "//base:base_java",
     "//chrome/browser/preferences:java",
+    "//components/language/android:language_bridge_java",
     "//third_party/google_android_play_core:com_google_android_play_core_java",
   ]
 }
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/DEPS b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/DEPS
new file mode 100644
index 0000000..b2d7c09522
--- /dev/null
+++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+components/language/android"
+]
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/GlobalAppLocaleController.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/GlobalAppLocaleController.java
index c7e70f2b..3ca2ea52 100644
--- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/GlobalAppLocaleController.java
+++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/GlobalAppLocaleController.java
@@ -10,6 +10,7 @@
 import android.text.TextUtils;
 
 import org.chromium.base.LocaleUtils;
+import org.chromium.components.language.AndroidLanguageMetricsBridge;
 
 import java.util.Locale;
 
@@ -96,6 +97,15 @@
     }
 
     /**
+     * Record the value of the override language if one is set. Otherwise
+     * record the empty string.
+     */
+    public void recordOverrideLangauge() {
+        String language = (mIsOverridden) ? mOverrideLanguage : "";
+        AndroidLanguageMetricsBridge.reportAppOverrideLanguage(language);
+    }
+
+    /**
      * Return the GlobalAppLocaleController singleton instance.
      * @return GlobalAppLocaleController singleton.
      */
diff --git a/chrome/browser/lens/java/src/org/chromium/chrome/browser/lens/LensController.java b/chrome/browser/lens/java/src/org/chromium/chrome/browser/lens/LensController.java
index d31aa76e..66d0a90 100644
--- a/chrome/browser/lens/java/src/org/chromium/chrome/browser/lens/LensController.java
+++ b/chrome/browser/lens/java/src/org/chromium/chrome/browser/lens/LensController.java
@@ -141,4 +141,19 @@
     public boolean isLensEnabled(@NonNull LensQueryParams lensQueryParams) {
         return mDelegate.isLensEnabled(lensQueryParams);
     }
+
+    /** Enables lens debug mode for chrome://internals/lens. */
+    public void enableDebugMode() {
+        mDelegate.enableDebugMode();
+    }
+
+    /** Disables lens debug mode for chrome://internals/lens. */
+    public void disableDebugMode() {
+        mDelegate.disableDebugMode();
+    }
+
+    /** Gets debug data to populate chrome://internals/lens. */
+    public String[][] getDebugData() {
+        return mDelegate.getDebugData();
+    }
 }
diff --git a/chrome/browser/lens/java/src/org/chromium/chrome/browser/lens/LensControllerDelegate.java b/chrome/browser/lens/java/src/org/chromium/chrome/browser/lens/LensControllerDelegate.java
index b7bc6c2..e07e0fa 100644
--- a/chrome/browser/lens/java/src/org/chromium/chrome/browser/lens/LensControllerDelegate.java
+++ b/chrome/browser/lens/java/src/org/chromium/chrome/browser/lens/LensControllerDelegate.java
@@ -95,4 +95,15 @@
     protected @StringRes int getTranslateWithGoogleLensTextResourceId() {
         return R.string.contextmenu_translate_image_with_google_lens;
     }
+
+    /** Enables lens debug mode for chrome://internals/lens. */
+    public void enableDebugMode() {}
+
+    /** Disables lens debug mode for chrome://internals/lens. */
+    public void disableDebugMode() {}
+
+    /** Gets debug data to populate chrome://internals/lens. */
+    public String[][] getDebugData() {
+        return new String[0][0];
+    }
 }
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl_unittest.cc b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl_unittest.cc
index 42671ea..df64eaa 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl_unittest.cc
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl_unittest.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h"
 
 #include "base/run_loop.h"
+#include "base/test/gmock_callback_support.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/mock_callback.h"
 #include "base/test/simple_test_clock.h"
@@ -26,7 +27,6 @@
 using cast_channel::ChannelError;
 using ::testing::_;
 using testing::ElementsAre;
-using ::testing::Invoke;
 using ::testing::Return;
 using ::testing::SaveArg;
 using ::testing::WithArgs;
@@ -101,12 +101,10 @@
   }
 
  protected:
-  void ExpectOpenSocketInternal(cast_channel::CastSocket* socket) {
+  void ExpectOpenSocket(cast_channel::CastSocket* socket) {
     EXPECT_CALL(*mock_cast_socket_service_,
-                OpenSocketInternal(socket->ip_endpoint(), _))
-        .WillOnce(Invoke([socket](const auto& ip_endpoint, auto open_cb) {
-          std::move(open_cb).Run(socket);
-        }));
+                OpenSocket_(socket->ip_endpoint(), _))
+        .WillOnce(base::test::RunOnceCallback<1>(socket));
   }
 
   static const std::vector<DiscoveryNetworkInfo> fake_ethernet_info_;
@@ -277,14 +275,12 @@
   socket.SetErrorState(cast_channel::ChannelError::NONE);
 
   // No pending sink
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint, _))
-      .Times(1);
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint, _)).Times(1);
   media_sink_service_impl_.OpenChannel(
       cast_sink, nullptr, CastMediaSinkServiceImpl::SinkSource::kMdns);
 
   // One pending sink, the same as |cast_sink|
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint, _))
-      .Times(0);
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint, _)).Times(0);
   media_sink_service_impl_.OpenChannel(
       cast_sink, nullptr, CastMediaSinkServiceImpl::SinkSource::kMdns);
 }
@@ -301,13 +297,13 @@
   std::unique_ptr<net::BackoffEntry> backoff_entry(
       new net::BackoffEntry(&media_sink_service_impl_.backoff_policy_));
   media_sink_service_impl_.retry_params_.max_retry_attempts = 3;
-  ExpectOpenSocketInternal(&socket);
+  ExpectOpenSocket(&socket);
   media_sink_service_impl_.OpenChannel(
       cast_sink, std::move(backoff_entry),
       CastMediaSinkServiceImpl::SinkSource::kMdns);
 
   socket.SetErrorState(cast_channel::ChannelError::NONE);
-  ExpectOpenSocketInternal(&socket);
+  ExpectOpenSocket(&socket);
   // Wait for 16 seconds.
   mock_time_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(16));
 }
@@ -320,10 +316,8 @@
   socket.SetIPEndpoint(ip_endpoint);
   socket.SetErrorState(cast_channel::ChannelError::CAST_SOCKET_ERROR);
 
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint, _))
-      .WillRepeatedly(Invoke([&](const auto& ip_endpoint1, auto open_cb) {
-        std::move(open_cb).Run(&socket);
-      }));
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint, _))
+      .WillRepeatedly(base::test::RunOnceCallback<1>(&socket));
   media_sink_service_impl_.OpenChannel(
       cast_sink, nullptr, CastMediaSinkServiceImpl::SinkSource::kMdns);
 
@@ -345,8 +339,8 @@
   clock.SetNow(start_time);
   media_sink_service_impl_.SetClockForTest(&clock);
 
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint1, _));
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint2, _));
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint1, _));
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint2, _));
 
   // 1st round finds service 1 & 2.
   std::vector<MediaSinkInternal> sinks1{cast_sink1, cast_sink2};
@@ -370,9 +364,9 @@
                             delta.InMilliseconds(), 1);
 
   // There is already a socket open for |ip_endpoint2|.
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint2, _))
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint2, _))
       .Times(0);
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint3, _));
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint3, _));
 
   // 2nd round finds service 2 & 3.
   std::vector<MediaSinkInternal> sinks2{cast_sink2, cast_sink3};
@@ -414,10 +408,8 @@
   clock.SetNow(start_time);
   media_sink_service_impl_.SetClockForTest(&clock);
 
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint1, _))
-      .WillRepeatedly(Invoke([&](const auto& ip_endpoint1, auto open_cb) {
-        std::move(open_cb).Run(&socket);
-      }));
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint1, _))
+      .WillRepeatedly(base::test::RunOnceCallback<1>(&socket));
   std::vector<MediaSinkInternal> sinks1 = {cast_sink1};
   media_sink_service_impl_.OpenChannels(
       sinks1, CastMediaSinkServiceImpl::SinkSource::kMdns);
@@ -432,10 +424,8 @@
   extra_data.ip_endpoint = ip_endpoint2;
   cast_sink1.set_cast_data(extra_data);
 
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint2, _))
-      .WillRepeatedly(Invoke([&](const auto& ip_endpoint1, auto open_cb) {
-        std::move(open_cb).Run(&socket);
-      }));
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint2, _))
+      .WillRepeatedly(base::test::RunOnceCallback<1>(&socket));
 
   std::vector<MediaSinkInternal> updated_sinks1 = {cast_sink1};
   media_sink_service_impl_.OpenChannels(
@@ -462,10 +452,8 @@
   clock.SetNow(start_time);
   media_sink_service_impl_.SetClockForTest(&clock);
 
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint, _))
-      .WillRepeatedly(Invoke([&](const auto& ip_endpoint, auto open_cb) {
-        std::move(open_cb).Run(&socket);
-      }));
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint, _))
+      .WillRepeatedly(base::test::RunOnceCallback<1>(&socket));
   std::vector<MediaSinkInternal> sinks = {cast_sink};
   OpenChannels(sinks, CastMediaSinkServiceImpl::SinkSource::kMdns);
 
@@ -475,7 +463,7 @@
   cast_sink.sink().set_name("Updated name");
   std::vector<MediaSinkInternal> updated_sinks = {cast_sink};
 
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(_, _)).Times(0);
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(_, _)).Times(0);
   EXPECT_CALL(observer_, OnSinkAddedOrUpdated(cast_sink));
   OpenChannels(updated_sinks, CastMediaSinkServiceImpl::SinkSource::kMdns);
 
@@ -525,10 +513,8 @@
   media_sink_service_impl_.OnChannelOpenSucceeded(
       cast_sink, &socket, CastMediaSinkServiceImpl::SinkSource::kMdns);
 
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint1, _))
-      .WillRepeatedly(Invoke([&](const auto& ip_endpoint1, auto open_cb) {
-        std::move(open_cb).Run(&socket);
-      }));
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint1, _))
+      .WillRepeatedly(base::test::RunOnceCallback<1>(&socket));
   media_sink_service_impl_.OnError(socket,
                                    cast_channel::ChannelError::PING_TIMEOUT);
 
@@ -553,10 +539,8 @@
 
   // Set the error state to indicate that opening a channel failed.
   socket.SetErrorState(ChannelError::CONNECT_ERROR);
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint1, _))
-      .WillRepeatedly(Invoke([&](const auto& ip_endpoint1, auto open_cb) {
-        std::move(open_cb).Run(&socket);
-      }));
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint1, _))
+      .WillRepeatedly(base::test::RunOnceCallback<1>(&socket));
   media_sink_service_impl_.OnError(socket,
                                    cast_channel::ChannelError::PING_TIMEOUT);
 
@@ -579,7 +563,7 @@
   // No op for CONNECTING cast channel.
   EXPECT_CALL(socket, ready_state())
       .WillOnce(Return(cast_channel::ReadyState::CONNECTING));
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(_, _)).Times(0);
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(_, _)).Times(0);
 
   base::HistogramTester tester;
   media_sink_service_impl_.OnError(
@@ -601,7 +585,7 @@
   media_sink_service_impl_.OnError(
       socket, cast_channel::ChannelError::CHANNEL_NOT_OPEN);
 
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint1, _))
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint1, _))
       .Times(0);
   mock_time_task_runner_->FastForwardUntilNoTasksRemain();
 }
@@ -625,18 +609,10 @@
   socket2.SetAudioOnly(true);
 
   // Channel 1, 2 opened.
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint1, _))
-      .WillOnce(WithArgs<1>(
-          [&socket1](const base::RepeatingCallback<void(
-                         cast_channel::CastSocket * socket)>& callback) {
-            callback.Run(&socket1);
-          }));
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint2, _))
-      .WillOnce(WithArgs<1>(
-          [&socket2](const base::RepeatingCallback<void(
-                         cast_channel::CastSocket * socket)>& callback) {
-            callback.Run(&socket2);
-          }));
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint1, _))
+      .WillOnce(base::test::RunOnceCallback<1>(&socket1));
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint2, _))
+      .WillOnce(base::test::RunOnceCallback<1>(&socket2));
 
   // Add DIAL sinks to |dial_media_sink_service_|, which in turn notifies
   // |media_sink_service_impl_| via the Observer interface.
@@ -672,32 +648,24 @@
   socket1.set_id(1);
   socket1.SetErrorState(cast_channel::ChannelError::CONNECT_ERROR);
 
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint1, _))
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint1, _))
       .Times(1)
-      .WillOnce(WithArgs<1>(
-          Invoke([&socket1](const base::RepeatingCallback<void(
-                                cast_channel::CastSocket * socket)>& callback) {
-            std::move(callback).Run(&socket1);
-          })));
+      .WillOnce(base::test::RunOnceCallback<1>(&socket1));
   media_sink_service_impl_.OnSinkAddedOrUpdated(dial_sink1);
 
   // We don't trigger retries, thus each iteration will only increment the
   // failure count once.
   for (int i = 0; i < CastMediaSinkServiceImpl::kMaxDialSinkFailureCount - 1;
        ++i) {
-    EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint1, _))
+    EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint1, _))
         .Times(1)
-        .WillOnce(WithArgs<1>(Invoke(
-            [&socket1](const base::RepeatingCallback<void(
-                           cast_channel::CastSocket * socket)>& callback) {
-              std::move(callback).Run(&socket1);
-            })));
+        .WillOnce(base::test::RunOnceCallback<1>(&socket1));
     media_sink_service_impl_.OnSinkAddedOrUpdated(dial_sink1);
   }
 
   // OnChannelOpenFailed too many times; next time OnSinkAddedOrUpdated is
   // called, we won't attempt to open channel.
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint1, _))
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint1, _))
       .Times(0);
 
   media_sink_service_impl_.OnSinkAddedOrUpdated(dial_sink1);
@@ -712,7 +680,7 @@
   ASSERT_EQ(ip_endpoint1.address(),
             cast_sink.cast_data().ip_endpoint.address());
   EXPECT_CALL(*mock_cast_socket_service_,
-              OpenSocketInternal(cast_sink.cast_data().ip_endpoint, _))
+              OpenSocket_(cast_sink.cast_data().ip_endpoint, _))
       .Times(1);
   media_sink_service_impl_.OpenChannels(
       cast_sinks, CastMediaSinkServiceImpl::SinkSource::kMdns);
@@ -731,9 +699,9 @@
   // Find Cast sink 1
   media_sink_service_impl_.AddOrUpdateSink(cast_sink1);
 
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint1, _))
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint1, _))
       .Times(0);
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint2, _));
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint2, _));
 
   // Attempt to connect to |cast_sink2| only since |cast_sink1| is already
   // connected.
@@ -762,8 +730,8 @@
   socket1.set_id(1);
   socket2.SetIPEndpoint(ip_endpoint2);
   socket2.set_id(2);
-  ExpectOpenSocketInternal(&socket1);
-  ExpectOpenSocketInternal(&socket2);
+  ExpectOpenSocket(&socket1);
+  ExpectOpenSocket(&socket2);
   media_sink_service_impl_.OpenChannels(
       sink_list1, CastMediaSinkServiceImpl::SinkSource::kMdns);
 
@@ -787,7 +755,7 @@
   cast_channel::MockCastSocket socket3;
   socket3.SetIPEndpoint(ip_endpoint3);
   socket3.set_id(3);
-  ExpectOpenSocketInternal(&socket3);
+  ExpectOpenSocket(&socket3);
   media_sink_service_impl_.OpenChannels(
       sink_list2, CastMediaSinkServiceImpl::SinkSource::kMdns);
 
@@ -798,8 +766,8 @@
   content::RunAllTasksUntilIdle();
   mock_time_task_runner_->FastForwardUntilNoTasksRemain();
 
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint1, _));
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint2, _));
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint1, _));
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint2, _));
   fake_network_info_ = fake_ethernet_info_;
   ChangeConnectionType(network::mojom::ConnectionType::CONNECTION_ETHERNET);
   content::RunAllTasksUntilIdle();
@@ -828,8 +796,8 @@
   socket2.SetErrorState(cast_channel::ChannelError::CONNECT_ERROR);
   socket2.SetIPEndpoint(ip_endpoint2);
   socket2.set_id(2);
-  ExpectOpenSocketInternal(&socket1);
-  ExpectOpenSocketInternal(&socket2);
+  ExpectOpenSocket(&socket1);
+  ExpectOpenSocket(&socket2);
   media_sink_service_impl_.OpenChannels(
       sink_list1, CastMediaSinkServiceImpl::SinkSource::kMdns);
 
@@ -852,7 +820,7 @@
   cast_channel::MockCastSocket socket3;
   socket3.SetIPEndpoint(ip_endpoint3);
   socket3.set_id(3);
-  ExpectOpenSocketInternal(&socket3);
+  ExpectOpenSocket(&socket3);
   media_sink_service_impl_.OpenChannels(
       sink_list2, CastMediaSinkServiceImpl::SinkSource::kMdns);
 
@@ -863,8 +831,8 @@
   content::RunAllTasksUntilIdle();
   mock_time_task_runner_->FastForwardUntilNoTasksRemain();
 
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint1, _));
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint2, _))
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint1, _));
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint2, _))
       .Times(0);
   fake_network_info_ = fake_ethernet_info_;
   ChangeConnectionType(network::mojom::ConnectionType::CONNECTION_ETHERNET);
@@ -889,7 +857,7 @@
   cast_channel::MockCastSocket socket1;
   socket1.SetIPEndpoint(ip_endpoint1);
   socket1.set_id(1);
-  ExpectOpenSocketInternal(&socket1);
+  ExpectOpenSocket(&socket1);
   media_sink_service_impl_.OpenChannels(
       sink_list1, CastMediaSinkServiceImpl::SinkSource::kMdns);
   media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint1, sink1);
@@ -912,7 +880,7 @@
   cast_channel::MockCastSocket socket2;
   socket2.SetIPEndpoint(ip_endpoint2);
   socket2.set_id(2);
-  ExpectOpenSocketInternal(&socket2);
+  ExpectOpenSocket(&socket2);
   media_sink_service_impl_.OpenChannels(
       sink_list2, CastMediaSinkServiceImpl::SinkSource::kMdns);
 
@@ -924,7 +892,7 @@
   content::RunAllTasksUntilIdle();
   mock_time_task_runner_->FastForwardUntilNoTasksRemain();
 
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(_, _)).Times(0);
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(_, _)).Times(0);
   fake_network_info_ = fake_ethernet_info_;
   ChangeConnectionType(network::mojom::ConnectionType::CONNECTION_ETHERNET);
   content::RunAllTasksUntilIdle();
@@ -957,8 +925,8 @@
   socket1.set_id(1);
   socket2.SetIPEndpoint(ip_endpoint2);
   socket2.set_id(2);
-  ExpectOpenSocketInternal(&socket1);
-  ExpectOpenSocketInternal(&socket2);
+  ExpectOpenSocket(&socket1);
+  ExpectOpenSocket(&socket2);
   media_sink_service_impl_.OpenChannels(
       sink_list1, CastMediaSinkServiceImpl::SinkSource::kMdns);
 
@@ -977,13 +945,13 @@
   cast_channel::MockCastSocket socket3;
   socket3.SetIPEndpoint(ip_endpoint3);
   socket3.set_id(3);
-  ExpectOpenSocketInternal(&socket3);
+  ExpectOpenSocket(&socket3);
   media_sink_service_impl_.OpenChannels(
       sink_list2, CastMediaSinkServiceImpl::SinkSource::kMdns);
 
   // Connecting to a network whose ID resolves to __unknown__ shouldn't pull any
   // cache items from another unknown network.
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(_, _)).Times(0);
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(_, _)).Times(0);
   fake_network_info_ = fake_unknown_info_;
   ChangeConnectionType(network::mojom::ConnectionType::CONNECTION_WIFI);
   content::RunAllTasksUntilIdle();
@@ -1017,8 +985,8 @@
   socket1.set_id(1);
   socket2.SetIPEndpoint(ip_endpoint2);
   socket2.set_id(2);
-  ExpectOpenSocketInternal(&socket1);
-  ExpectOpenSocketInternal(&socket2);
+  ExpectOpenSocket(&socket1);
+  ExpectOpenSocket(&socket2);
   media_sink_service_impl_.OpenChannels(
       sink_list1, CastMediaSinkServiceImpl::SinkSource::kMdns);
 
@@ -1042,7 +1010,7 @@
   cast_channel::MockCastSocket socket3;
   socket3.SetIPEndpoint(ip_endpoint3);
   socket3.set_id(3);
-  ExpectOpenSocketInternal(&socket3);
+  ExpectOpenSocket(&socket3);
   media_sink_service_impl_.OpenChannels(
       sink_list2, CastMediaSinkServiceImpl::SinkSource::kMdns);
 
@@ -1058,8 +1026,8 @@
   // Resolution will fail for cached sinks.
   socket1.SetErrorState(cast_channel::ChannelError::CONNECT_ERROR);
   socket2.SetErrorState(cast_channel::ChannelError::CONNECT_ERROR);
-  ExpectOpenSocketInternal(&socket1);
-  ExpectOpenSocketInternal(&socket2);
+  ExpectOpenSocket(&socket1);
+  ExpectOpenSocket(&socket2);
   fake_network_info_ = fake_ethernet_info_;
   ChangeConnectionType(network::mojom::ConnectionType::CONNECTION_ETHERNET);
   content::RunAllTasksUntilIdle();
@@ -1073,7 +1041,7 @@
   cast_channel::MockCastSocket socket4;
   socket4.SetIPEndpoint(ip_endpoint4);
   socket4.set_id(4);
-  ExpectOpenSocketInternal(&socket4);
+  ExpectOpenSocket(&socket4);
   media_sink_service_impl_.OpenChannels(
       sink_list3, CastMediaSinkServiceImpl::SinkSource::kMdns);
 
@@ -1085,7 +1053,7 @@
   media_sink_service_impl_.OnChannelOpenFailed(ip_endpoint4, sink4);
 
   // Reconnect and expect only |sink4| to be cached.
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint4, _));
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint4, _));
   fake_network_info_ = fake_ethernet_info_;
   ChangeConnectionType(network::mojom::ConnectionType::CONNECTION_ETHERNET);
   content::RunAllTasksUntilIdle();
@@ -1114,8 +1082,8 @@
   socket1.set_id(1);
   socket2.SetIPEndpoint(ip_endpoint2);
   socket2.set_id(2);
-  ExpectOpenSocketInternal(&socket1);
-  ExpectOpenSocketInternal(&socket2);
+  ExpectOpenSocket(&socket1);
+  ExpectOpenSocket(&socket2);
   media_sink_service_impl_.OpenChannels(
       sink_list1, CastMediaSinkServiceImpl::SinkSource::kMdns);
   media_sink_service_impl_.OnSinkAddedOrUpdated(sink2_dial);
@@ -1156,8 +1124,8 @@
   socket3.set_id(3);
   socket4.SetIPEndpoint(ip_endpoint4);
   socket4.set_id(4);
-  ExpectOpenSocketInternal(&socket3);
-  ExpectOpenSocketInternal(&socket4);
+  ExpectOpenSocket(&socket3);
+  ExpectOpenSocket(&socket4);
   media_sink_service_impl_.OpenChannels(
       sink_list2, CastMediaSinkServiceImpl::SinkSource::kMdns);
   media_sink_service_impl_.OnSinkAddedOrUpdated(sink4_dial);
@@ -1169,8 +1137,8 @@
   content::RunAllTasksUntilIdle();
   mock_time_task_runner_->FastForwardUntilNoTasksRemain();
 
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint1, _));
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint2, _));
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint1, _));
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint2, _));
   fake_network_info_ = fake_ethernet_info_;
   ChangeConnectionType(network::mojom::ConnectionType::CONNECTION_ETHERNET);
   content::RunAllTasksUntilIdle();
@@ -1197,7 +1165,7 @@
   cast_channel::MockCastSocket socket1_dial;
   socket1_dial.SetIPEndpoint(ip_endpoint1_dial);
   socket1_dial.set_id(1);
-  ExpectOpenSocketInternal(&socket1_dial);
+  ExpectOpenSocket(&socket1_dial);
   media_sink_service_impl_.OnSinkAddedOrUpdated(sink1_dial);
 
   // The same sink is then discovered via mdns. However we won't open channel
@@ -1206,8 +1174,7 @@
   socket1_cast.SetIPEndpoint(ip_endpoint1_cast);
   socket1_cast.set_id(2);
 
-  EXPECT_CALL(*mock_cast_socket_service_,
-              OpenSocketInternal(ip_endpoint1_cast, _))
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint1_cast, _))
       .Times(0);
   media_sink_service_impl_.OpenChannels(
       sink_list1, CastMediaSinkServiceImpl::SinkSource::kMdns);
@@ -1232,7 +1199,7 @@
   cast_channel::MockCastSocket socket2;
   socket2.SetIPEndpoint(ip_endpoint2);
   socket2.set_id(3);
-  ExpectOpenSocketInternal(&socket2);
+  ExpectOpenSocket(&socket2);
   media_sink_service_impl_.OpenChannels(
       sink_list2, CastMediaSinkServiceImpl::SinkSource::kMdns);
 
@@ -1243,8 +1210,7 @@
   content::RunAllTasksUntilIdle();
   mock_time_task_runner_->FastForwardUntilNoTasksRemain();
 
-  EXPECT_CALL(*mock_cast_socket_service_,
-              OpenSocketInternal(ip_endpoint1_cast, _));
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint1_cast, _));
   fake_network_info_ = fake_ethernet_info_;
   ChangeConnectionType(network::mojom::ConnectionType::CONNECTION_ETHERNET);
   content::RunAllTasksUntilIdle();
@@ -1272,8 +1238,8 @@
   socket1.set_id(1);
   socket2.SetIPEndpoint(ip_endpoint2);
   socket2.set_id(2);
-  ExpectOpenSocketInternal(&socket1);
-  ExpectOpenSocketInternal(&socket2);
+  ExpectOpenSocket(&socket1);
+  ExpectOpenSocket(&socket2);
   media_sink_service_impl_.OpenChannels(
       sink_list1, CastMediaSinkServiceImpl::SinkSource::kMdns);
 
@@ -1292,14 +1258,14 @@
   cast_channel::MockCastSocket socket3;
   socket3.SetIPEndpoint(ip_endpoint3);
   socket3.set_id(3);
-  ExpectOpenSocketInternal(&socket3);
+  ExpectOpenSocket(&socket3);
   media_sink_service_impl_.OpenChannels(
       sink_list2, CastMediaSinkServiceImpl::SinkSource::kMdns);
 
   // Reconnecting to the previous ethernet network should restore the same sinks
   // from the cache and attempt to resolve them.
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint1, _));
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocketInternal(ip_endpoint2, _));
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint1, _));
+  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket_(ip_endpoint2, _));
   fake_network_info_ = fake_ethernet_info_;
   ChangeConnectionType(network::mojom::ConnectionType::CONNECTION_ETHERNET);
   content::RunAllTasksUntilIdle();
diff --git a/chrome/browser/optimization_guide/prediction/prediction_model_download_manager.cc b/chrome/browser/optimization_guide/prediction/prediction_model_download_manager.cc
index 9dd9983..4a402655 100644
--- a/chrome/browser/optimization_guide/prediction/prediction_model_download_manager.cc
+++ b/chrome/browser/optimization_guide/prediction/prediction_model_download_manager.cc
@@ -134,7 +134,7 @@
   download_params.scheduling_params.network_requirements =
       download::SchedulingParams::NetworkRequirements::NONE;
 
-  download_service_->StartDownload(download_params);
+  download_service_->StartDownload(std::move(download_params));
 }
 
 void PredictionModelDownloadManager::CancelAllPendingDownloads() {
diff --git a/chrome/browser/optimization_guide/prediction/prediction_model_download_manager_unittest.cc b/chrome/browser/optimization_guide/prediction/prediction_model_download_manager_unittest.cc
index 5a3212c..19cb40317 100644
--- a/chrome/browser/optimization_guide/prediction/prediction_model_download_manager_unittest.cc
+++ b/chrome/browser/optimization_guide/prediction/prediction_model_download_manager_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/sequence_checker.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/thread_pool/thread_pool_instance.h"
+#include "base/test/gmock_move_support.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
@@ -30,7 +31,6 @@
 
 using ::testing::_;
 using ::testing::Eq;
-using ::testing::SaveArg;
 
 class TestPredictionModelDownloadObserver
     : public PredictionModelDownloadObserver {
@@ -273,8 +273,8 @@
       /*disabled_features=*/{});
 
   download::DownloadParams download_params;
-  EXPECT_CALL(*download_service(), StartDownload(_))
-      .WillOnce(SaveArg<0>(&download_params));
+  EXPECT_CALL(*download_service(), StartDownload_(_))
+      .WillOnce(MoveArg<0>(&download_params));
   download_manager()->StartDownload(GURL("someurl"));
 
   // Validate parameters - basically that we attach the correct client, just do
@@ -313,8 +313,8 @@
       /*disabled_features=*/{});
 
   download::DownloadParams download_params;
-  EXPECT_CALL(*download_service(), StartDownload(_))
-      .WillOnce(SaveArg<0>(&download_params));
+  EXPECT_CALL(*download_service(), StartDownload_(_))
+      .WillOnce(MoveArg<0>(&download_params));
   download_manager()->StartDownload(GURL("someurl"));
 
   // Validate parameters - basically that we attach the correct client, just do
@@ -344,8 +344,8 @@
 
 TEST_F(PredictionModelDownloadManagerTest, StartDownloadFailedToSchedule) {
   download::DownloadParams download_params;
-  EXPECT_CALL(*download_service(), StartDownload(_))
-      .WillOnce(SaveArg<0>(&download_params));
+  EXPECT_CALL(*download_service(), StartDownload_(_))
+      .WillOnce(MoveArg<0>(&download_params));
   download_manager()->StartDownload(GURL("someurl"));
 
   // Now invoke start callback.
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc
index 129fedd4..0603762 100644
--- a/chrome/browser/pdf/pdf_extension_test.cc
+++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -87,6 +87,7 @@
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/dump_accessibility_test_helper.h"
 #include "content/public/test/hit_test_region_observer.h"
+#include "content/public/test/prerender_test_util.h"
 #include "content/public/test/scoped_time_zone.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "content/public/test/url_loader_interceptor.h"
@@ -3432,3 +3433,52 @@
   const GURL& expected_url = GetActiveWebContents()->GetURL();
   EXPECT_EQ("https://bing.com/", expected_url.spec());
 }
+
+class PDFExtensionPrerenderTest : public PDFExtensionTest {
+ public:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    PDFExtensionTest::SetUpCommandLine(command_line);
+    // |prerender_helper_| has a ScopedFeatureList so we needed to delay its
+    // creation until now because PDFExtensionTest also uses a ScopedFeatureList
+    // and initialization order matters.
+    prerender_helper_ = std::make_unique<content::test::PrerenderTestHelper>(
+        base::BindRepeating(&PDFExtensionPrerenderTest::GetActiveWebContents,
+                            base::Unretained(this)));
+  }
+
+  void SetUpOnMainThread() override {
+    prerender_helper_->SetUpOnMainThread(embedded_test_server());
+    PDFExtensionTest::SetUpOnMainThread();
+  }
+
+ protected:
+  content::test::PrerenderTestHelper& prerender_helper() {
+    return *prerender_helper_;
+  }
+
+ private:
+  std::unique_ptr<content::test::PrerenderTestHelper> prerender_helper_;
+};
+
+// TODO(1206312, 1205920): As of writing this test, we can attempt to prerender
+// the PDF viewer without crashing, however the viewer itself fails to load a
+// PDF. This test should be extended once that works.
+IN_PROC_BROWSER_TEST_F(PDFExtensionPrerenderTest,
+                       LoadPdfWhilePrerenderedDoesNotCrash) {
+  const GURL initial_url =
+      embedded_test_server()->GetURL("a.test", "/prerender/add_prerender.html");
+  const GURL pdf_url =
+      embedded_test_server()->GetURL("a.test", "/pdf/test.pdf");
+  content::WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  ui_test_utils::NavigateToURL(browser(), initial_url);
+
+  const int host_id = prerender_helper().AddPrerender(pdf_url);
+  content::RenderFrameHost* prerendered_render_frame_host =
+      prerender_helper().GetPrerenderedMainFrameHost(host_id);
+  ASSERT_TRUE(prerendered_render_frame_host);
+  ASSERT_EQ(web_contents->GetURL(), initial_url);
+
+  prerender_helper().NavigatePrimaryPage(pdf_url);
+  ASSERT_EQ(web_contents->GetURL(), pdf_url);
+}
diff --git a/chrome/browser/pdf/pdf_extension_test_util.cc b/chrome/browser/pdf/pdf_extension_test_util.cc
index 9dbc30e..af966a9 100644
--- a/chrome/browser/pdf/pdf_extension_test_util.cc
+++ b/chrome/browser/pdf/pdf_extension_test_util.cc
@@ -10,10 +10,10 @@
 namespace pdf_extension_test_util {
 
 testing::AssertionResult EnsurePDFHasLoaded(
-    content::WebContents* web_contents) {
+    const content::ToRenderFrameHost& frame) {
   bool load_success = false;
   if (!content::ExecuteScriptAndExtractBool(
-          web_contents,
+          frame,
           "window.addEventListener('message', event => {"
           "  if (event.origin !=="
           "          'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai') {"
diff --git a/chrome/browser/pdf/pdf_extension_test_util.h b/chrome/browser/pdf/pdf_extension_test_util.h
index a170d4f1..a397deb 100644
--- a/chrome/browser/pdf/pdf_extension_test_util.h
+++ b/chrome/browser/pdf/pdf_extension_test_util.h
@@ -9,17 +9,17 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace content {
-class WebContents;
+class ToRenderFrameHost;
 }  // namespace content
 
 namespace pdf_extension_test_util {
 
-// Ensures, inside the given `web_contents`, that a PDF has either finished
+// Ensures, inside the given `frame`, that a PDF has either finished
 // loading or prompted a password. The result indicates success if the PDF loads
 // successfully, otherwise it indicates failure. If it doesn't finish loading,
 // the test will hang.
-testing::AssertionResult EnsurePDFHasLoaded(content::WebContents* web_contents)
-    WARN_UNUSED_RESULT;
+testing::AssertionResult EnsurePDFHasLoaded(
+    const content::ToRenderFrameHost& frame) WARN_UNUSED_RESULT;
 
 }  // namespace pdf_extension_test_util
 
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn
index 10818b89..80b30c8 100644
--- a/chrome/browser/resources/BUILD.gn
+++ b/chrome/browser/resources/BUILD.gn
@@ -165,6 +165,7 @@
       deps += [
         "explore_sites_internals:closure_compile",
         "feed_internals:closure_compile",
+        "internals/lens:closure_compile",
         "internals/notifications:closure_compile",
         "internals/query_tiles:closure_compile",
         "offline_pages:closure_compile",
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/pointer_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/pointer_handler.js
index b4ef0bf..ae83882 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/pointer_handler.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/pointer_handler.js
@@ -21,8 +21,6 @@
   constructor() {
     super(null);
 
-    /** @private {boolean|undefined} */
-    this.hasPendingEvents_;
     /** @private {number|undefined} */
     this.mouseX_;
     /** @private {number|undefined} */
@@ -57,10 +55,8 @@
 
         this.expectingHoverCount_--;
         this.handleHitTestResult(evt.target);
-        this.runHitTest();
       });
 
-      this.hasPendingEvents_ = false;
       this.mouseX_ = 0;
       this.mouseY_ = 0;
     });
@@ -78,18 +74,13 @@
   /**
    * Performs a hit test using the most recent mouse coordinates received in
    * onMouseMove or onMove (a e.g. for touch explore).
-   *
-   * Note that runHitTest only ever does a hit test when |hasPendingEvents| is
-   * true.
    * @param {boolean} isTouch
+   * @param {AutomationNode} specificNode
    */
-  runHitTest(isTouch = false) {
+  runHitTest(isTouch = false, specificNode = null) {
     if (this.mouseX_ === undefined || this.mouseY_ === undefined) {
       return;
     }
-    if (!this.hasPendingEvents_) {
-      return;
-    }
 
     if (isTouch && this.isChromebox_) {
       // TODO(accessibility): hit testing seems to be broken in some cases e.g.
@@ -100,12 +91,10 @@
       return;
     }
 
-    this.node_.hitTestWithReply(this.mouseX_, this.mouseY_, (target) => {
+    const actOnNode = specificNode ? specificNode : this.node_;
+    actOnNode.hitTestWithReply(this.mouseX_, this.mouseY_, (target) => {
       this.handleHitTestResult(target);
-      this.runHitTest();
     });
-
-    this.hasPendingEvents_ = false;
   }
 
   /**
@@ -134,7 +123,6 @@
   onMove(x, y, isTouch = false) {
     this.mouseX_ = x;
     this.mouseY_ = y;
-    this.hasPendingEvents_ = true;
     this.runHitTest(isTouch);
   }
 
@@ -176,13 +164,8 @@
       const appNode = walker.next().node;
       if (appNode) {
         // This means we've gotten the app, which is technically in a different
-        // tree so hit tests will be delivered to it properly and come back in
-        // our hover event handler.
-        // TODO: switch to hitTestWithReply once OnActionResult gets hooked up
-        // from Lacros.
-        appNode.hitTest(this.mouseX_, this.mouseY_, EventType.HOVER);
-        this.expectingHoverCount_++;
-        this.lastHoverRequested_ = new Date();
+        // tree so hit tests will be delivered to it properly.
+        this.runHitTest(false, appNode);
       } else {
         // Otherwise, we're in ARC++, which still requires a synthesized mouse
         // event.
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.html b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.html
index 9e67d04..4f52f93 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.html
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.html
@@ -65,7 +65,7 @@
     scroll-snap-align: center;
     scroll-snap-stop: always;
   }
-  #tabs emoji-group-button:nth-child(11) {
+  #tabs emoji-group-button:nth-child(14) {
     scroll-snap-align: center;
     scroll-snap-stop: always;
   }
@@ -187,6 +187,12 @@
       <emoji-group-button class="fake" icon="[[emojiGroupTabs[0].icon]]"
         tabindex="-1">
       </emoji-group-button>
+      <emoji-group-button class="fake" icon="[[emojiGroupTabs[0].icon]]"
+        tabindex="-1">
+      </emoji-group-button>
+      <emoji-group-button class="fake" icon="[[emojiGroupTabs[0].icon]]"
+        tabindex="-1">
+      </emoji-group-button>
       <emoji-group-button id="RightChevronScrollTarget"
         icon="[[emojiGroupTabs[0].icon]]" tabindex="-1">
       </emoji-group-button>
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.js b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.js
index 0305ed8..b0c53bd 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.js
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.js
@@ -277,8 +277,8 @@
   }
 
   onRightChevronClick() {
-    this.$.tabs.scrollLeft = GROUP_ICON_SIZE * 6;
-    this.scrollToGroup(GROUP_TABS[GROUP_PER_ROW - 3].groupId);
+    this.$.tabs.scrollLeft = GROUP_ICON_SIZE * 8;
+    this.scrollToGroup(GROUP_TABS[GROUP_PER_ROW - 1].groupId);
     this.groupTabsMoving = true;
     this.$.bar.style.left = EMOJI_GROUP_SIZE_PX;
   }
@@ -398,7 +398,7 @@
           GROUP_ICON_SIZE * index) {
         // 5 = We want the seventh icon to be first. Then -1 for chevron, -1 for
         // 1 based indexing.
-        tabscrollLeft = GROUP_ICON_SIZE * (5);
+        tabscrollLeft = GROUP_ICON_SIZE * (7);
       }
 
       if (updateTabsScroll) {
diff --git a/chrome/browser/resources/chromeos/vm/OWNERS b/chrome/browser/resources/chromeos/vm/OWNERS
new file mode 100644
index 0000000..a33be2b
--- /dev/null
+++ b/chrome/browser/resources/chromeos/vm/OWNERS
@@ -0,0 +1 @@
+file://chrome/browser/ash/guest_os/OWNERS
diff --git a/chrome/browser/resources/internals/BUILD.gn b/chrome/browser/resources/internals/BUILD.gn
index 4356d04..2bedbba1 100644
--- a/chrome/browser/resources/internals/BUILD.gn
+++ b/chrome/browser/resources/internals/BUILD.gn
@@ -25,8 +25,14 @@
       "$target_gen_dir/user_education/mojo_resources.grdp",
     ]
   } else {
-    deps = [ "notifications:build_grdp" ]
-    grdp_files = [ "$target_gen_dir/notifications/resources.grdp" ]
+    deps = [
+      "lens:build_grdp",
+      "notifications:build_grdp",
+    ]
+    grdp_files = [
+      "$target_gen_dir/lens/resources.grdp",
+      "$target_gen_dir/notifications/resources.grdp",
+    ]
   }
 }
 
diff --git a/chrome/browser/resources/internals/lens/BUILD.gn b/chrome/browser/resources/internals/lens/BUILD.gn
new file mode 100644
index 0000000..479ded7a
--- /dev/null
+++ b/chrome/browser/resources/internals/lens/BUILD.gn
@@ -0,0 +1,37 @@
+# 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("//third_party/closure_compiler/compile_js.gni")
+import("//ui/webui/resources/tools/generate_grd.gni")
+
+assert(is_android)
+
+generate_grd("build_grdp") {
+  grd_prefix = "lens_internals"
+  out_grd = "$target_gen_dir/resources.grdp"
+  input_files = [
+    "lens_internals_browser_proxy.js",
+    "lens_internals.html",
+    "lens_internals.js",
+  ]
+  input_files_base_dir = rebase_path(".", "//")
+}
+
+js_type_check("closure_compile") {
+  deps = [
+    ":lens_internals",
+    ":lens_internals_browser_proxy",
+  ]
+}
+
+js_library("lens_internals") {
+  deps = [
+    ":lens_internals_browser_proxy",
+    "//ui/webui/resources/js:util.m",
+  ]
+}
+
+js_library("lens_internals_browser_proxy") {
+  deps = [ "//ui/webui/resources/js:cr.m" ]
+}
diff --git a/chrome/browser/resources/internals/lens/OWNERS b/chrome/browser/resources/internals/lens/OWNERS
new file mode 100644
index 0000000..dde3a47
--- /dev/null
+++ b/chrome/browser/resources/internals/lens/OWNERS
@@ -0,0 +1,2 @@
+benwgold@google.com
+fgorski@chromium.org
\ No newline at end of file
diff --git a/chrome/browser/resources/internals/lens/lens_internals.html b/chrome/browser/resources/internals/lens/lens_internals.html
new file mode 100644
index 0000000..a06d9f5
--- /dev/null
+++ b/chrome/browser/resources/internals/lens/lens_internals.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<html lang="en" dir="ltr">
+  <head>
+    <meta charset="utf-8">
+    <title>Lens Internals</title>
+    <meta name="viewport" content="width=device-width">
+    <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
+  </head>
+  <body>
+    <h1>Lens Debug Stats</h1>
+    <h4>(Refresh to update page)</h4>
+    <div>
+      <button id="start-debug-mode">
+        Start Debug Mode
+      </button>
+      <button id="stop-debug-mode" hidden>
+        Stop Debug Mode
+      </button>
+
+    </div>
+    <div id="debug-data-container">
+      <table id="debug-data-table" hidden></table>
+    </div>
+    <script type="module" src="lens_internals.js"></script>
+  </body>
+</html>
diff --git a/chrome/browser/resources/internals/lens/lens_internals.js b/chrome/browser/resources/internals/lens/lens_internals.js
new file mode 100644
index 0000000..7884f93
--- /dev/null
+++ b/chrome/browser/resources/internals/lens/lens_internals.js
@@ -0,0 +1,76 @@
+// 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 {$} from 'chrome://resources/js/util.m.js';
+
+import {LensInternalsBrowserProxy, LensInternalsBrowserProxyImpl} from './lens_internals_browser_proxy.js';
+
+/** @param {boolean} showEnableButton Whether to show the "start" button. */
+function toggleDebugModeButton(showEnableButton) {
+  $('start-debug-mode').toggleAttribute('hidden', !showEnableButton);
+  $('stop-debug-mode').toggleAttribute('hidden', showEnableButton);
+}
+
+/**
+ * @param {!Array<!Array<string>>} data The debug data to display in table
+ *     form.
+ */
+function onDebugDataRefreshed(data) {
+  if (data.length == 0) {
+    toggleDebugModeButton(/*showEnableButton=*/ true);
+  } else {
+    toggleDebugModeButton(/*showEnableButton=*/ false);
+    updateDebugDataTable(data);
+  }
+}
+
+/**
+ * @param {!Array<!Array<string>>} tableData The debug data to display in
+ *     table form.
+ */
+function updateDebugDataTable(tableData) {
+  const table = document.createElement('table');
+  table.style.display = 'block';
+  const tableBody = document.createElement('tbody');
+
+  tableData.forEach(function(rowData) {
+    const row = document.createElement('tr');
+    rowData.forEach(function(cellData) {
+      const cell = document.createElement('td');
+      cell.appendChild(document.createTextNode(cellData));
+      row.appendChild(cell);
+    });
+    tableBody.appendChild(row);
+  });
+  table.appendChild(tableBody);
+
+  $('debug-data-table').replaceWith(table);
+  table.id = 'debug-data-table';
+}
+
+function initialize() {
+  /** @type {!LensInternalsBrowserProxy} */
+  const browserProxy = LensInternalsBrowserProxyImpl.getInstance();
+
+  $('start-debug-mode').onclick = function() {
+    browserProxy.startDebugMode().then(function() {
+      // After starting debug mode automatically refresh data.  This will
+      // toggle the button if the call was successful.
+      browserProxy.refreshDebugData().then(onDebugDataRefreshed);
+    });
+  };
+
+  $('stop-debug-mode').onclick = function() {
+    browserProxy.stopDebugMode().then(function() {
+      // After stopping debug mode automatically refresh data.  This will
+      // toggle the button if the call was successful.
+      browserProxy.refreshDebugData().then(onDebugDataRefreshed);
+    });
+  };
+
+  // Start by attempting to refresh the debug data. Whether the java layer
+  // supplied data back determines which debug mode button is displayed.
+  browserProxy.refreshDebugData().then(onDebugDataRefreshed);
+}
+
+document.addEventListener('DOMContentLoaded', initialize);
\ No newline at end of file
diff --git a/chrome/browser/resources/internals/lens/lens_internals_browser_proxy.js b/chrome/browser/resources/internals/lens/lens_internals_browser_proxy.js
new file mode 100644
index 0000000..8025eb71
--- /dev/null
+++ b/chrome/browser/resources/internals/lens/lens_internals_browser_proxy.js
@@ -0,0 +1,49 @@
+// 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 {addSingletonGetter, sendWithPromise} from 'chrome://resources/js/cr.m.js';
+
+/** @interface */
+export class LensInternalsBrowserProxy {
+  /**
+   * Start debug mode collection for proactive.
+   * @return {!Promise<void>} A promise firing when the call is complete.
+   */
+  startDebugMode() {}
+
+  /**
+   * Start debug mode collection for proactive.
+   * @return {!Promise<!Array<!Array<string>>>} A promise firing when the call
+   *     is complete.
+   */
+  refreshDebugData() {}
+
+  /**
+   * Stop debug mode collection for proactive.
+   * @return {!Promise<void>} A promise firing when the call is complete.
+   */
+  stopDebugMode() {}
+}
+
+/**
+ * @implements {LensInternalsBrowserProxy}
+ */
+export class LensInternalsBrowserProxyImpl {
+  /** @override */
+  startDebugMode() {
+    return sendWithPromise('startDebugMode');
+  }
+
+  /** @override */
+  refreshDebugData() {
+    return sendWithPromise('refreshDebugData');
+  }
+
+  /** @override */
+  stopDebugMode() {
+    return sendWithPromise('stopDebugMode');
+  }
+}
+
+addSingletonGetter(LensInternalsBrowserProxyImpl);
diff --git a/chrome/browser/resources/pdf/BUILD.gn b/chrome/browser/resources/pdf/BUILD.gn
index ce6ab4e..db66055b 100644
--- a/chrome/browser/resources/pdf/BUILD.gn
+++ b/chrome/browser/resources/pdf/BUILD.gn
@@ -260,20 +260,17 @@
     ":annotation_tool",
     ":controller",
     ":viewport",
-    "//ui/webui/resources/js:cr.m",
     "//ui/webui/resources/js/cr:event_target.m",
   ]
 }
 
 js_library("local_storage_proxy") {
-  deps = [ "//ui/webui/resources/js:cr.m" ]
 }
 
 js_library("controller") {
   deps = [
     ":viewport",
     "//ui/webui/resources/js:assert.m",
-    "//ui/webui/resources/js:cr.m",
     "//ui/webui/resources/js:load_time_data.m",
     "//ui/webui/resources/js:promise_resolver.m",
     "//ui/webui/resources/js/cr:event_target.m",
diff --git a/chrome/browser/resources/pdf/controller.js b/chrome/browser/resources/pdf/controller.js
index 7dd7c3f..372a58ba 100644
--- a/chrome/browser/resources/pdf/controller.js
+++ b/chrome/browser/resources/pdf/controller.js
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 import {assert} from 'chrome://resources/js/assert.m.js';
-import {addSingletonGetter} from 'chrome://resources/js/cr.m.js';
 import {NativeEventTarget as EventTarget} from 'chrome://resources/js/cr/event_target.m.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {PromiseResolver} from 'chrome://resources/js/promise_resolver.m.js';
@@ -564,6 +563,12 @@
 
     resolver.resolve(messageData);
   }
+
+  /** @return {!PluginController} */
+  static getInstance() {
+    return instance || (instance = new PluginController());
+  }
 }
 
-addSingletonGetter(PluginController);
+/** @type {?PluginController} */
+let instance = null;
diff --git a/chrome/browser/resources/pdf/ink_controller.js b/chrome/browser/resources/pdf/ink_controller.js
index 7a10692..95b8a5b 100644
--- a/chrome/browser/resources/pdf/ink_controller.js
+++ b/chrome/browser/resources/pdf/ink_controller.js
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {addSingletonGetter} from 'chrome://resources/js/cr.m.js';
 import {NativeEventTarget as EventTarget} from 'chrome://resources/js/cr/event_target.m.js';
 
 import {ContentController} from './controller.js';
@@ -185,6 +184,12 @@
     this.inkHost_ = null;
     this.isActive = false;
   }
+
+  /** @return {!InkController} */
+  static getInstance() {
+    return instance || (instance = new InkController());
+  }
 }
 
-addSingletonGetter(InkController);
+/** @type {?InkController} */
+let instance = null;
diff --git a/chrome/browser/resources/pdf/local_storage_proxy.js b/chrome/browser/resources/pdf/local_storage_proxy.js
index 92b36c31..be842f3 100644
--- a/chrome/browser/resources/pdf/local_storage_proxy.js
+++ b/chrome/browser/resources/pdf/local_storage_proxy.js
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {addSingletonGetter} from 'chrome://resources/js/cr.m.js';
-
 /** @interface */
 class LocalStorageProxy {
   /**
@@ -30,6 +28,12 @@
   setItem(key, value) {
     window.localStorage.setItem(key, value);
   }
+
+  /** @return {!LocalStorageProxy} */
+  static getInstance() {
+    return instance || (instance = new LocalStorageProxyImpl());
+  }
 }
 
-addSingletonGetter(LocalStorageProxyImpl);
+/** @type {?LocalStorageProxy} */
+let instance = null;
diff --git a/chrome/browser/resources/pdf/pdf_viewer.js b/chrome/browser/resources/pdf/pdf_viewer.js
index 872f12f..36d3635 100644
--- a/chrome/browser/resources/pdf/pdf_viewer.js
+++ b/chrome/browser/resources/pdf/pdf_viewer.js
@@ -285,8 +285,8 @@
 
     // TODO(dpapad): Add tests after crbug.com/1111459 is fixed.
     this.sidenavCollapsed_ = Boolean(Number.parseInt(
-        LocalStorageProxyImpl.getInstance().getItem(
-            LOCAL_STORAGE_SIDENAV_COLLAPSED_KEY),
+        /** @type {string} */ (LocalStorageProxyImpl.getInstance().getItem(
+            LOCAL_STORAGE_SIDENAV_COLLAPSED_KEY)),
         10));
 
     // Non-Polymer properties
@@ -1099,7 +1099,8 @@
     }
 
     LocalStorageProxyImpl.getInstance().setItem(
-        LOCAL_STORAGE_SIDENAV_COLLAPSED_KEY, this.sidenavCollapsed_ ? 1 : 0);
+        LOCAL_STORAGE_SIDENAV_COLLAPSED_KEY,
+        (this.sidenavCollapsed_ ? 1 : 0).toString());
   }
 
   /**
diff --git a/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.html b/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.html
index f33aeec..61c2ec8 100644
--- a/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.html
+++ b/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.html
@@ -68,7 +68,7 @@
         fill: var(--cros-icon-color-prominent);
       }
 
-      iron-icon[icon='cr:error'] {
+      iron-icon[icon='cr:error-outline'] {
         fill: var(--cros-error-color);
       }
 
diff --git a/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.js b/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.js
index 5d56f56..f4bc8e4 100644
--- a/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.js
+++ b/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.js
@@ -472,7 +472,7 @@
       case UpdateStatus.FAILED_DOWNLOAD:
       case UpdateStatus.FAILED_HTTP:
       case UpdateStatus.FAILED:
-        return 'cr:error';
+        return 'cr:error-outline';
       case UpdateStatus.UPDATED:
       case UpdateStatus.NEARLY_UPDATED:
         // TODO(crbug.com/986596): Don't use browser icons here. Fork them.
diff --git a/chrome/browser/safe_browsing/BUILD.gn b/chrome/browser/safe_browsing/BUILD.gn
index 825663c..4d46dbb1 100644
--- a/chrome/browser/safe_browsing/BUILD.gn
+++ b/chrome/browser/safe_browsing/BUILD.gn
@@ -178,6 +178,7 @@
       "//components/sync_user_events",
       "//components/unified_consent",
       "//components/variations/service",
+      "//components/version_info",
       "//content/public/browser",
       "//services/preferences/public/mojom:mojom",
     ]
diff --git a/chrome/browser/safe_browsing/user_population.cc b/chrome/browser/safe_browsing/user_population.cc
index 217af50..a1ba523 100644
--- a/chrome/browser/safe_browsing/user_population.cc
+++ b/chrome/browser/safe_browsing/user_population.cc
@@ -4,8 +4,10 @@
 
 #include "chrome/browser/safe_browsing/user_population.h"
 
+#include "base/feature_list.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/policy/chrome_browser_policy_connector.h"
+#include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/safe_browsing/advanced_protection_status_manager.h"
 #include "chrome/browser/safe_browsing/advanced_protection_status_manager_factory.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
@@ -13,8 +15,10 @@
 #include "components/safe_browsing/buildflags.h"
 #include "components/safe_browsing/core/common/safe_browsing_prefs.h"
 #include "components/safe_browsing/core/common/utils.h"
+#include "components/safe_browsing/core/features.h"
 #include "components/sync/driver/sync_service.h"
 #include "components/unified_consent/pref_names.h"
+#include "components/version_info/version_info.h"
 
 namespace safe_browsing {
 
@@ -58,6 +62,23 @@
   population.set_profile_management_status(GetProfileManagementStatus(
       g_browser_process->browser_policy_connector()));
 
+  if (base::FeatureList::IsEnabled(kBetterTelemetryAcrossReports)) {
+    std::string user_agent =
+        version_info::GetProductNameAndVersionForUserAgent() + "/" +
+        version_info::GetOSType();
+    population.set_user_agent(user_agent);
+
+    ProfileManager* profile_manager = g_browser_process->profile_manager();
+    // |profile_manager| may be null in tests.
+    if (profile_manager) {
+      population.set_number_of_profiles(profile_manager->GetNumberOfProfiles());
+      population.set_number_of_loaded_profiles(
+          profile_manager->GetLoadedProfiles().size());
+      population.set_number_of_open_profiles(
+          profile_manager->GetLastOpenedProfiles().size());
+    }
+  }
+
   return population;
 }
 
diff --git a/chrome/browser/safe_browsing/user_population_unittest.cc b/chrome/browser/safe_browsing/user_population_unittest.cc
index 486183f..17cfd979 100644
--- a/chrome/browser/safe_browsing/user_population_unittest.cc
+++ b/chrome/browser/safe_browsing/user_population_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/safe_browsing/user_population.h"
 
+#include "base/feature_list.h"
 #include "chrome/browser/safe_browsing/advanced_protection_status_manager.h"
 #include "chrome/browser/safe_browsing/advanced_protection_status_manager_factory.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
@@ -11,9 +12,11 @@
 #include "components/prefs/pref_service.h"
 #include "components/safe_browsing/buildflags.h"
 #include "components/safe_browsing/core/common/safe_browsing_prefs.h"
+#include "components/safe_browsing/core/features.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/driver/test_sync_service.h"
 #include "components/unified_consent/pref_names.h"
+#include "components/version_info/version_info.h"
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -142,4 +145,29 @@
 }
 #endif
 
+TEST(GetUserPopulationTest, PopulatesUserAgent) {
+  content::BrowserTaskEnvironment task_environment;
+  TestingProfile profile;
+
+  {
+    base::test::ScopedFeatureList feature_list;
+    feature_list.InitWithFeatures(
+        /* enabled_features = */ {},
+        /* disabled_features = */ {kBetterTelemetryAcrossReports});
+    ChromeUserPopulation population = GetUserPopulation(&profile);
+    EXPECT_EQ(population.user_agent(), "");
+  }
+  {
+    base::test::ScopedFeatureList feature_list;
+    feature_list.InitWithFeatures(
+        /* enabled_features = */ {kBetterTelemetryAcrossReports},
+        /* disabled_features = */ {});
+    std::string user_agent =
+        version_info::GetProductNameAndVersionForUserAgent() + "/" +
+        version_info::GetOSType();
+    ChromeUserPopulation population = GetUserPopulation(&profile);
+    EXPECT_EQ(population.user_agent(), user_agent);
+  }
+}
+
 }  // namespace safe_browsing
diff --git a/chrome/browser/sessions/session_restore_browsertest_chromeos.cc b/chrome/browser/sessions/session_restore_browsertest_chromeos.cc
index 2f07094..9dfd46b 100644
--- a/chrome/browser/sessions/session_restore_browsertest_chromeos.cc
+++ b/chrome/browser/sessions/session_restore_browsertest_chromeos.cc
@@ -120,10 +120,9 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 
-// Assigns three browser windows to three different desks. Assign a fourth
-// browser window to all desks.
+// Assigns three browser windows to three different desks.
 IN_PROC_BROWSER_TEST_F(SessionRestoreTestChromeOS,
-                       DISABLED_PRE_RestoreBrowserWindowsToDesks) {
+                       PRE_RestoreBrowserWindowsToDesks) {
   // Create two more desks so we have three desks in total.
   ash::AutotestDesksApi().CreateNewDesk();
   ash::AutotestDesksApi().CreateNewDesk();
@@ -149,32 +148,15 @@
   Browser* browser_desk2 = CreateBrowserWithParams(browser_desk2_params);
   browser_desk2->SetWindowUserTitle("2");
 
-  // Create a fourth browser window and make it visible on all desks.
-  ash::AutotestDesksApi().ActivateDeskAtIndex(0, base::DoNothing());
-
-  Browser::CreateParams visible_on_all_desks_browser_params =
-      Browser::CreateParams(profile(), true);
-  visible_on_all_desks_browser_params.initial_visible_on_all_workspaces_state =
-      true;
-  Browser* visible_on_all_desks_browser =
-      CreateBrowserWithParams(visible_on_all_desks_browser_params);
-
-  auto* visible_on_all_desks_window =
-      visible_on_all_desks_browser->window()->GetNativeWindow();
-  ASSERT_TRUE(visible_on_all_desks_window->GetProperty(
-      aura::client::kVisibleOnAllWorkspacesKey));
-  ASSERT_TRUE(ash::DesksHelper::Get()->BelongsToActiveDesk(
-      visible_on_all_desks_window));
-
   TurnOnSessionRestore();
 }
 
 // Verifies that three windows restored to their right desk after restored. Also
 // verifies that the fourth window is visible on all desks after being restored.
 IN_PROC_BROWSER_TEST_F(SessionRestoreTestChromeOS,
-                       DISABLED_RestoreBrowserWindowsToDesks) {
+                       RestoreBrowserWindowsToDesks) {
   auto* browser_list = BrowserList::GetInstance();
-  ASSERT_EQ(4u, browser_list->size());
+  ASSERT_EQ(3u, browser_list->size());
 
   // The first, second and third browser should restore to the first, second
   // and third desk, consecutively.
@@ -195,9 +177,49 @@
     ASSERT_EQ(desk_index,
               workspace == aura::client::kUnassignedWorkspace ? 0 : workspace);
   }
+}
 
-  // There should be a fourth browser that should be visible on all desks.
-  auto* visible_on_all_desks_browser = browser_list->get(3);
+// Assigns a browser window to all desks.
+IN_PROC_BROWSER_TEST_F(SessionRestoreTestChromeOS,
+                       PRE_RestoreAllDesksBrowserWindow) {
+  // Create two desks so we have three in total.
+  ash::AutotestDesksApi().CreateNewDesk();
+  ash::AutotestDesksApi().CreateNewDesk();
+
+  // Create a browser that is visible on all desks.
+  Browser::CreateParams visible_on_all_desks_browser_params =
+      Browser::CreateParams(profile(), true);
+  visible_on_all_desks_browser_params.initial_visible_on_all_workspaces_state =
+      true;
+  Browser* visible_on_all_desks_browser =
+      CreateBrowserWithParams(visible_on_all_desks_browser_params);
+
+  // Ensure the visible on all desks browser has the right properties.
+  auto* visible_on_all_desks_window =
+      visible_on_all_desks_browser->window()->GetNativeWindow();
+  ASSERT_TRUE(visible_on_all_desks_window->GetProperty(
+      aura::client::kVisibleOnAllWorkspacesKey));
+  ASSERT_TRUE(ash::DesksHelper::Get()->BelongsToActiveDesk(
+      visible_on_all_desks_window));
+
+  // Check that there are two browsers, the default one and the visible on all
+  // desks browser.
+  auto* browser_list = BrowserList::GetInstance();
+  ASSERT_EQ(2u, browser_list->size());
+
+  TurnOnSessionRestore();
+}
+
+// Verifies that the visible on all desks browser window is restore properly.
+IN_PROC_BROWSER_TEST_F(SessionRestoreTestChromeOS,
+                       RestoreAllDesksBrowserWindow) {
+  // There should be two browsers restored, the default browser and the all
+  // desks browser.
+  auto* browser_list = BrowserList::GetInstance();
+  ASSERT_EQ(2u, browser_list->size());
+
+  // Check that the visible on all desks browser is restored properly.
+  auto* visible_on_all_desks_browser = browser_list->get(1);
   auto* visible_on_all_desks_window =
       visible_on_all_desks_browser->window()->GetNativeWindow();
   ASSERT_TRUE(visible_on_all_desks_window->GetProperty(
diff --git a/chrome/browser/sharing/features.cc b/chrome/browser/sharing/features.cc
index da448507..f28d4f7 100644
--- a/chrome/browser/sharing/features.cc
+++ b/chrome/browser/sharing/features.cc
@@ -6,9 +6,6 @@
 
 #include "build/build_config.h"
 
-const base::Feature kSharingQRCodeGenerator{"SharingQRCodeGenerator",
-                                            base::FEATURE_ENABLED_BY_DEFAULT};
-
 const base::Feature kSharingDeviceExpiration{"SharingDeviceExpiration",
                                              base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/chrome/browser/sharing/features.h b/chrome/browser/sharing/features.h
index 3acb082..e65d52e 100644
--- a/chrome/browser/sharing/features.h
+++ b/chrome/browser/sharing/features.h
@@ -8,9 +8,6 @@
 #include "base/feature_list.h"
 #include "base/metrics/field_trial_params.h"
 
-// Feature flag to enable QR Code Generator (currently desktop-only).
-extern const base::Feature kSharingQRCodeGenerator;
-
 // Feature flag for configuring device expiration.
 extern const base::Feature kSharingDeviceExpiration;
 
diff --git a/chrome/browser/supervised_user/supervised_user_service.cc b/chrome/browser/supervised_user/supervised_user_service.cc
index aa24422..c880506 100644
--- a/chrome/browser/supervised_user/supervised_user_service.cc
+++ b/chrome/browser/supervised_user/supervised_user_service.cc
@@ -311,7 +311,7 @@
       denylist_state_(DenylistLoadState::NOT_LOADED) {
   url_filter_.AddObserver(this);
 #if BUILDFLAG(ENABLE_EXTENSIONS)
-  registry_observer_.Add(extensions::ExtensionRegistry::Get(profile));
+  registry_observation_.Observe(extensions::ExtensionRegistry::Get(profile));
 #endif
 }
 
diff --git a/chrome/browser/supervised_user/supervised_user_service.h b/chrome/browser/supervised_user/supervised_user_service.h
index b49ea29..4af648c 100644
--- a/chrome/browser/supervised_user/supervised_user_service.h
+++ b/chrome/browser/supervised_user/supervised_user_service.h
@@ -16,7 +16,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
 #include "build/build_config.h"
 #include "chrome/browser/net/file_downloader.h"
 #include "chrome/browser/supervised_user/supervised_user_denylist.h"
@@ -400,9 +400,9 @@
   std::vector<std::unique_ptr<PermissionRequestCreator>> permissions_creators_;
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
-  ScopedObserver<extensions::ExtensionRegistry,
-                 extensions::ExtensionRegistryObserver>
-      registry_observer_{this};
+  base::ScopedObservation<extensions::ExtensionRegistry,
+                          extensions::ExtensionRegistryObserver>
+      registry_observation_{this};
 #endif
 
   base::ObserverList<SupervisedUserServiceObserver>::Unchecked observer_list_;
diff --git a/chrome/browser/supervised_user/supervised_user_service_unittest.cc b/chrome/browser/supervised_user/supervised_user_service_unittest.cc
index 5ebdc21c..3aeb192 100644
--- a/chrome/browser/supervised_user/supervised_user_service_unittest.cc
+++ b/chrome/browser/supervised_user/supervised_user_service_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
+#include "base/scoped_observation.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
@@ -91,11 +92,11 @@
     : public AsyncTestHelper,
       public SupervisedUserURLFilter::Observer {
  public:
-  SupervisedUserURLFilterObserver() : scoped_observer_(this) {}
+  SupervisedUserURLFilterObserver() {}
   ~SupervisedUserURLFilterObserver() {}
 
   void Init(SupervisedUserURLFilter* url_filter) {
-    scoped_observer_.Add(url_filter);
+    scoped_observation_.Observe(url_filter);
   }
 
   // SupervisedUserURLFilter::Observer
@@ -104,8 +105,9 @@
   }
 
  private:
-  ScopedObserver<SupervisedUserURLFilter, SupervisedUserURLFilter::Observer>
-      scoped_observer_;
+  base::ScopedObservation<SupervisedUserURLFilter,
+                          SupervisedUserURLFilter::Observer>
+      scoped_observation_{this};
 
   DISALLOW_COPY_AND_ASSIGN(SupervisedUserURLFilterObserver);
 };
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index bd4f508..a362920 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -756,6 +756,8 @@
       "webui/explore_sites_internals/explore_sites_internals_page_handler.h",
       "webui/explore_sites_internals/explore_sites_internals_ui.cc",
       "webui/explore_sites_internals/explore_sites_internals_ui.h",
+      "webui/internals/lens/lens_internals_ui_message_handler.cc",
+      "webui/internals/lens/lens_internals_ui_message_handler.h",
       "webui/internals/notifications/notifications_internals_ui_message_handler.cc",
       "webui/internals/notifications/notifications_internals_ui_message_handler.h",
       "webui/internals/query_tiles/query_tiles_internals_ui_message_handler.cc",
@@ -4390,8 +4392,6 @@
       "webauthn/sheet_models.h",
       "webauthn/transport_hover_list_model.cc",
       "webauthn/transport_hover_list_model.h",
-      "webauthn/transport_utils.cc",
-      "webauthn/transport_utils.h",
       "webauthn/webauthn_ui_helpers.cc",
       "webauthn/webauthn_ui_helpers.h",
     ]
diff --git a/chrome/browser/ui/app_list/search/app_list_search_browsertest.cc b/chrome/browser/ui/app_list/search/app_list_search_browsertest.cc
index ac86b78..a942194 100644
--- a/chrome/browser/ui/app_list/search/app_list_search_browsertest.cc
+++ b/chrome/browser/ui/app_list/search/app_list_search_browsertest.cc
@@ -7,6 +7,7 @@
 
 #include "ash/constants/ash_features.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
+#include "ash/public/cpp/app_list/app_list_metrics.h"
 #include "ash/public/cpp/app_list/app_list_types.h"
 #include "base/callback_helpers.h"
 #include "base/files/file_util.h"
@@ -177,6 +178,7 @@
   ChromeSearchResult* result = FindResult("help-app://discover");
   ASSERT_TRUE(result);
   EXPECT_EQ(base::UTF16ToASCII(result->title()), "Make your own game");
+  EXPECT_EQ(result->metrics_type(), ash::HELP_APP_DISCOVER);
 
   // Open the search result. This should open the help app at the expected url.
   size_t num_browsers = chrome::GetTotalBrowserCount();
@@ -218,6 +220,7 @@
   auto* result = FindResult("help-app://updates");
   ASSERT_TRUE(result);
   EXPECT_EQ(base::UTF16ToASCII(result->title()), "What's new with Chrome OS");
+  EXPECT_EQ(result->metrics_type(), ash::HELP_APP_UPDATES);
   // Displayed in first position.
   EXPECT_EQ(result->position_priority(), 1.0f);
   EXPECT_EQ(result->display_type(), DisplayType::kChip);
diff --git a/chrome/browser/ui/app_list/search/help_app_provider.cc b/chrome/browser/ui/app_list/search/help_app_provider.cc
index 9adb5ba..f3bdbe1f 100644
--- a/chrome/browser/ui/app_list/search/help_app_provider.cc
+++ b/chrome/browser/ui/app_list/search/help_app_provider.cc
@@ -9,6 +9,7 @@
 #include "ash/constants/ash_features.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
+#include "ash/public/cpp/app_list/app_list_metrics.h"
 #include "base/bind.h"
 #include "base/feature_list.h"
 #include "base/macros.h"
@@ -130,7 +131,14 @@
   SetPositionPriority(1.0f);
   SetResultType(ResultType::kHelpApp);
   SetDisplayType(DisplayType::kChip);
-  SetMetricsType(ash::HELP_APP);
+  // Some chips have different metrics types.
+  if (id == kHelpAppDiscoverResult) {
+    SetMetricsType(ash::HELP_APP_DISCOVER);
+  } else if (id == kHelpAppUpdatesResult) {
+    SetMetricsType(ash::HELP_APP_UPDATES);
+  } else {
+    SetMetricsType(ash::HELP_APP_DEFAULT);
+  }
   SetChipIcon(icon);
 }
 
@@ -150,7 +158,7 @@
   SetTitleTags(CalculateTags(query, result->title));
   SetResultType(ResultType::kHelpApp);
   SetDisplayType(DisplayType::kList);
-  SetMetricsType(ash::HELP_APP);
+  SetMetricsType(ash::HELP_APP_DEFAULT);
   SetIcon(icon);
   SetDetails(result->main_category);
 }
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.cc b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.cc
index 0f9575a4..92ac373 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.cc
+++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.cc
@@ -131,9 +131,12 @@
   receivers_.Add(this, std::move(receiver));
 }
 
+// TODO(crbug.com/1208910): Support incognito.
 void HoldingSpaceKeyedService::AddPrintedPdf(
-    const base::FilePath& printed_pdf_path) {
-  AddItemOfType(HoldingSpaceItem::Type::kPrintedPdf, printed_pdf_path);
+    const base::FilePath& printed_pdf_path,
+    bool from_incognito_profile) {
+  if (!from_incognito_profile)
+    AddItemOfType(HoldingSpaceItem::Type::kPrintedPdf, printed_pdf_path);
 }
 
 void HoldingSpaceKeyedService::AddPinnedFiles(
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.h b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.h
index 2a4d5cb6..43c36cd 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.h
+++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.h
@@ -63,7 +63,8 @@
       mojo::PendingReceiver<crosapi::mojom::HoldingSpaceService> receiver);
 
   // crosapi::mojom::HoldingSpaceKeyedService:
-  void AddPrintedPdf(const base::FilePath& printed_pdf_path) override;
+  void AddPrintedPdf(const base::FilePath& printed_pdf_path,
+                     bool from_incognito_profile) override;
 
   // Adds multiple pinned file items identified by the provided file system
   // URLs.
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc
index 9918562..9f8fa92 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc
+++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc
@@ -732,11 +732,12 @@
   }
 }
 
+// TODO(crbug.com/1170667): Fix flakes and re-enable.
 // Tests that holding space item's image representation gets updated when the
 // backing file is changed using move operation. Furthermore, verifies that
 // conflicts caused by moving a holding space item file to another path present
 // in the holding space get resolved.
-TEST_F(HoldingSpaceKeyedServiceTest, UpdateItemsOverwrittenByMove) {
+TEST_F(HoldingSpaceKeyedServiceTest, DISABLED_UpdateItemsOverwrittenByMove) {
   // Create a file system mount point.
   std::unique_ptr<ScopedTestMountPoint> downloads_mount =
       ScopedTestMountPoint::CreateAndMountDownloads(GetProfile());
@@ -1616,7 +1617,8 @@
                      profile, file_path))});
         break;
       case HoldingSpaceItem::Type::kPrintedPdf:
-        holding_space_service->AddPrintedPdf(file_path);
+        holding_space_service->AddPrintedPdf(file_path,
+                                             /*from_incognito_profile=*/false);
         break;
       case HoldingSpaceItem::Type::kScreenRecording:
         holding_space_service->AddScreenRecording(file_path);
@@ -1816,9 +1818,11 @@
   EXPECT_EQ(u"File 2.png", item_2->text());
 }
 
-// Base class for tests of print-to-PDF integration.
+// Base class for tests of print-to-PDF integration. Parameterized by whether
+// tests should use an incognito browser.
 class HoldingSpaceKeyedServicePrintToPdfIntegrationTest
-    : public HoldingSpaceKeyedServiceTest {
+    : public HoldingSpaceKeyedServiceTest,
+      public testing::WithParamInterface<bool> {
  public:
   // Starts a job to print an empty PDF to the specified `file_path`.
   // NOTE: This method will not return until the print job completes.
@@ -1836,22 +1840,49 @@
     run_loop.Run();
   }
 
+  // Returns true if the test should use an incognito browser, false otherwise.
+  bool UseIncognitoBrowser() const { return GetParam(); }
+
  private:
   // HoldingSpaceKeyedServiceTest:
   void SetUp() override {
     HoldingSpaceKeyedServiceTest::SetUp();
 
     // Create the PDF printer handler.
+    Browser* browser = GetBrowserForPdfPrinterHandler();
     pdf_printer_handler_ = std::make_unique<printing::PdfPrinterHandler>(
-        profile(), browser()->tab_strip_model()->GetActiveWebContents(),
+        browser->profile(), browser->tab_strip_model()->GetActiveWebContents(),
         /*sticky_settings=*/nullptr);
   }
 
+  void TearDown() override {
+    incognito_browser_.reset();
+    HoldingSpaceKeyedServiceTest::TearDown();
+  }
+
+  Browser* GetBrowserForPdfPrinterHandler() {
+    if (!UseIncognitoBrowser())
+      return browser();
+    if (!incognito_browser_) {
+      incognito_browser_ =
+          CreateBrowserWithTestWindowForParams(Browser::CreateParams(
+              profile()->GetPrimaryOTRProfile(/*create_if_needed=*/true),
+              /*user_gesture=*/true));
+    }
+    return incognito_browser_.get();
+  }
+
   std::unique_ptr<printing::PdfPrinterHandler> pdf_printer_handler_;
+  std::unique_ptr<Browser> incognito_browser_;
 };
 
-// Verifies that print-to-PDF adds an associated item to holding space.
-TEST_F(HoldingSpaceKeyedServicePrintToPdfIntegrationTest, AddPrintedPdfItem) {
+INSTANTIATE_TEST_SUITE_P(All,
+                         HoldingSpaceKeyedServicePrintToPdfIntegrationTest,
+                         testing::Bool());
+
+// Verifies that print-to-PDF adds an associated item to holding space unless
+// the print job was from an incognito profile.
+TEST_P(HoldingSpaceKeyedServicePrintToPdfIntegrationTest, AddPrintedPdfItem) {
   // Create a file system mount point.
   std::unique_ptr<ScopedTestMountPoint> mount_point =
       ScopedTestMountPoint::CreateAndMountDownloads(GetProfile());
@@ -1870,7 +1901,14 @@
   base::FilePath file_path = mount_point->GetRootPath().Append("foo.pdf");
   StartPrintToPdfAndWaitForSave(u"job_title", file_path);
 
-  // Verify that the holding space is now populated with the expected item.
+  // If the print job was from an incognito profile, no item should have been
+  // added to holding space.
+  if (UseIncognitoBrowser()) {
+    ASSERT_EQ(model->items().size(), 0u);
+    return;
+  }
+
+  // Otherwise, verify that holding space is populated with the expected item.
   ASSERT_EQ(model->items().size(), 1u);
   EXPECT_EQ(model->items()[0]->type(), HoldingSpaceItem::Type::kPrintedPdf);
   EXPECT_EQ(model->items()[0]->file_path(), file_path);
diff --git a/chrome/browser/ui/ash/wallpaper_controller_client_impl.cc b/chrome/browser/ui/ash/wallpaper_controller_client_impl.cc
index bd518b4..9f76f20 100644
--- a/chrome/browser/ui/ash/wallpaper_controller_client_impl.cc
+++ b/chrome/browser/ui/ash/wallpaper_controller_client_impl.cc
@@ -11,8 +11,11 @@
 #include "base/bind.h"
 #include "base/hash/sha1.h"
 #include "base/json/json_reader.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/path_service.h"
+#include "base/sequenced_task_runner.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "base/values.h"
 #include "chrome/browser/apps/app_service/app_launch_params.h"
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
@@ -35,6 +38,7 @@
 #include "components/session_manager/core/session_manager.h"
 #include "components/user_manager/known_user.h"
 #include "components/user_manager/user_manager.h"
+#include "extensions/browser/api/storage/backend_task_runner.h"
 #include "extensions/browser/api/storage/storage_frontend.h"
 #include "extensions/browser/event_router.h"
 #include "extensions/browser/extension_registry.h"
@@ -126,6 +130,40 @@
   return nullptr;
 }
 
+// Extract daily refresh collection id from |value_store|. If unable to fetch
+// the daily refresh collection id, or the user does not have daily refresh
+// configured, returns empty string. This must be run on the same sequence
+// that |value_store| came from.
+std::string GetDailyRefreshCollectionId(ValueStore* value_store) {
+  if (!value_store)
+    return std::string();
+
+  auto read_result = value_store->Get(kChromeAppDailyRefreshInfoPref);
+
+  if (!read_result.status().ok())
+    return std::string();
+
+  const auto* daily_refresh_info_string =
+      read_result.settings().FindStringKey(kChromeAppDailyRefreshInfoPref);
+
+  if (!daily_refresh_info_string)
+    return std::string();
+
+  const base::Optional<base::Value> daily_refresh_info =
+      base::JSONReader::Read(*daily_refresh_info_string);
+
+  if (!daily_refresh_info)
+    return std::string();
+
+  const auto* collection_id =
+      daily_refresh_info->FindStringKey(kChromeAppCollectionId);
+
+  if (!collection_id)
+    return std::string();
+
+  return *collection_id;
+}
+
 }  // namespace
 
 WallpaperControllerClientImpl::WallpaperControllerClientImpl() {
@@ -439,8 +477,8 @@
 }
 
 void WallpaperControllerClientImpl::MigrateCollectionIdFromValueStoreForTesting(
-    ValueStore* storage) {
-  MigrateCollectionIdFromValueStore(storage);
+    ValueStore* value_store) {
+  SetDailyRefreshCollectionId(GetDailyRefreshCollectionId(value_store));
 }
 
 void WallpaperControllerClientImpl::DeviceWallpaperImageFilePathChanged() {
@@ -551,16 +589,21 @@
   // Although not now, there will be a day where this application no longer
   // exists.
   if (!extension) {
-    wallpaper_controller_->SetDailyRefreshCollectionId(std::string());
+    SetDailyRefreshCollectionId(std::string());
     return;
   }
 
+  // Get a ptr to current sequence.
+  const scoped_refptr<base::SequencedTaskRunner> task_runner =
+      base::SequencedTaskRunnerHandle::Get();
+
   auto* storage_frontend = extensions::StorageFrontend::Get(profile);
+  // Callback runs on a backend sequence.
   storage_frontend->RunWithStorage(
       extension, extensions::settings_namespace::LOCAL,
       base::BindOnce(
-          &WallpaperControllerClientImpl::MigrateCollectionIdFromValueStore,
-          weak_factory_.GetWeakPtr()));
+          &WallpaperControllerClientImpl::OnGetWallpaperChromeAppValueStore,
+          storage_weak_factory_.GetWeakPtr(), task_runner));
 }
 
 bool WallpaperControllerClientImpl::ShouldShowUserNamesOnLogin() const {
@@ -576,40 +619,20 @@
       local_state_->GetString(prefs::kDeviceWallpaperImageFilePath));
 }
 
-void WallpaperControllerClientImpl::MigrateCollectionIdFromValueStore(
-    ValueStore* storage) {
-  using ReadResult = ValueStore::ReadResult;
+void WallpaperControllerClientImpl::OnGetWallpaperChromeAppValueStore(
+    scoped_refptr<base::SequencedTaskRunner> main_task_runner,
+    ValueStore* value_store) {
+  DCHECK(extensions::IsOnBackendSequence());
+  std::string collection_id = GetDailyRefreshCollectionId(value_store);
+  // Jump back to original task runner.
+  main_task_runner->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          &WallpaperControllerClientImpl::SetDailyRefreshCollectionId,
+          weak_factory_.GetWeakPtr(), collection_id));
+}
 
-  if (!storage) {
-    wallpaper_controller_->SetDailyRefreshCollectionId(std::string());
-    return;
-  }
-
-  const std::string chrome_app_daily_refresh_info_pref(
-      kChromeAppDailyRefreshInfoPref);
-
-  ReadResult result = storage->Get(chrome_app_daily_refresh_info_pref);
-  if (!result.status().ok()) {
-    wallpaper_controller_->SetDailyRefreshCollectionId(std::string());
-    return;
-  }
-
-  const std::string* daily_refresh_info_string =
-      result.settings().FindStringKey(chrome_app_daily_refresh_info_pref);
-  if (!daily_refresh_info_string) {
-    wallpaper_controller_->SetDailyRefreshCollectionId(std::string());
-    return;
-  }
-
-  const base::Optional<base::Value> daily_refresh_info =
-      base::JSONReader::Read(*daily_refresh_info_string);
-  if (!daily_refresh_info) {
-    wallpaper_controller_->SetDailyRefreshCollectionId(std::string());
-    return;
-  }
-
-  const std::string* collection_id =
-      daily_refresh_info->FindStringKey(kChromeAppCollectionId);
-  wallpaper_controller_->SetDailyRefreshCollectionId(
-      collection_id ? *collection_id : std::string());
+void WallpaperControllerClientImpl::SetDailyRefreshCollectionId(
+    const std::string& collection_id) {
+  wallpaper_controller_->SetDailyRefreshCollectionId(collection_id);
 }
diff --git a/chrome/browser/ui/ash/wallpaper_controller_client_impl.h b/chrome/browser/ui/ash/wallpaper_controller_client_impl.h
index baf63d1..4b389340 100644
--- a/chrome/browser/ui/ash/wallpaper_controller_client_impl.h
+++ b/chrome/browser/ui/ash/wallpaper_controller_client_impl.h
@@ -17,6 +17,10 @@
 class AccountId;
 class ValueStore;
 
+namespace base {
+class SequencedTaskRunner;
+}  // namespace base
+
 // Handles chrome-side wallpaper control alongside the ash-side controller.
 class WallpaperControllerClientImpl : public ash::WallpaperControllerClient {
  public:
@@ -117,12 +121,15 @@
 
   base::FilePath GetDeviceWallpaperImageFilePath();
 
-  // Retrieves the collection id from the value store that backs chrome.storage
-  // for the old chrome app and passes it to wallpaper controller to store.
-  // This differs from |MigrateCollectionIdFromChromeApp|, which gets the value
-  // store associated with the current user to pass into this function, and is
-  // exposed to the wallpaper controller.
-  void MigrateCollectionIdFromValueStore(ValueStore* storage);
+  // Used as callback to |MigrateCollectionIdFromChromeApp|. Called on backend
+  // task runner. Extracts the daily refresh collection id and calls
+  // |SetDailyRefreshCollectionId| on main task runner.
+  void OnGetWallpaperChromeAppValueStore(
+      scoped_refptr<base::SequencedTaskRunner> main_task_runner,
+      ValueStore* value_store);
+
+  // Passes |collection_id| to wallpaper controller on main task runner.
+  void SetDailyRefreshCollectionId(const std::string& collection_id);
 
   // WallpaperController interface in ash.
   ash::WallpaperController* wallpaper_controller_;
@@ -138,6 +145,8 @@
   base::CallbackListSubscription show_user_names_on_signin_subscription_;
 
   base::WeakPtrFactory<WallpaperControllerClientImpl> weak_factory_{this};
+  base::WeakPtrFactory<WallpaperControllerClientImpl> storage_weak_factory_{
+      this};
 
   DISALLOW_COPY_AND_ASSIGN(WallpaperControllerClientImpl);
 };
diff --git a/chrome/browser/ui/aura/accessibility/DEPS b/chrome/browser/ui/aura/accessibility/DEPS
deleted file mode 100644
index 12a5ca5..0000000
--- a/chrome/browser/ui/aura/accessibility/DEPS
+++ /dev/null
@@ -1,6 +0,0 @@
-specific_include_rules = {
-  "automation_manager_aura\.cc": [
-    "+ash/shell.h",
-    "+ash/wm/window_util.h",
-  ],
-}
diff --git a/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc b/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc
index 437d515..93ac3bd 100644
--- a/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc
+++ b/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc
@@ -32,12 +32,7 @@
 #include "ui/views/view.h"
 #include "ui/views/widget/widget.h"
 #include "ui/wm/core/coordinate_conversion.h"
-
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "ash/public/cpp/shell_window_ids.h"
-#include "ash/shell.h"
-#include "ash/wm/window_util.h"
-#endif
+#include "ui/wm/public/activation_client.h"
 
 // static
 AutomationManagerAura* AutomationManagerAura::GetInstance() {
@@ -49,13 +44,13 @@
   enabled_ = true;
   Reset(false);
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Seed the views::AXAuraObjCache with per-display root windows so
   // GetTopLevelWindows() returns the correct values when automation is enabled
   // with multiple displays connected.
-  for (aura::Window* root : ash::Shell::GetAllRootWindows())
-    cache_->OnRootWindowObjCreated(root);
-#endif
+  if (send_window_state_on_enable_) {
+    for (auto* host : aura::Env::GetInstance()->window_tree_hosts())
+      cache_->OnRootWindowObjCreated(host->window());
+  }
 
   // Send this event immediately to push the initial desktop tree state.
   pending_events_.push_back({tree_->GetRoot()->GetUniqueId(),
@@ -66,14 +61,26 @@
   // ordering of two base::Singletons.
   cache_->SetDelegate(this);
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  aura::Window* active_window = ash::window_util::GetActiveWindow();
+  const display::Display& display =
+      display::Screen::GetScreen()->GetPrimaryDisplay();
+  aura::Window* root_window = nullptr;
+  for (auto* host : aura::Env::GetInstance()->window_tree_hosts()) {
+    if (display.id() == host->GetDisplayId()) {
+      root_window = host->window();
+      break;
+    }
+  }
+
+  aura::Window* active_window = nullptr;
+  if (root_window) {
+    active_window = ::wm::GetActivationClient(root_window)->GetActiveWindow();
+  }
+
   if (active_window) {
     views::AXAuraObjWrapper* focus = cache_->GetOrCreate(active_window);
     if (focus)
       PostEvent(focus->GetUniqueId(), ax::mojom::Event::kChildrenChanged);
   }
-#endif
 
   if (!automation_event_router_observer_.IsObserving() &&
       !automation_event_router_interface_) {
@@ -206,15 +213,12 @@
     alert_window_.reset();
   } else {
     tree_serializer_ = std::make_unique<AuraAXTreeSerializer>(tree_.get());
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-    ash::Shell* shell = ash::Shell::Get();
-    // Windows within the overlay container get moved to the new monitor when
-    // the primary display gets swapped.
-    alert_window_ = std::make_unique<views::AccessibilityAlertWindow>(
-        shell->GetContainer(shell->GetPrimaryRootWindow(),
-                            ash::kShellWindowId_OverlayContainer),
-        cache_.get());
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
+    const auto& hosts = aura::Env::GetInstance()->window_tree_hosts();
+    if (!hosts.empty()) {
+      alert_window_ = std::make_unique<views::AccessibilityAlertWindow>(
+          hosts[0]->window(), cache_.get());
+    }
   }
 }
 
diff --git a/chrome/browser/ui/aura/accessibility/automation_manager_aura.h b/chrome/browser/ui/aura/accessibility/automation_manager_aura.h
index 6fa1d49..4b93f966 100644
--- a/chrome/browser/ui/aura/accessibility/automation_manager_aura.h
+++ b/chrome/browser/ui/aura/accessibility/automation_manager_aura.h
@@ -152,6 +152,8 @@
                           extensions::AutomationEventRouterObserver>
       automation_event_router_observer_{this};
 
+  bool send_window_state_on_enable_ = true;
+
   DISALLOW_COPY_AND_ASSIGN(AutomationManagerAura);
 };
 
diff --git a/chrome/browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc b/chrome/browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc
index 0a34084..fcc5eb6d 100644
--- a/chrome/browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc
+++ b/chrome/browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc
@@ -491,6 +491,7 @@
   auto cache = std::make_unique<views::AXAuraObjCache>();
   auto* cache_ptr = cache.get();
   AutomationManagerAura* manager = AutomationManagerAura::GetInstance();
+  manager->send_window_state_on_enable_ = false;
   manager->set_ax_aura_obj_cache_for_testing(std::move(cache));
   AutomationEventWaiter waiter;
   manager->Enable();
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index 2e7499c..dca4b61 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -97,6 +97,7 @@
 #include "chrome/browser/ui/autofill/payments/offer_notification_bubble_controller_impl.h"
 #include "chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.h"
 #include "chrome/browser/ui/autofill/payments/save_upi_bubble_controller_impl.h"
+#include "chrome/browser/ui/autofill/payments/virtual_card_manual_fallback_bubble_controller_impl.h"
 #include "chrome/browser/ui/autofill/payments/virtual_card_selection_dialog_controller_impl.h"
 #include "chrome/browser/ui/autofill/payments/webauthn_dialog_controller_impl.h"
 #include "chrome/browser/ui/autofill/payments/webauthn_dialog_state.h"
@@ -683,6 +684,19 @@
 #endif
 }
 
+void ChromeAutofillClient::ShowVirtualCardManualFallbackBubble(
+    const CreditCard* credit_card,
+    const std::u16string& cvc) {
+#if !defined(OS_ANDROID)  // Desktop only
+  VirtualCardManualFallbackBubbleControllerImpl::CreateForWebContents(
+      web_contents());
+  VirtualCardManualFallbackBubbleControllerImpl* controller =
+      VirtualCardManualFallbackBubbleControllerImpl::FromWebContents(
+          web_contents());
+  controller->ShowBubble(credit_card, cvc);
+#endif
+}
+
 bool ChromeAutofillClient::IsAutofillAssistantShowing() {
   auto* assistant_runtime_manager =
       autofill_assistant::RuntimeManager::GetForWebContents(web_contents());
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.h b/chrome/browser/ui/autofill/chrome_autofill_client.h
index 9c7ea436..e2f8e14 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.h
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.h
@@ -150,6 +150,8 @@
   void HideAutofillPopup(PopupHidingReason reason) override;
   void ShowOfferNotificationIfApplicable(
       const AutofillOfferData* offer) override;
+  void ShowVirtualCardManualFallbackBubble(const CreditCard* card,
+                                           const std::u16string& cvc) override;
   bool IsAutofillAssistantShowing() override;
   bool IsAutocompleteEnabled() override;
   void PropagateAutofillPredictions(
diff --git a/chrome/browser/ui/global_media_controls/media_session_notification_producer.cc b/chrome/browser/ui/global_media_controls/media_session_notification_producer.cc
index 8439d4a..cedd279c 100644
--- a/chrome/browser/ui/global_media_controls/media_session_notification_producer.cc
+++ b/chrome/browser/ui/global_media_controls/media_session_notification_producer.cc
@@ -437,18 +437,10 @@
 
   it->second.OnSessionInteractedWith();
 
-  content::WebContents* web_contents = it->second.web_contents();
-  if (!web_contents)
-    return;
-
-  content::WebContentsDelegate* delegate = web_contents->GetDelegate();
-  if (!delegate)
-    return;
-
   base::UmaHistogramEnumeration("Media.Notification.Click",
                                 MediaNotificationClickSource::kMedia);
 
-  delegate->ActivateContents(web_contents);
+  it->second.item()->Raise();
 }
 
 void MediaSessionNotificationProducer::OnContainerDismissed(
diff --git a/chrome/browser/ui/qrcode_generator/qrcode_generator_bubble_controller.cc b/chrome/browser/ui/qrcode_generator/qrcode_generator_bubble_controller.cc
index 60c1ae3..311e640 100644
--- a/chrome/browser/ui/qrcode_generator/qrcode_generator_bubble_controller.cc
+++ b/chrome/browser/ui/qrcode_generator/qrcode_generator_bubble_controller.cc
@@ -21,9 +21,6 @@
 
 // static
 bool QRCodeGeneratorBubbleController::IsGeneratorAvailable(const GURL& url) {
-  if (!base::FeatureList::IsEnabled(kSharingQRCodeGenerator))
-    return false;
-
   if (!url.SchemeIsHTTPOrHTTPS())
     return false;
 
diff --git a/chrome/browser/ui/qrcode_generator/qrcode_generator_bubble_controller_unittest.cc b/chrome/browser/ui/qrcode_generator/qrcode_generator_bubble_controller_unittest.cc
index bfc9872..34ebc50 100644
--- a/chrome/browser/ui/qrcode_generator/qrcode_generator_bubble_controller_unittest.cc
+++ b/chrome/browser/ui/qrcode_generator/qrcode_generator_bubble_controller_unittest.cc
@@ -18,16 +18,11 @@
 
   ~QRCodeGeneratorBubbleControllerTest() override = default;
 
- protected:
-  base::test::ScopedFeatureList scoped_feature_list_;
-
  private:
   DISALLOW_COPY_AND_ASSIGN(QRCodeGeneratorBubbleControllerTest);
 };
 
 TEST_F(QRCodeGeneratorBubbleControllerTest, AllowedURLs) {
-  scoped_feature_list_.InitAndEnableFeature(kSharingQRCodeGenerator);
-
   // Allow valid http/https URLs.
   ASSERT_TRUE(QRCodeGeneratorBubbleController::IsGeneratorAvailable(
       GURL("http://www.example.com")));
@@ -50,16 +45,4 @@
       QRCodeGeneratorBubbleController::IsGeneratorAvailable(GURL("NotAURL")));
 }
 
-TEST_F(QRCodeGeneratorBubbleControllerTest, UnavailableWithFeatureOff) {
-  scoped_feature_list_.InitAndDisableFeature(kSharingQRCodeGenerator);
-
-  // Normally-available URLs should not be allowed when the feature is off.
-  ASSERT_FALSE(QRCodeGeneratorBubbleController::IsGeneratorAvailable(
-      GURL("http://www.example.com")));
-  ASSERT_FALSE(QRCodeGeneratorBubbleController::IsGeneratorAvailable(
-      GURL("https://www.example.com")));
-  ASSERT_FALSE(QRCodeGeneratorBubbleController::IsGeneratorAvailable(
-      GURL("https://www.example.com/path?q=abc")));
-}
-
 }  // namespace qrcode_generator
diff --git a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc
index ad13ff1..9423ce9 100644
--- a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc
+++ b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc
@@ -543,9 +543,13 @@
   InsertItemAt(curr_model_index, command_id,
                title.empty() ? base::UTF8ToUTF16(item.url.spec()) : title);
   AddTabFavicon(command_id, item.url);
+  int header_index = GetIndexOfCommandId(kRecentlyClosedHeaderCommandId);
+  // We shouldn't get here if there is no recently closed header.
+  DCHECK_GT(header_index, -1);
   // visual_data should only be populated if the tab was part of a tab group
-  // when closed.
-  if (visual_data.has_value()) {
+  // when closed. We shouldn't set the minor icon for the item most recently
+  // closed, as this creates visual clutter alongside the shortcut text.
+  if (visual_data.has_value() && curr_model_index > header_index + 1) {
     const auto& theme =
         ThemeService::GetThemeProviderForProfile(browser_->profile());
     const int color_id =
diff --git a/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc b/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc
index 79697dd..cd37da9 100644
--- a/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc
+++ b/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc
@@ -794,6 +794,13 @@
 
   // Clicking the first notification should make the first tab active.
   ClickNotificationByTitle(u"Big Buck Bunny");
+
+  // Allow the MediaSessionNotificationItem to flush its message to the
+  // MediaSessionImpl. There isn't currently a clean way for us to access the
+  // MediaSessionNotificationItem directly to force it to flush, so we use this
+  // non-ideal |RunUntilIdle()| call instead.
+  base::RunLoop().RunUntilIdle();
+
   EXPECT_EQ(first_web_contents, GetActiveWebContents());
 }
 
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc
index 7b05cfb1..44f81c1 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -265,8 +265,7 @@
     // the left most icon.
     params.types_enabled.push_back(PageActionIconType::kSendTabToSelf);
     params.types_enabled.push_back(PageActionIconType::kClickToCall);
-    if (base::FeatureList::IsEnabled(kSharingQRCodeGenerator))
-      params.types_enabled.push_back(PageActionIconType::kQRCodeGenerator);
+    params.types_enabled.push_back(PageActionIconType::kQRCodeGenerator);
     if (base::FeatureList::IsEnabled(kSharedClipboardUI))
       params.types_enabled.push_back(PageActionIconType::kSharedClipboard);
     if (base::FeatureList::IsEnabled(sharing_hub::kSharingHubDesktopOmnibox))
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
index 521e0c5..1f127e1 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -1629,13 +1629,8 @@
 void OmniboxViewViews::OnGestureEvent(ui::GestureEvent* event) {
   PermitExternalProtocolHandler();
 
-  static const bool kTakeFocusOnTapUp =
-      base::FeatureList::IsEnabled(views::features::kTextfieldFocusOnTapUp);
-
   const bool gesture_should_take_focus =
-      !HasFocus() &&
-      event->type() ==
-          (kTakeFocusOnTapUp ? ui::ET_GESTURE_TAP : ui::ET_GESTURE_TAP_DOWN);
+      !HasFocus() && event->type() == ui::ET_GESTURE_TAP;
   if (gesture_should_take_focus) {
     select_all_on_gesture_tap_ = true;
 
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc
index db599830..4d55b1e 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc
@@ -336,18 +336,10 @@
 
   // Take the focus away and tap in the omnibox again, but drag a bit before
   // releasing. This shouldn't select text.
-  //
-  // Whether it'll focus depends on the state of the below feature: touch and
-  // drag will send a tap-down event, then a scroll or swipe event, but no
-  // complete tap event. When enabled, textfields will take focus on a complete
-  // tap instead of tap-down.
-  const bool focused_after_drag =
-      !base::FeatureList::IsEnabled(views::features::kTextfieldFocusOnTapUp);
   ASSERT_NO_FATAL_FAILURE(
       ui_test_utils::ClickOnView(browser(), VIEW_ID_TAB_CONTAINER));
   ASSERT_NO_FATAL_FAILURE(Tap(tap_location, tap2_location));
-  EXPECT_EQ(focused_after_drag,
-            ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
+  EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
   EXPECT_FALSE(omnibox_view->IsSelectAll());
 }
 
diff --git a/chrome/browser/ui/views/qrcode_generator/qrcode_generator_bubble.cc b/chrome/browser/ui/views/qrcode_generator/qrcode_generator_bubble.cc
index f6c1328..028fc62 100644
--- a/chrome/browser/ui/views/qrcode_generator/qrcode_generator_bubble.cc
+++ b/chrome/browser/ui/views/qrcode_generator/qrcode_generator_bubble.cc
@@ -290,12 +290,10 @@
   column_set_bottom_error_label->AddColumn(
       views::GridLayout::FILL, views::GridLayout::CENTER, 1.0,
       views::GridLayout::ColumnSize::kUsePreferred, 0, 0);
-  // User-facing limit rounded down for readability.
-  int max_url_length = base::GetFieldTrialParamByFeatureAsInt(
-      kSharingQRCodeGenerator, "max_url_length", 250);
+  // User-facing limit rounded down to 250 characters for readability.
   auto bottom_error_label = std::make_unique<views::Label>(
       l10n_util::GetStringFUTF16Int(
-          IDS_BROWSER_SHARING_QR_CODE_DIALOG_ERROR_TOO_LONG, max_url_length),
+          IDS_BROWSER_SHARING_QR_CODE_DIALOG_ERROR_TOO_LONG, 250),
       views::style::CONTEXT_LABEL, views::style::STYLE_SECONDARY);
   bottom_error_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
   bottom_error_label->SetVisible(false);
diff --git a/chrome/browser/ui/views/webauthn/authenticator_dialog_view_browsertest.cc b/chrome/browser/ui/views/webauthn/authenticator_dialog_view_browsertest.cc
index 4add1a0c..af921ae8 100644
--- a/chrome/browser/ui/views/webauthn/authenticator_dialog_view_browsertest.cc
+++ b/chrome/browser/ui/views/webauthn/authenticator_dialog_view_browsertest.cc
@@ -112,7 +112,7 @@
 
     auto dialog_model = std::make_unique<AuthenticatorRequestDialogModel>(
         /*relying_party_id=*/"example.com");
-    dialog_model->SetCurrentStep(
+    dialog_model->SetCurrentStepForTesting(
         AuthenticatorRequestDialogModel::Step::kTimedOut);
     AuthenticatorRequestDialogView* dialog =
         test::AuthenticatorRequestDialogViewTestApi::CreateDialogView(
diff --git a/chrome/browser/ui/views/webauthn/authenticator_transport_selector_sheet_view.cc b/chrome/browser/ui/views/webauthn/authenticator_transport_selector_sheet_view.cc
index 309533d..7699e64f 100644
--- a/chrome/browser/ui/views/webauthn/authenticator_transport_selector_sheet_view.cc
+++ b/chrome/browser/ui/views/webauthn/authenticator_transport_selector_sheet_view.cc
@@ -4,12 +4,6 @@
 
 #include "chrome/browser/ui/views/webauthn/authenticator_transport_selector_sheet_view.h"
 
-#include <utility>
-
-#include "base/containers/contains.h"
-#include "chrome/browser/webauthn/authenticator_transport.h"
-#include "device/fido/features.h"
-
 AuthenticatorTransportSelectorSheetView::
     AuthenticatorTransportSelectorSheetView(
         std::unique_ptr<AuthenticatorTransportSelectorSheetModel> model)
@@ -21,39 +15,8 @@
 std::pair<std::unique_ptr<views::View>,
           AuthenticatorRequestSheetView::AutoFocus>
 AuthenticatorTransportSelectorSheetView::BuildStepSpecificContent() {
-  AuthenticatorRequestDialogModel* const dialog_model = model()->dialog_model();
-  base::flat_set<AuthenticatorTransport> transports =
-      dialog_model->available_transports();
-
-  std::vector<std::string> phone_names;
-  if (base::Contains(
-          transports,
-          device::FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy)) {
-    phone_names = dialog_model->paired_phone_names();
-
-    // The generic phone option is not shown unless a caBLE extension was
-    // provided because it's the extension which denotes what a "default" phone
-    // is.
-    bool show_generic_phone;
-    switch (dialog_model->cable_ui_type()) {
-      case AuthenticatorRequestDialogModel::CableUIType::CABLE_V1:
-      case AuthenticatorRequestDialogModel::CableUIType::CABLE_V2_SERVER_LINK:
-        show_generic_phone = true;
-        break;
-      case AuthenticatorRequestDialogModel::CableUIType::CABLE_V2_2ND_FACTOR:
-        show_generic_phone = false;
-        break;
-    }
-
-    if (!show_generic_phone) {
-      transports.erase(
-          device::FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy);
-    }
-  }
-
   return std::make_pair(
       std::make_unique<HoverListView>(std::make_unique<TransportHoverListModel>(
-          transports, dialog_model->win_native_api_enabled(),
-          std::move(phone_names), model())),
+          model()->dialog_model()->mechanisms())),
       AutoFocus::kYes);
 }
diff --git a/chrome/browser/ui/webauthn/authenticator_dialog_browsertest.cc b/chrome/browser/ui/webauthn/authenticator_dialog_browsertest.cc
index c4399b7e..22f2aa3 100644
--- a/chrome/browser/ui/webauthn/authenticator_dialog_browsertest.cc
+++ b/chrome/browser/ui/webauthn/authenticator_dialog_browsertest.cc
@@ -46,53 +46,63 @@
       transport_availability.available_transports.insert(
           AuthenticatorTransport::kAndroidAccessory);
     }
-    model->set_cable_transport_info(
-        /*extension_is_v2=*/false,
-        /*paired_phones=*/{},
-        /*contact_phone_callback=*/base::DoNothing(), "fido://qrcode");
+    transport_availability.has_recognized_platform_authenticator_credential =
+        false;
+    transport_availability.request_type =
+        device::FidoRequestType::kGetAssertion;
     model->StartFlow(std::move(transport_availability),
                      /*use_location_bar_bubble=*/false);
 
     // The dialog should immediately close as soon as it is displayed.
     if (name == "transports") {
-      model->SetCurrentStep(
+      model->SetCurrentStepForTesting(
           AuthenticatorRequestDialogModel::Step::kTransportSelection);
     } else if (name == "activate_usb") {
-      model->SetCurrentStep(
+      model->SetCurrentStepForTesting(
           AuthenticatorRequestDialogModel::Step::kUsbInsertAndActivate);
     } else if (name == "timeout") {
-      model->SetCurrentStep(AuthenticatorRequestDialogModel::Step::kTimedOut);
+      model->SetCurrentStepForTesting(
+          AuthenticatorRequestDialogModel::Step::kTimedOut);
     } else if (name == "no_available_transports") {
-      model->SetCurrentStep(
+      model->SetCurrentStepForTesting(
           AuthenticatorRequestDialogModel::Step::kErrorNoAvailableTransports);
     } else if (name == "key_not_registered") {
-      model->SetCurrentStep(
+      model->SetCurrentStepForTesting(
           AuthenticatorRequestDialogModel::Step::kKeyNotRegistered);
     } else if (name == "key_already_registered") {
-      model->SetCurrentStep(
+      model->SetCurrentStepForTesting(
           AuthenticatorRequestDialogModel::Step::kKeyAlreadyRegistered);
     } else if (name == "internal_unrecognized_error") {
-      model->SetCurrentStep(
+      model->SetCurrentStepForTesting(
           AuthenticatorRequestDialogModel::Step::kErrorInternalUnrecognized);
     } else if (name == "ble_power_on_manual") {
-      model->SetCurrentStep(
+      model->SetCurrentStepForTesting(
           AuthenticatorRequestDialogModel::Step::kBlePowerOnManual);
     } else if (name == "touchid_incognito") {
-      model->SetCurrentStep(AuthenticatorRequestDialogModel::Step::
-                                kPlatformAuthenticatorOffTheRecordInterstitial);
+      model->SetCurrentStepForTesting(
+          AuthenticatorRequestDialogModel::Step::
+              kPlatformAuthenticatorOffTheRecordInterstitial);
     } else if (name == "cable_activate" ||
                name == "cable_server_link_activate") {
-      model->SetCurrentStep(
+      model->set_cable_transport_info(
+          /*extension_is_v2=*/false,
+          /*paired_phones=*/{},
+          /*contact_phone_callback=*/base::DoNothing(), "fido://qrcode");
+      model->SetCurrentStepForTesting(
           AuthenticatorRequestDialogModel::Step::kCableActivate);
     } else if (name == "cable_v2_activate") {
       model->set_cable_transport_info(
           /*extension_is_v2=*/base::nullopt,
           /*paired_phones=*/{},
           /*contact_phone_callback=*/base::DoNothing(), "fido://qrcode");
-      model->SetCurrentStep(
+      model->SetCurrentStepForTesting(
           AuthenticatorRequestDialogModel::Step::kCableActivate);
     } else if (name == "cable_v2_pair") {
-      model->SetCurrentStep(
+      model->set_cable_transport_info(
+          /*extension_is_v2=*/base::nullopt,
+          /*paired_phones=*/{},
+          /*contact_phone_callback=*/base::DoNothing(), "fido://qrcode");
+      model->SetCurrentStepForTesting(
           AuthenticatorRequestDialogModel::Step::kCableV2QRCode);
     } else if (name == "set_pin") {
       model->CollectPIN(device::pin::PINEntryReason::kSet,
@@ -143,22 +153,22 @@
                         device::pin::PINEntryError::kSameAsCurrentPIN, 6, 0,
                         base::BindOnce([](std::u16string pin) {}));
     } else if (name == "second_tap") {
-      model->SetCurrentStep(
+      model->SetCurrentStepForTesting(
           AuthenticatorRequestDialogModel::Step::kClientPinTapAgain);
     } else if (name == "soft_block") {
-      model->SetCurrentStep(
+      model->SetCurrentStepForTesting(
           AuthenticatorRequestDialogModel::Step::kClientPinErrorSoftBlock);
     } else if (name == "hard_block") {
-      model->SetCurrentStep(
+      model->SetCurrentStepForTesting(
           AuthenticatorRequestDialogModel::Step::kClientPinErrorHardBlock);
     } else if (name == "authenticator_removed") {
-      model->SetCurrentStep(AuthenticatorRequestDialogModel::Step::
-                                kClientPinErrorAuthenticatorRemoved);
+      model->SetCurrentStepForTesting(AuthenticatorRequestDialogModel::Step::
+                                          kClientPinErrorAuthenticatorRemoved);
     } else if (name == "missing_capability") {
-      model->SetCurrentStep(
+      model->SetCurrentStepForTesting(
           AuthenticatorRequestDialogModel::Step::kMissingCapability);
     } else if (name == "storage_full") {
-      model->SetCurrentStep(
+      model->SetCurrentStepForTesting(
           AuthenticatorRequestDialogModel::Step::kStorageFull);
     } else if (name == "account_select") {
       // These strings attempt to exercise the encoding of direction and
diff --git a/chrome/browser/ui/webauthn/other_transports_menu_model.cc b/chrome/browser/ui/webauthn/other_transports_menu_model.cc
index 41a4b8b6..4305ea5 100644
--- a/chrome/browser/ui/webauthn/other_transports_menu_model.cc
+++ b/chrome/browser/ui/webauthn/other_transports_menu_model.cc
@@ -4,84 +4,35 @@
 
 #include "chrome/browser/ui/webauthn/other_transports_menu_model.h"
 
-#include "base/numerics/safe_conversions.h"
-#include "chrome/browser/ui/webauthn/transport_utils.h"
-#include "chrome/grit/generated_resources.h"
-#include "ui/base/l10n/l10n_util.h"
+#include "chrome/browser/webauthn/authenticator_request_dialog_model.h"
 #include "ui/base/models/image_model.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/paint_vector_icon.h"
 
-namespace {
-
-gfx::ImageSkia GetTransportIcon(AuthenticatorTransport transport) {
-  constexpr int kTransportIconSize = 16;
-  // TODO (kylixrd): Review the use of the hard-coded color for possible change
-  // to using a ColorProvider color id.
-  return gfx::CreateVectorIcon(*GetTransportVectorIcon(transport),
-                               kTransportIconSize, gfx::kGoogleGrey700);
-}
-
-}  // namespace
-
 OtherTransportsMenuModel::OtherTransportsMenuModel(
-    AuthenticatorRequestDialogModel* dialog_model,
-    AuthenticatorTransport current_transport)
+    AuthenticatorRequestDialogModel* dialog_model)
     : ui::SimpleMenuModel(this), dialog_model_(dialog_model) {
-  DCHECK(dialog_model);
-  dialog_model_->AddObserver(this);
+  base::span<const AuthenticatorRequestDialogModel::Mechanism> mechanisms =
+      dialog_model->mechanisms();
+  const base::Optional<size_t> current_mechanism =
+      dialog_model->current_mechanism();
 
-#if defined(OS_WIN)
-  // During the caBLE dialog, if the native Windows authenticator is available,
-  // show a single pseudo transport value for switching to the native Windows
-  // option.
-  if (dialog_model_->transport_availability()
-          ->has_win_native_api_authenticator) {
-    DCHECK(current_transport ==
-           AuthenticatorTransport::kCloudAssistedBluetoothLowEnergy);
-    AppendItemForNativeWinApi();
-    return;
-  }
-#endif  // defined(OS_WIN)
-
-  PopulateWithTransportsExceptFor(current_transport);
-}
-
-OtherTransportsMenuModel::~OtherTransportsMenuModel() {
-  if (dialog_model_) {
-    dialog_model_->RemoveObserver(this);
-    dialog_model_ = nullptr;
-  }
-}
-
-void OtherTransportsMenuModel::PopulateWithTransportsExceptFor(
-    AuthenticatorTransport current_transport) {
-  for (const auto transport :
-       dialog_model_->transport_availability()->available_transports) {
-    if (transport == current_transport) {
+  constexpr int kTransportIconSize = 16;
+  for (size_t i = 0; i < mechanisms.size(); i++) {
+    if (current_mechanism && i == *current_mechanism) {
       continue;
     }
 
-    auto name = GetTransportHumanReadableName(
-        transport, TransportSelectionContext::kOtherTransportsMenu);
-    AddItemWithIcon(base::strict_cast<int>(transport), std::move(name),
-                    ui::ImageModel::FromImageSkia(GetTransportIcon(transport)));
+    const auto& m = mechanisms[i];
+    AddItemWithIcon(static_cast<int>(i), m.short_name,
+                    // TODO (kylixrd): Review the use of the hard-coded color
+                    // for possible change to using a ColorProvider color id.
+                    ui::ImageModel::FromImageSkia(gfx::CreateVectorIcon(
+                        *m.icon, kTransportIconSize, gfx::kGoogleGrey700)));
   }
 }
 
-#if defined(OS_WIN)
-// Magic command ID for calling AbandonFlowAndDispatchToNativeWindowsApi().
-// This must not be a defined AuthenticatorTransport value.
-constexpr int kWinNativeApiMenuCommand = 999;
-
-void OtherTransportsMenuModel::AppendItemForNativeWinApi() {
-  AddItemWithIcon(kWinNativeApiMenuCommand,
-                  l10n_util::GetStringUTF16(
-                      IDS_WEBAUTHN_TRANSPORT_POPUP_DIFFERENT_AUTHENTICATOR_WIN),
-                  ui::ImageModel::FromImageSkia(GetTransportIcon(
-                      AuthenticatorTransport::kUsbHumanInterfaceDevice)));
-}
-#endif  // defined(OS_WIN)
+OtherTransportsMenuModel::~OtherTransportsMenuModel() = default;
 
 bool OtherTransportsMenuModel::IsCommandIdChecked(int command_id) const {
   return false;
@@ -92,25 +43,5 @@
 }
 
 void OtherTransportsMenuModel::ExecuteCommand(int command_id, int event_flags) {
-  DCHECK(dialog_model_);
-
-#if defined(OS_WIN)
-  if (command_id == kWinNativeApiMenuCommand) {
-    DCHECK(dialog_model_->transport_availability()
-               ->has_win_native_api_authenticator);
-    dialog_model_->HideDialogAndDispatchToNativeWindowsApi();
-    return;
-  }
-#endif  // defined(OS_WIN)
-
-  AuthenticatorTransport selected_transport =
-      static_cast<AuthenticatorTransport>(command_id);
-
-  dialog_model_->StartGuidedFlowForTransport(selected_transport);
-}
-
-void OtherTransportsMenuModel::OnModelDestroyed(
-    AuthenticatorRequestDialogModel* model) {
-  DCHECK(model == dialog_model_);
-  dialog_model_ = nullptr;
+  dialog_model_->mechanisms()[command_id].callback.Run();
 }
diff --git a/chrome/browser/ui/webauthn/other_transports_menu_model.h b/chrome/browser/ui/webauthn/other_transports_menu_model.h
index 4e54beb..6d0d1bee 100644
--- a/chrome/browser/ui/webauthn/other_transports_menu_model.h
+++ b/chrome/browser/ui/webauthn/other_transports_menu_model.h
@@ -5,22 +5,20 @@
 #ifndef CHROME_BROWSER_UI_WEBAUTHN_OTHER_TRANSPORTS_MENU_MODEL_H_
 #define CHROME_BROWSER_UI_WEBAUTHN_OTHER_TRANSPORTS_MENU_MODEL_H_
 
-#include "build/build_config.h"
-#include "chrome/browser/webauthn/authenticator_request_dialog_model.h"
 #include "ui/base/models/simple_menu_model.h"
 
+class AuthenticatorRequestDialogModel;
+
 // The model of the pop-up menu shown when `Choose another option` is clicked.
 //
 // This pop-up menu is available on several sheets instructing the user to
 // activate their security key over a given transport, and allows the user to
 // instead use a different transport protocol.
-class OtherTransportsMenuModel
-    : public ui::SimpleMenuModel,
-      public ui::SimpleMenuModel::Delegate,
-      public AuthenticatorRequestDialogModel::Observer {
+class OtherTransportsMenuModel : public ui::SimpleMenuModel,
+                                 public ui::SimpleMenuModel::Delegate {
  public:
-  OtherTransportsMenuModel(AuthenticatorRequestDialogModel* dialog_model,
-                           AuthenticatorTransport current_transport);
+  explicit OtherTransportsMenuModel(
+      AuthenticatorRequestDialogModel* dialog_model);
   ~OtherTransportsMenuModel() override;
 
  protected:
@@ -29,19 +27,7 @@
   bool IsCommandIdEnabled(int command_id) const override;
   void ExecuteCommand(int command_id, int event_flags) override;
 
-  // AuthenticatorRequestDialogModel::Observer:
-  void OnModelDestroyed(AuthenticatorRequestDialogModel* model) override;
-
- private:
-  // Appends all available transports except the |current_transport|
-  void PopulateWithTransportsExceptFor(
-      AuthenticatorTransport current_transport);
-
-#if defined(OS_WIN)
-  void AppendItemForNativeWinApi();
-#endif
-
-  AuthenticatorRequestDialogModel* dialog_model_;
+  AuthenticatorRequestDialogModel* const dialog_model_;
 
   DISALLOW_COPY_AND_ASSIGN(OtherTransportsMenuModel);
 };
diff --git a/chrome/browser/ui/webauthn/sheet_models.cc b/chrome/browser/ui/webauthn/sheet_models.cc
index 4a551a1..d47a157 100644
--- a/chrome/browser/ui/webauthn/sheet_models.cc
+++ b/chrome/browser/ui/webauthn/sheet_models.cc
@@ -149,29 +149,14 @@
       IDS_WEBAUTHN_TRANSPORT_SELECTION_DESCRIPTION);
 }
 
-void AuthenticatorTransportSelectorSheetModel::OnTransportSelected(
-    AuthenticatorTransport transport) {
-  dialog_model()->StartGuidedFlowForTransport(transport);
-}
-
-void AuthenticatorTransportSelectorSheetModel::StartWinNativeApi() {
-  dialog_model()->StartWinNativeApi();
-}
-
-void AuthenticatorTransportSelectorSheetModel::ContactPhone(
-    const std::string& name) {
-  dialog_model()->ContactPhone(name);
-}
-
 // AuthenticatorInsertAndActivateUsbSheetModel ----------------------
 
 AuthenticatorInsertAndActivateUsbSheetModel::
     AuthenticatorInsertAndActivateUsbSheetModel(
         AuthenticatorRequestDialogModel* dialog_model)
     : AuthenticatorSheetModelBase(dialog_model),
-      other_transports_menu_model_(std::make_unique<OtherTransportsMenuModel>(
-          dialog_model,
-          AuthenticatorTransport::kUsbHumanInterfaceDevice)) {}
+      other_transports_menu_model_(
+          std::make_unique<OtherTransportsMenuModel>(dialog_model)) {}
 
 AuthenticatorInsertAndActivateUsbSheetModel::
     ~AuthenticatorInsertAndActivateUsbSheetModel() = default;
@@ -492,9 +477,8 @@
     AuthenticatorOffTheRecordInterstitialSheetModel(
         AuthenticatorRequestDialogModel* dialog_model)
     : AuthenticatorSheetModelBase(dialog_model),
-      other_transports_menu_model_(std::make_unique<OtherTransportsMenuModel>(
-          dialog_model,
-          AuthenticatorTransport::kInternal)) {}
+      other_transports_menu_model_(
+          std::make_unique<OtherTransportsMenuModel>(dialog_model)) {}
 
 AuthenticatorOffTheRecordInterstitialSheetModel::
     ~AuthenticatorOffTheRecordInterstitialSheetModel() = default;
@@ -554,9 +538,8 @@
 AuthenticatorPaaskSheetModel::AuthenticatorPaaskSheetModel(
     AuthenticatorRequestDialogModel* dialog_model)
     : AuthenticatorSheetModelBase(dialog_model),
-      other_transports_menu_model_(std::make_unique<OtherTransportsMenuModel>(
-          dialog_model,
-          AuthenticatorTransport::kCloudAssistedBluetoothLowEnergy)) {}
+      other_transports_menu_model_(
+          std::make_unique<OtherTransportsMenuModel>(dialog_model)) {}
 
 AuthenticatorPaaskSheetModel::~AuthenticatorPaaskSheetModel() = default;
 
@@ -619,9 +602,8 @@
     AuthenticatorAndroidAccessorySheetModel(
         AuthenticatorRequestDialogModel* dialog_model)
     : AuthenticatorSheetModelBase(dialog_model),
-      other_transports_menu_model_(std::make_unique<OtherTransportsMenuModel>(
-          dialog_model,
-          AuthenticatorTransport::kAndroidAccessory)) {}
+      other_transports_menu_model_(
+          std::make_unique<OtherTransportsMenuModel>(dialog_model)) {}
 
 AuthenticatorAndroidAccessorySheetModel::
     ~AuthenticatorAndroidAccessorySheetModel() = default;
@@ -660,9 +642,8 @@
 AuthenticatorPaaskV2SheetModel::AuthenticatorPaaskV2SheetModel(
     AuthenticatorRequestDialogModel* dialog_model)
     : AuthenticatorSheetModelBase(dialog_model),
-      other_transports_menu_model_(std::make_unique<OtherTransportsMenuModel>(
-          dialog_model,
-          AuthenticatorTransport::kCloudAssistedBluetoothLowEnergy)) {}
+      other_transports_menu_model_(
+          std::make_unique<OtherTransportsMenuModel>(dialog_model)) {}
 
 AuthenticatorPaaskV2SheetModel::~AuthenticatorPaaskV2SheetModel() = default;
 
diff --git a/chrome/browser/ui/webauthn/sheet_models.h b/chrome/browser/ui/webauthn/sheet_models.h
index 54cbf21..b2a470392 100644
--- a/chrome/browser/ui/webauthn/sheet_models.h
+++ b/chrome/browser/ui/webauthn/sheet_models.h
@@ -68,16 +68,10 @@
 // The sheet shown for selecting the transport over which the security key
 // should be accessed.
 class AuthenticatorTransportSelectorSheetModel
-    : public AuthenticatorSheetModelBase,
-      public TransportHoverListModel::Delegate {
+    : public AuthenticatorSheetModelBase {
  public:
   using AuthenticatorSheetModelBase::AuthenticatorSheetModelBase;
 
-  // TransportHoverListModel::Delegate:
-  void OnTransportSelected(AuthenticatorTransport transport) override;
-  void StartWinNativeApi() override;
-  void ContactPhone(const std::string& name) override;
-
  private:
   // AuthenticatorSheetModelBase:
   bool IsBackButtonVisible() const override;
diff --git a/chrome/browser/ui/webauthn/transport_hover_list_model.cc b/chrome/browser/ui/webauthn/transport_hover_list_model.cc
index c089b9f..678a4f0 100644
--- a/chrome/browser/ui/webauthn/transport_hover_list_model.cc
+++ b/chrome/browser/ui/webauthn/transport_hover_list_model.cc
@@ -4,38 +4,11 @@
 
 #include "chrome/browser/ui/webauthn/transport_hover_list_model.h"
 
-#include <utility>
-
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/app/vector_icons/vector_icons.h"
-#include "chrome/browser/ui/webauthn/transport_utils.h"
-#include "chrome/grit/generated_resources.h"
-#include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/paint_vector_icon.h"
-#include "ui/gfx/text_elider.h"
-
-namespace {
-// The tag ID space consists of the union of |AuthenticatorTransport| values
-// with the extra values defined below. These extra values must not overlap with
-// any values of |AuthenticatorTransport|.
-
-constexpr int kTagExtraBase = 1 << 16;
-constexpr int kNativeWinApiTag = kTagExtraBase;
-
-// kTagPhoneBase is the starting tag number for the names of linked phones.
-constexpr int kTagPhoneBase = 1 << 20;
-
-}  // namespace
 
 TransportHoverListModel::TransportHoverListModel(
-    base::flat_set<AuthenticatorTransport> transport_list,
-    bool show_win_native_api_item,
-    std::vector<std::string> phone_names,
-    Delegate* delegate)
-    : transport_list_(std::move(transport_list)),
-      show_win_native_api_item_(show_win_native_api_item),
-      phone_names_(std::move(phone_names)),
-      delegate_(delegate) {}
+    base::span<const AuthenticatorRequestDialogModel::Mechanism> mechanisms)
+    : mechanisms_(mechanisms) {}
 
 TransportHoverListModel::~TransportHoverListModel() = default;
 
@@ -56,36 +29,15 @@
 }
 
 std::vector<int> TransportHoverListModel::GetButtonTags() const {
-  std::vector<int> tag_list(transport_list_.size());
-  std::transform(
-      transport_list_.begin(), transport_list_.end(), tag_list.begin(),
-      [](const auto& transport) { return base::strict_cast<int>(transport); });
-  if (show_win_native_api_item_) {
-    tag_list.push_back(kNativeWinApiTag);
+  std::vector<int> tag_list(mechanisms_.size());
+  for (size_t i = 0; i < mechanisms_.size(); i++) {
+    tag_list[i] = static_cast<int>(i);
   }
-  for (size_t i = 0; i < phone_names_.size(); i++) {
-    tag_list.push_back(kTagPhoneBase + static_cast<int>(i));
-  }
-
   return tag_list;
 }
 
 std::u16string TransportHoverListModel::GetItemText(int item_tag) const {
-  if (item_tag >= kTagPhoneBase) {
-    static constexpr size_t kMaxNameChars = 50;
-    const std::u16string name =
-        base::UTF8ToUTF16(phone_names_[item_tag - kTagPhoneBase]);
-    std::u16string elided;
-    gfx::ElideString(name, kMaxNameChars, &elided);
-    return elided;
-  }
-  if (item_tag == kNativeWinApiTag) {
-    return l10n_util::GetStringUTF16(
-        IDS_WEBAUTHN_TRANSPORT_POPUP_DIFFERENT_AUTHENTICATOR_WIN);
-  }
-  return GetTransportHumanReadableName(
-      static_cast<AuthenticatorTransport>(item_tag),
-      TransportSelectionContext::kTransportSelectionSheet);
+  return mechanisms_[item_tag].name;
 }
 
 std::u16string TransportHoverListModel::GetDescriptionText(int item_tag) const {
@@ -94,35 +46,15 @@
 
 const gfx::VectorIcon* TransportHoverListModel::GetItemIcon(
     int item_tag) const {
-  if (item_tag >= kTagPhoneBase) {
-    return &kSmartphoneIcon;
-  }
-  if (item_tag == kNativeWinApiTag) {
-    return GetTransportVectorIcon(
-        AuthenticatorTransport::kUsbHumanInterfaceDevice);
-  }
-
-  return GetTransportVectorIcon(static_cast<AuthenticatorTransport>(item_tag));
+  return mechanisms_[item_tag].icon;
 }
 
 void TransportHoverListModel::OnListItemSelected(int item_tag) {
-  if (!delegate_) {
-    return;
-  }
-
-  if (item_tag >= kTagPhoneBase) {
-    delegate_->ContactPhone(phone_names_[item_tag - kTagPhoneBase]);
-  } else if (item_tag == kNativeWinApiTag) {
-    delegate_->StartWinNativeApi();
-  } else {
-    delegate_->OnTransportSelected(
-        static_cast<AuthenticatorTransport>(item_tag));
-  }
+  mechanisms_[item_tag].callback.Run();
 }
 
 size_t TransportHoverListModel::GetPreferredItemCount() const {
-  return transport_list_.size() +
-         static_cast<size_t>(show_win_native_api_item_) + phone_names_.size();
+  return mechanisms_.size();
 }
 
 bool TransportHoverListModel::StyleForTwoLines() const {
diff --git a/chrome/browser/ui/webauthn/transport_hover_list_model.h b/chrome/browser/ui/webauthn/transport_hover_list_model.h
index 34b03582..babdfaf 100644
--- a/chrome/browser/ui/webauthn/transport_hover_list_model.h
+++ b/chrome/browser/ui/webauthn/transport_hover_list_model.h
@@ -5,33 +5,22 @@
 #ifndef CHROME_BROWSER_UI_WEBAUTHN_TRANSPORT_HOVER_LIST_MODEL_H_
 #define CHROME_BROWSER_UI_WEBAUTHN_TRANSPORT_HOVER_LIST_MODEL_H_
 
-#include <stddef.h>
 #include <string>
 #include <vector>
 
-#include "base/containers/flat_set.h"
+#include "base/containers/span.h"
 #include "base/macros.h"
 #include "chrome/browser/ui/webauthn/hover_list_model.h"
-#include "chrome/browser/webauthn/authenticator_transport.h"
+#include "chrome/browser/webauthn/authenticator_request_dialog_model.h"
+
+namespace gfx {
+struct VectorIcon;
+}
 
 class TransportHoverListModel : public HoverListModel {
  public:
-  // Interface that the client should implement to learn when the user clicks on
-  // views that observe the model.
-  class Delegate {
-   public:
-    // Called when the given |transport| is selected by the user.
-    virtual void OnTransportSelected(AuthenticatorTransport transport) = 0;
-    // Called to trigger the native Windows API.
-    virtual void StartWinNativeApi() = 0;
-    // Called to trigger a contact with a phone specified by name.
-    virtual void ContactPhone(const std::string& name) = 0;
-  };
-
-  TransportHoverListModel(base::flat_set<AuthenticatorTransport> transport_list,
-                          bool show_win_native_api_item,
-                          std::vector<std::string> phone_names,
-                          Delegate* delegate);
+  explicit TransportHoverListModel(
+      base::span<const AuthenticatorRequestDialogModel::Mechanism> mechanisms);
   ~TransportHoverListModel() override;
 
   // HoverListModel:
@@ -48,17 +37,8 @@
   bool StyleForTwoLines() const override;
 
  private:
-  // Contains an AuthenticatorTransport for each item in the list.
-  base::flat_set<AuthenticatorTransport> transport_list_;
-
-  // Indicates whether a button to dispatch the request to the native Windows
-  // API should be shown.
-  const bool show_win_native_api_item_ = false;
-
-  // The human-friendly names of all paired phones.
-  std::vector<std::string> phone_names_;
-
-  Delegate* const delegate_;  // Weak, may be nullptr.
+  const base::span<const AuthenticatorRequestDialogModel::Mechanism>
+      mechanisms_;
 
   DISALLOW_COPY_AND_ASSIGN(TransportHoverListModel);
 };
diff --git a/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.cc b/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.cc
index 541ee04..0b29597 100644
--- a/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.cc
@@ -20,8 +20,6 @@
 namespace cellular_setup {
 namespace {
 
-const char useExternalEuiccLoadTimeDataName[] = "useExternalEuicc";
-
 constexpr webui::LocalizedString kLocalizedStringsWithoutPlaceholders[] = {
     {"activationCode", IDS_CELLULAR_SETUP_ESIM_PAGE_ACTIVATION_CODE},
     {"cancel", IDS_CANCEL},
@@ -94,10 +92,12 @@
 };
 
 const std::vector<const NamedBoolean>& GetBooleanValues() {
-  static const base::NoDestructor<std::vector<const NamedBoolean>> named_bools({
-      {"updatedCellularActivationUi",
-       chromeos::features::IsCellularActivationUiEnabled()},
-  });
+  static const base::NoDestructor<std::vector<const NamedBoolean>> named_bools(
+      {{"updatedCellularActivationUi",
+        chromeos::features::IsCellularActivationUiEnabled()},
+       {"useExternalEuicc",
+        base::FeatureList::IsEnabled(
+            chromeos::features::kCellularUseExternalEuicc)}});
   return *named_bools;
 }
 
@@ -115,9 +115,6 @@
 void AddNonStringLoadTimeData(content::WebUIDataSource* html_source) {
   for (const auto& entry : GetBooleanValues())
     html_source->AddBoolean(entry.name, entry.value);
-  html_source->AddBoolean(useExternalEuiccLoadTimeDataName,
-                          base::FeatureList::IsEnabled(
-                              chromeos::features::kCellularUseExternalEuicc));
 }
 
 void AddNonStringLoadTimeDataToDict(base::DictionaryValue* dict) {
diff --git a/chrome/browser/ui/webui/download_internals/download_internals_ui_message_handler.cc b/chrome/browser/ui/webui/download_internals/download_internals_ui_message_handler.cc
index 042cc501f..48f8b7a 100644
--- a/chrome/browser/ui/webui/download_internals/download_internals_ui_message_handler.cc
+++ b/chrome/browser/ui/webui/download_internals/download_internals_ui_message_handler.cc
@@ -146,7 +146,7 @@
       net::MutableNetworkTrafficAnnotationTag(traffic_annotation);
 
   DCHECK(download_service_);
-  download_service_->StartDownload(params);
+  download_service_->StartDownload(std::move(params));
 }
 
 }  // namespace download_internals
diff --git a/chrome/browser/ui/webui/internals/internals_ui.cc b/chrome/browser/ui/webui/internals/internals_ui.cc
index 18880e4..3b611375 100644
--- a/chrome/browser/ui/webui/internals/internals_ui.cc
+++ b/chrome/browser/ui/webui/internals/internals_ui.cc
@@ -13,6 +13,7 @@
 #include "content/public/browser/web_ui_data_source.h"
 
 #if defined(OS_ANDROID)
+#include "chrome/browser/ui/webui/internals/lens/lens_internals_ui_message_handler.h"
 #include "chrome/browser/ui/webui/internals/notifications/notifications_internals_ui_message_handler.h"
 #include "chrome/browser/ui/webui/internals/query_tiles/query_tiles_internals_ui_message_handler.h"
 #else
@@ -65,6 +66,8 @@
   // Add your sub-URL internals WebUI here.
   // Keep this set of sub-URLs in sync with |kChromeInternalsPathURLs|.
 #if defined(OS_ANDROID)
+  // chrome://internals/lens
+  AddLensInternals(web_ui);
   // chrome://internals/notifications
   source_->AddResourcePath(
       "notifications",
@@ -95,6 +98,13 @@
 InternalsUI::~InternalsUI() = default;
 
 #if defined(OS_ANDROID)
+void InternalsUI::AddLensInternals(content::WebUI* web_ui) {
+  source_->AddResourcePath("lens", IDR_LENS_INTERNALS_LENS_INTERNALS_HTML);
+
+  web_ui->AddMessageHandler(
+      std::make_unique<LensInternalsUIMessageHandler>(profile_));
+}
+
 void InternalsUI::AddQueryTilesInternals(content::WebUI* web_ui) {
   source_->AddResourcePath("query_tiles_internals.js",
                            IDR_QUERY_TILES_INTERNALS_JS);
diff --git a/chrome/browser/ui/webui/internals/internals_ui.h b/chrome/browser/ui/webui/internals/internals_ui.h
index 22bc3b1..29b57787 100644
--- a/chrome/browser/ui/webui/internals/internals_ui.h
+++ b/chrome/browser/ui/webui/internals/internals_ui.h
@@ -44,6 +44,9 @@
 #if defined(OS_ANDROID)
   // Add resources and message handler for chrome://internals/query-tiles.
   void AddQueryTilesInternals(content::WebUI* web_ui);
+
+  // Add resources and message handler for chrome://internals/lens.
+  void AddLensInternals(content::WebUI* web_ui);
 #endif  // defined(OS_ANDROID)
 
   Profile* profile_;
diff --git a/chrome/browser/ui/webui/internals/lens/lens_internals_ui_message_handler.cc b/chrome/browser/ui/webui/internals/lens/lens_internals_ui_message_handler.cc
new file mode 100644
index 0000000..59a6421
--- /dev/null
+++ b/chrome/browser/ui/webui/internals/lens/lens_internals_ui_message_handler.cc
@@ -0,0 +1,97 @@
+// 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/ui/webui/internals/lens/lens_internals_ui_message_handler.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "base/android/jni_array.h"
+#include "base/android/jni_string.h"
+#include "base/bind.h"
+#include "base/values.h"
+#include "chrome/android/chrome_jni_headers/LensDebugBridge_jni.h"
+#include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/web_ui.h"
+
+LensInternalsUIMessageHandler::LensInternalsUIMessageHandler(Profile* profile) {
+}
+
+LensInternalsUIMessageHandler::~LensInternalsUIMessageHandler() = default;
+
+void LensInternalsUIMessageHandler::RegisterMessages() {
+  web_ui()->RegisterMessageCallback(
+      "startDebugMode",
+      base::BindRepeating(&LensInternalsUIMessageHandler::HandleStartDebugMode,
+                          base::Unretained(this)));
+
+  web_ui()->RegisterMessageCallback(
+      "refreshDebugData",
+      base::BindRepeating(
+          &LensInternalsUIMessageHandler::HandleRefreshDebugData,
+          base::Unretained(this)));
+
+  web_ui()->RegisterMessageCallback(
+      "stopDebugMode",
+      base::BindRepeating(&LensInternalsUIMessageHandler::HandleStopDebugMode,
+                          base::Unretained(this)));
+}
+
+void LensInternalsUIMessageHandler::HandleStartDebugMode(
+    const base::ListValue* args) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+
+  Java_LensDebugBridge_startProactiveDebugMode(env);
+
+  const base::Value* callback_id;
+  auto result = args->Get(0, &callback_id);
+  DCHECK(result);
+
+  ResolveJavascriptCallback(*callback_id, base::Value());
+}
+
+void LensInternalsUIMessageHandler::HandleRefreshDebugData(
+    const base::ListValue* args) {
+  // Only needs to be called once.
+  AllowJavascript();
+  JNIEnv* env = base::android::AttachCurrentThread();
+
+  base::android::ScopedJavaLocalRef<jobjectArray> j_debug_data =
+      Java_LensDebugBridge_refreshDebugData(env);
+  std::vector<std::vector<std::u16string>> debug_data;
+  base::android::Java2dStringArrayTo2dStringVector(env, j_debug_data,
+                                                   &debug_data);
+
+  std::vector<base::Value> debug_data_as_vector_of_values;
+  for (auto const& row : debug_data) {
+    std::vector<base::Value> row_as_list_storage;
+    // Convert to base::Value array.
+    for (std::u16string const& cell_string : row) {
+      row_as_list_storage.emplace_back(base::Value(cell_string));
+    }
+    debug_data_as_vector_of_values.emplace_back(
+        base::Value(row_as_list_storage));
+  }
+
+  const base::Value* callback_id;
+  auto result = args->Get(0, &callback_id);
+  DCHECK(result);
+
+  ResolveJavascriptCallback(*callback_id,
+                            base::Value(debug_data_as_vector_of_values));
+}
+
+void LensInternalsUIMessageHandler::HandleStopDebugMode(
+    const base::ListValue* args) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+
+  Java_LensDebugBridge_stopProactiveDebugMode(env);
+
+  const base::Value* callback_id;
+  auto result = args->Get(0, &callback_id);
+  DCHECK(result);
+
+  ResolveJavascriptCallback(*callback_id, base::Value());
+}
diff --git a/chrome/browser/ui/webui/internals/lens/lens_internals_ui_message_handler.h b/chrome/browser/ui/webui/internals/lens/lens_internals_ui_message_handler.h
new file mode 100644
index 0000000..39b1eb50
--- /dev/null
+++ b/chrome/browser/ui/webui/internals/lens/lens_internals_ui_message_handler.h
@@ -0,0 +1,37 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_INTERNALS_LENS_LENS_INTERNALS_UI_MESSAGE_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_INTERNALS_LENS_LENS_INTERNALS_UI_MESSAGE_HANDLER_H_
+
+#include "base/android/scoped_java_ref.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/scoped_observation.h"
+#include "content/public/browser/web_ui_message_handler.h"
+
+namespace base {
+class ListValue;
+}  // namespace base
+
+class Profile;
+
+class LensInternalsUIMessageHandler : public content::WebUIMessageHandler {
+ public:
+  explicit LensInternalsUIMessageHandler(Profile* profile);
+  ~LensInternalsUIMessageHandler() override;
+
+  // content::WebUIMessageHandler implementation.
+  void RegisterMessages() override;
+
+ private:
+  // Logger::Observer implementation.
+  void HandleStartDebugMode(const base::ListValue* args);
+  void HandleRefreshDebugData(const base::ListValue* args);
+  void HandleStopDebugMode(const base::ListValue* args);
+
+  base::android::ScopedJavaGlobalRef<jobject> java_ref_;
+};
+
+#endif  // CHROME_BROWSER_UI_WEBUI_INTERNALS_LENS_LENS_INTERNALS_UI_MESSAGE_HANDLER_H_
diff --git a/chrome/browser/ui/webui/management/management_ui_handler_unittest.cc b/chrome/browser/ui/webui/management/management_ui_handler_unittest.cc
index bf96882..1c9200b6 100644
--- a/chrome/browser/ui/webui/management/management_ui_handler_unittest.cc
+++ b/chrome/browser/ui/webui/management/management_ui_handler_unittest.cc
@@ -406,6 +406,9 @@
 
     crostini_features_ = std::make_unique<crostini::FakeCrostiniFeatures>();
     SetUpConnectManager();
+    // DBusThreadManager::Initialize() has to be called before creating
+    // NetworkHandlerTestHelper.
+    chromeos::DBusThreadManager::Initialize();
     network_handler_test_helper_ =
         std::make_unique<chromeos::NetworkHandlerTestHelper>();
     chromeos::NetworkMetadataStore::RegisterPrefs(user_prefs_.registry());
@@ -417,6 +420,8 @@
   }
   void TearDown() override {
     network_handler_test_helper_.reset();
+    profile_.reset();
+    chromeos::DBusThreadManager::Shutdown();
     TestingBrowserProcess::GetGlobal()->SetLocalState(nullptr);
     DeviceSettingsTestBase::TearDown();
   }
diff --git a/chrome/browser/ui/webui/print_preview/pdf_printer_handler.cc b/chrome/browser/ui/webui/print_preview/pdf_printer_handler.cc
index 2967458f..bb1a223 100644
--- a/chrome/browser/ui/webui/print_preview/pdf_printer_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/pdf_printer_handler.cc
@@ -164,6 +164,7 @@
 
 // Callback that runs after `PrintToPdfCallback()` returns.
 void OnPdfPrintedCallback(const AccountId& account_id,
+                          bool from_incognito_profile,
                           const base::FilePath& path,
                           base::OnceClosure pdf_file_saved_closure) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
@@ -174,13 +175,13 @@
         ash::HoldingSpaceKeyedServiceFactory::GetInstance()->GetService(
             profile);
     if (holding_space_keyed_service)
-      holding_space_keyed_service->AddPrintedPdf(path);
+      holding_space_keyed_service->AddPrintedPdf(path, from_incognito_profile);
   }
 #elif BUILDFLAG(IS_CHROMEOS_LACROS)
   auto* service = chromeos::LacrosService::Get();
   if (service && service->IsAvailable<crosapi::mojom::HoldingSpaceService>()) {
     service->GetRemote<crosapi::mojom::HoldingSpaceService>()->AddPrintedPdf(
-        path);
+        path, from_incognito_profile);
   }
 #endif
   if (!pdf_file_saved_closure.is_null())
@@ -440,7 +441,8 @@
       FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
       base::BindOnce(&PrintToPdfCallback, print_data_, print_to_pdf_path_),
       base::BindOnce(&OnPdfPrintedCallback, GetAccountId(profile_),
-                     print_to_pdf_path_, std::move(pdf_file_saved_closure_)));
+                     profile_->IsIncognitoProfile(), print_to_pdf_path_,
+                     std::move(pdf_file_saved_closure_)));
 
   print_to_pdf_path_.clear();
 
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model.cc b/chrome/browser/webauthn/authenticator_request_dialog_model.cc
index 6e8153f..4ef2716 100644
--- a/chrome/browser/webauthn/authenticator_request_dialog_model.cc
+++ b/chrome/browser/webauthn/authenticator_request_dialog_model.cc
@@ -14,61 +14,86 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "build/build_config.h"
+#include "chrome/app/vector_icons/vector_icons.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/vector_icons/vector_icons.h"
 #include "device/fido/features.h"
 #include "device/fido/fido_authenticator.h"
 #include "device/fido/pin.h"
 #include "device/fido/public_key_credential_user_entity.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/text_elider.h"
 
 namespace {
 
-// Attempts to auto-select the most likely transport that will be used to
-// service this request, or returns base::nullopt if unsure.
-base::Optional<device::FidoTransportProtocol> SelectMostLikelyTransport(
-    const device::FidoRequestHandlerBase::TransportAvailabilityInfo&
-        transport_availability,
-    bool cable_extension_provided,
-    bool have_paired_phones) {
-  const base::flat_set<AuthenticatorTransport>& candidate_transports(
-      transport_availability.available_transports);
-
-  // If there is only one transport available, select that instead of showing a
-  // transport selection screen with only a single item. The exception is if
-  // the transport is caBLE and we have paired phones to list. In that case the
-  // user has to click one of the phones on the transport selection screen.
-  if (candidate_transports.size() == 1 &&
-      (!have_paired_phones ||
-       !base::Contains(
-           candidate_transports,
-           AuthenticatorTransport::kCloudAssistedBluetoothLowEnergy))) {
-    return *candidate_transports.begin();
+constexpr int GetMessageIdForTransportDescription(
+    AuthenticatorTransport transport) {
+  switch (transport) {
+    case AuthenticatorTransport::kUsbHumanInterfaceDevice:
+      return IDS_WEBAUTHN_TRANSPORT_USB;
+    case AuthenticatorTransport::kInternal:
+      return IDS_WEBAUTHN_TRANSPORT_INTERNAL;
+    case AuthenticatorTransport::kCloudAssistedBluetoothLowEnergy:
+      return IDS_WEBAUTHN_TRANSPORT_CABLE;
+    case AuthenticatorTransport::kAndroidAccessory:
+      return IDS_WEBAUTHN_TRANSPORT_AOA;
+    case AuthenticatorTransport::kBluetoothLowEnergy:
+    case AuthenticatorTransport::kNearFieldCommunication:
+      NOTREACHED();
+      return 0;
   }
+}
 
-  // The remaining decisions apply to GetAssertion requests only. For
-  // MakeCredential, the user needs to choose from transport selection.
-  if (transport_availability.request_type !=
-      device::FidoRequestType::kGetAssertion) {
-    return base::nullopt;
+std::u16string GetTransportDescription(AuthenticatorTransport transport) {
+  const int msg_id = GetMessageIdForTransportDescription(transport);
+  if (!msg_id) {
+    return std::u16string();
   }
+  return l10n_util::GetStringUTF16(msg_id);
+}
 
-  // Auto advance to the platform authenticator if it has a matching credential
-  // for the (possibly empty) allow list.
-  if (base::Contains(candidate_transports,
-                     device::FidoTransportProtocol::kInternal) &&
-      *transport_availability
-           .has_recognized_platform_authenticator_credential) {
-    return device::FidoTransportProtocol::kInternal;
+constexpr int GetMessageIdForTransportShortDescription(
+    AuthenticatorTransport transport) {
+  switch (transport) {
+    case AuthenticatorTransport::kUsbHumanInterfaceDevice:
+      return IDS_WEBAUTHN_TRANSPORT_POPUP_USB;
+    case AuthenticatorTransport::kInternal:
+      return IDS_WEBAUTHN_TRANSPORT_POPUP_INTERNAL;
+    case AuthenticatorTransport::kCloudAssistedBluetoothLowEnergy:
+      return IDS_WEBAUTHN_TRANSPORT_POPUP_CABLE;
+    case AuthenticatorTransport::kAndroidAccessory:
+      return IDS_WEBAUTHN_TRANSPORT_POPUP_AOA;
+    case AuthenticatorTransport::kBluetoothLowEnergy:
+    case AuthenticatorTransport::kNearFieldCommunication:
+      NOTREACHED();
+      return 0;
   }
+}
 
-  // If the RP supplied the caBLE extension then respect that and always select
-  // caBLE for GetAssertion operations.
-  if (cable_extension_provided &&
-      base::Contains(
-          candidate_transports,
-          AuthenticatorTransport::kCloudAssistedBluetoothLowEnergy)) {
-    return AuthenticatorTransport::kCloudAssistedBluetoothLowEnergy;
+std::u16string GetTransportShortDescription(AuthenticatorTransport transport) {
+  const int msg_id = GetMessageIdForTransportShortDescription(transport);
+  if (!msg_id) {
+    return std::u16string();
   }
+  return l10n_util::GetStringUTF16(msg_id);
+}
 
-  return base::nullopt;
+constexpr const gfx::VectorIcon* GetTransportIcon(
+    AuthenticatorTransport transport) {
+  switch (transport) {
+    case AuthenticatorTransport::kUsbHumanInterfaceDevice:
+      return &vector_icons::kUsbIcon;
+    case AuthenticatorTransport::kInternal:
+      return &kLaptopIcon;
+    case AuthenticatorTransport::kCloudAssistedBluetoothLowEnergy:
+      return &kSmartphoneIcon;
+    case AuthenticatorTransport::kAndroidAccessory:
+      return &kUsbCableIcon;
+    case AuthenticatorTransport::kBluetoothLowEnergy:
+    case AuthenticatorTransport::kNearFieldCommunication:
+      NOTREACHED();
+      return nullptr;
+  }
 }
 
 }  // namespace
@@ -76,6 +101,22 @@
 AuthenticatorRequestDialogModel::EphemeralState::EphemeralState() = default;
 AuthenticatorRequestDialogModel::EphemeralState::~EphemeralState() = default;
 
+AuthenticatorRequestDialogModel::Mechanism::Mechanism(
+    AuthenticatorRequestDialogModel::Mechanism::Type in_type,
+    std::u16string in_name,
+    std::u16string in_short_name,
+    const gfx::VectorIcon* in_icon,
+    base::RepeatingClosure in_callback,
+    bool is_priority)
+    : name(std::move(in_name)),
+      short_name(std::move(in_short_name)),
+      icon(in_icon),
+      callback(std::move(in_callback)),
+      priority(is_priority),
+      type(std::move(in_type)) {}
+AuthenticatorRequestDialogModel::Mechanism::~Mechanism() = default;
+AuthenticatorRequestDialogModel::Mechanism::Mechanism(Mechanism&&) = default;
+
 AuthenticatorRequestDialogModel::PairedPhone::PairedPhone(const PairedPhone&) =
     default;
 AuthenticatorRequestDialogModel::PairedPhone::PairedPhone(
@@ -138,6 +179,8 @@
   transport_availability_ = std::move(transport_availability);
   use_location_bar_bubble_ = use_location_bar_bubble;
 
+  PopulateMechanisms();
+
   if (use_location_bar_bubble_) {
     // This is a conditional request so show a lightweight, non-modal dialog
     // instead.
@@ -157,6 +200,7 @@
     StartLocationBarBubbleRequest();
     return;
   }
+  current_mechanism_.reset();
   SetCurrentStep(Step::kTransportSelection);
 }
 
@@ -164,42 +208,29 @@
     StartGuidedFlowForMostLikelyTransportOrShowTransportSelection() {
   DCHECK(current_step() == Step::kNotStarted);
 
-  // If no authenticator other than the one for the native Windows API is
-  // available, or if the sole authenticator is caBLE, but there's no caBLE
-  // extension nor paired phone, then don't show Chrome UI but proceed straight
-  // to the native Windows UI.
-  if (transport_availability_.has_win_native_api_authenticator &&
-      !win_native_api_already_tried_) {
-    const auto& transports = transport_availability_.available_transports;
-    if (transports.empty() ||
-        (transports.size() == 1 &&
-         base::Contains(
-             transports,
-             AuthenticatorTransport::kCloudAssistedBluetoothLowEnergy) &&
-         !cable_extension_provided_ && paired_phones_.empty())) {
-      StartWinNativeApi();
-      return;
-    }
-  }
-
-  auto most_likely_transport = SelectMostLikelyTransport(
-      transport_availability_, cable_extension_provided_,
-      !paired_phones_.empty());
+  const auto priority_mechanism_it =
+      std::find_if(mechanisms_.begin(), mechanisms_.end(),
+                   [](const Mechanism& m) -> bool { return m.priority; });
 
   if (pending_step_) {
     SetCurrentStep(*pending_step_);
     pending_step_.reset();
-  } else if (most_likely_transport) {
-    StartGuidedFlowForTransport(*most_likely_transport);
-  } else if (!transport_availability_.available_transports.empty()) {
-    SetCurrentStep(Step::kTransportSelection);
-  } else {
+  } else if (mechanisms_.empty()) {
     SetCurrentStep(Step::kErrorNoAvailableTransports);
+  } else if (mechanisms_.size() == 1) {
+    mechanisms_[0].callback.Run();
+  } else if (priority_mechanism_it != mechanisms_.end()) {
+    priority_mechanism_it->callback.Run();
+  } else {
+    SetCurrentStep(Step::kTransportSelection);
   }
 }
 
 void AuthenticatorRequestDialogModel::StartGuidedFlowForTransport(
-    AuthenticatorTransport transport) {
+    AuthenticatorTransport transport,
+    size_t mechanism_index) {
+  current_mechanism_ = mechanism_index;
+
   DCHECK(current_step() == Step::kTransportSelection ||
          current_step() == Step::kUsbInsertAndActivate ||
          current_step() == Step::kCableActivate ||
@@ -209,9 +240,6 @@
     case AuthenticatorTransport::kUsbHumanInterfaceDevice:
       SetCurrentStep(Step::kUsbInsertAndActivate);
       break;
-    case AuthenticatorTransport::kNearFieldCommunication:
-      SetCurrentStep(Step::kTransportSelection);
-      break;
     case AuthenticatorTransport::kInternal:
       StartPlatformAuthenticatorFlow();
       break;
@@ -247,8 +275,10 @@
   HideDialog();
 }
 
-void AuthenticatorRequestDialogModel::StartWinNativeApi() {
+void AuthenticatorRequestDialogModel::StartWinNativeApi(
+    size_t mechanism_index) {
   DCHECK(transport_availability_.has_win_native_api_authenticator);
+  current_mechanism_ = mechanism_index;
 
   if (resident_key_requirement() !=
           device::ResidentKeyRequirement::kDiscouraged &&
@@ -259,7 +289,9 @@
   }
 }
 
-void AuthenticatorRequestDialogModel::ContactPhone(const std::string& name) {
+void AuthenticatorRequestDialogModel::ContactPhone(const std::string& name,
+                                                   size_t mechanism_index) {
+  current_mechanism_ = mechanism_index;
   ContactNextPhoneByName(name);
   EnsureBleAdapterIsPoweredAndContinueWithCable();
 }
@@ -639,6 +671,30 @@
       std::move(test_authenticator));
 }
 
+base::span<const AuthenticatorRequestDialogModel::Mechanism>
+AuthenticatorRequestDialogModel::mechanisms() const {
+  return mechanisms_;
+}
+
+base::Optional<size_t> AuthenticatorRequestDialogModel::current_mechanism()
+    const {
+  return current_mechanism_;
+}
+
+void AuthenticatorRequestDialogModel::ContactPhoneForTesting(
+    const std::string& name) {
+  ContactPhone(name, /*mechanism_index=*/0);
+}
+
+void AuthenticatorRequestDialogModel::StartTransportFlowForTesting(
+    AuthenticatorTransport transport) {
+  StartGuidedFlowForTransport(transport, /*mechanism_index=*/0);
+}
+
+void AuthenticatorRequestDialogModel::SetCurrentStepForTesting(Step step) {
+  SetCurrentStep(step);
+}
+
 bool AuthenticatorRequestDialogModel::cable_should_suggest_usb() const {
   return base::Contains(transport_availability_.available_transports,
                         AuthenticatorTransport::kAndroidAccessory);
@@ -667,6 +723,10 @@
   }
 }
 
+void AuthenticatorRequestDialogModel::FinishCollectToken() {
+  SetCurrentStep(Step::kClientPinTapAgain);
+}
+
 void AuthenticatorRequestDialogModel::StartInlineBioEnrollment(
     base::OnceClosure next_callback) {
   max_bio_samples_ = base::nullopt;
@@ -771,3 +831,110 @@
 
   DCHECK(found_name);
 }
+
+void AuthenticatorRequestDialogModel::PopulateMechanisms() {
+  const bool is_get_assertion = transport_availability_.request_type ==
+                                device::FidoRequestType::kGetAssertion;
+  // priority_transport contains the transport that should be activated
+  // immediately, if this is a getAssertion.
+  base::Optional<AuthenticatorTransport> priority_transport;
+
+  if (base::Contains(transport_availability_.available_transports,
+                     AuthenticatorTransport::kInternal) &&
+      is_get_assertion &&
+      *transport_availability_
+           .has_recognized_platform_authenticator_credential) {
+    priority_transport = AuthenticatorTransport::kInternal;
+  }
+
+  std::vector<AuthenticatorTransport> transports_to_list_if_active = {
+      AuthenticatorTransport::kUsbHumanInterfaceDevice,
+      AuthenticatorTransport::kInternal,
+  };
+
+  if (cable_ui_type_) {
+    switch (*cable_ui_type_) {
+      case AuthenticatorRequestDialogModel::CableUIType::CABLE_V2_SERVER_LINK:
+        transports_to_list_if_active.push_back(
+            AuthenticatorTransport::kAndroidAccessory);
+        [[fallthrough]];
+
+      case AuthenticatorRequestDialogModel::CableUIType::CABLE_V1: {
+        const auto cable =
+            AuthenticatorTransport::kCloudAssistedBluetoothLowEnergy;
+        if (base::Contains(transport_availability_.available_transports,
+                           cable)) {
+          transports_to_list_if_active.push_back(cable);
+          DCHECK(is_get_assertion);
+          if (!priority_transport) {
+            priority_transport = cable;
+          }
+        }
+        break;
+      }
+
+      case AuthenticatorRequestDialogModel::CableUIType::CABLE_V2_2ND_FACTOR:
+        break;
+    }
+  }
+
+  for (const auto transport : transports_to_list_if_active) {
+    if (!base::Contains(transport_availability_.available_transports,
+                        transport)) {
+      continue;
+    }
+
+    mechanisms_.emplace_back(
+        Mechanism::Transport(transport), GetTransportDescription(transport),
+        GetTransportShortDescription(transport), GetTransportIcon(transport),
+        base::BindRepeating(
+            &AuthenticatorRequestDialogModel::StartGuidedFlowForTransport,
+            base::Unretained(this), transport, mechanisms_.size()),
+        transport_availability_.request_type ==
+                device::FidoRequestType::kGetAssertion &&
+            priority_transport.has_value() && *priority_transport == transport);
+  }
+
+  if (win_native_api_enabled()) {
+    const std::u16string desc = l10n_util::GetStringUTF16(
+        IDS_WEBAUTHN_TRANSPORT_POPUP_DIFFERENT_AUTHENTICATOR_WIN);
+    mechanisms_.emplace_back(
+        Mechanism::WindowsAPI(/*unused*/ true), desc, desc,
+        GetTransportIcon(AuthenticatorTransport::kUsbHumanInterfaceDevice),
+        base::BindRepeating(&AuthenticatorRequestDialogModel::StartWinNativeApi,
+                            base::Unretained(this), mechanisms_.size()),
+        // The Windows API should have priority unless caBLE does, except that
+        // we'll show the selection sheet if there are linked phones in a
+        // makeCredential call.
+        !(priority_transport.has_value() ||
+          (transport_availability_.request_type ==
+               device::FidoRequestType::kMakeCredential &&
+           !paired_phones_.empty())));
+  }
+
+  if (base::Contains(
+          transport_availability_.available_transports,
+          AuthenticatorTransport::kCloudAssistedBluetoothLowEnergy)) {
+    for (const auto& phone_name : paired_phone_names()) {
+      const std::u16string name16 = base::UTF8ToUTF16(phone_name);
+      static constexpr size_t kMaxLongNameChars = 50;
+      static constexpr size_t kMaxShortNameChars = 30;
+      std::u16string long_name, short_name;
+      gfx::ElideString(name16, kMaxLongNameChars, &long_name);
+      gfx::ElideString(name16, kMaxShortNameChars, &short_name);
+
+      mechanisms_.emplace_back(
+          Mechanism::Phone(phone_name), std::move(long_name),
+          std::move(short_name), &kSmartphoneIcon,
+          base::BindRepeating(&AuthenticatorRequestDialogModel::ContactPhone,
+                              base::Unretained(this), phone_name,
+                              mechanisms_.size()),
+          /*priority=*/false);
+    }
+  }
+
+  // At most one mechanisms has priority.
+  DCHECK_LE(std::count_if(mechanisms_.begin(), mechanisms_.end(),
+                          [](const Mechanism& m) { return m.priority; }),
+            1);
+}
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model.h b/chrome/browser/webauthn/authenticator_request_dialog_model.h
index 289abc2..b9a59d9 100644
--- a/chrome/browser/webauthn/authenticator_request_dialog_model.h
+++ b/chrome/browser/webauthn/authenticator_request_dialog_model.h
@@ -15,6 +15,7 @@
 #include "base/observer_list.h"
 #include "base/optional.h"
 #include "base/strings/string_piece.h"
+#include "base/types/strong_alias.h"
 #include "build/build_config.h"
 #include "chrome/browser/webauthn/authenticator_reference.h"
 #include "chrome/browser/webauthn/authenticator_transport.h"
@@ -25,6 +26,11 @@
 #include "device/fido/fido_types.h"
 #include "device/fido/pin.h"
 #include "device/fido/public_key_credential_user_entity.h"
+#include "third_party/abseil-cpp/absl/types/variant.h"
+
+namespace gfx {
+struct VectorIcon;
+}
 
 namespace device {
 class AuthenticatorGetAssertionResponse;
@@ -139,6 +145,42 @@
     virtual void OnCancelRequest() {}
   };
 
+  // A Mechanism is a user-visable method of authenticating. It might be a
+  // transport (such as USB), a platform authenticator, a phone, or even a
+  // delegation to a platform API. Mechanisms are listed in the UI for the
+  // user to select between.
+  struct Mechanism {
+    // These types describe the type of Mechanism, but this is only for testing.
+    using Transport =
+        base::StrongAlias<class TransportTag, AuthenticatorTransport>;
+    using WindowsAPI = base::StrongAlias<class WindowsAPITag,
+                                         bool /* unused, but cannot be void */>;
+    using Phone = base::StrongAlias<class PhoneTag, std::string>;
+    using Type = absl::variant<Transport, WindowsAPI, Phone>;
+
+    Mechanism(Type type,
+              std::u16string name,
+              std::u16string short_name,
+              const gfx::VectorIcon* icon,
+              base::RepeatingClosure callback,
+              bool is_priority);
+    ~Mechanism();
+    Mechanism(Mechanism&&);
+    Mechanism(const Mechanism&) = delete;
+    Mechanism& operator=(const Mechanism&) = delete;
+
+    const std::u16string name;
+    const std::u16string short_name;
+    const gfx::VectorIcon* const icon;
+    const base::RepeatingClosure callback;
+    // priority is true if this mechanism should be activated immediately.
+    // Only a single Mechanism in a list should have priority.
+    const bool priority;
+
+    // type should only be accessed by tests.
+    const Type type;
+  };
+
   // PairedPhone represents a paired caBLEv2 device.
   struct PairedPhone {
     PairedPhone() = delete;
@@ -175,7 +217,6 @@
   explicit AuthenticatorRequestDialogModel(const std::string& relying_party_id);
   ~AuthenticatorRequestDialogModel();
 
-  void SetCurrentStep(Step step);
   Step current_step() const { return current_step_; }
 
   // Hides the dialog. A subsequent call to SetCurrentStep() will unhide it.
@@ -234,25 +275,10 @@
   // Valid action when at step: kNotStarted.
   void StartGuidedFlowForMostLikelyTransportOrShowTransportSelection();
 
-  // Requests that the step-by-step wizard flow commence, guiding the user
-  // through using the Secutity Key with the given |transport|.
-  //
-  // Valid action when at step: kNotStarted.
-  // kTransportSelection, and steps where the other transports menu is shown,
-  // namely, kUsbInsertAndActivate, kCableActivate.
-  void StartGuidedFlowForTransport(AuthenticatorTransport transport);
-
   // Hides the modal Chrome UI dialog and shows the native Windows WebAuthn
   // UI instead.
   void HideDialogAndDispatchToNativeWindowsApi();
 
-  // Displays a resident-key warning if needed and then calls
-  // |HideDialogAndDispatchToNativeWindowsApi|.
-  void StartWinNativeApi();
-
-  // Contacts a paired phone. The phone is specified by name.
-  void ContactPhone(const std::string& name);
-
   // Called when an attempt to contact a phone failed.
   void OnPhoneContactFailed(const std::string& name);
 
@@ -413,6 +439,25 @@
 
   void SetSelectedAuthenticatorForTesting(AuthenticatorReference authenticator);
 
+  base::span<const Mechanism> mechanisms() const;
+
+  // current_mechanism returns the index into |mechanisms| of the most recently
+  // activated mechanism, or nullopt if there isn't one.
+  base::Optional<size_t> current_mechanism() const;
+
+  // ContactPhoneForTesting triggers a contact for a phone with the given name.
+  // Only for unittests. UI should use |mechanisms()| to enumerate the
+  // user-visible mechanisms and use the callbacks therein.
+  void ContactPhoneForTesting(const std::string& name);
+
+  // StartTransportFlowForTesting moves the UI to focus on the given transport.
+  // UI should use |mechanisms()| to enumerate the user-visible mechanisms and
+  // use the callbacks therein.
+  void StartTransportFlowForTesting(AuthenticatorTransport transport);
+
+  // SetCurrentStepForTesting forces the model to the specified step.
+  void SetCurrentStepForTesting(Step step);
+
   ObservableAuthenticatorList& saved_authenticators() {
     return ephemeral_state_.saved_authenticators_;
   }
@@ -434,6 +479,7 @@
                   uint32_t min_pin_length,
                   int attempts,
                   base::OnceCallback<void(std::u16string)> provide_pin_cb);
+  void FinishCollectToken();
   uint32_t min_pin_length() const { return min_pin_length_; }
   device::pin::PINEntryError pin_error() const { return pin_error_; }
   base::Optional<int> pin_attempts() const { return pin_attempts_; }
@@ -505,12 +551,31 @@
     std::vector<device::PublicKeyCredentialUserEntity> users_;
   };
 
+  void SetCurrentStep(Step step);
+
+  // Requests that the step-by-step wizard flow commence, guiding the user
+  // through using the Secutity Key with the given |transport|.
+  //
+  // Valid action when at step: kNotStarted.
+  // kTransportSelection, and steps where the other transports menu is shown,
+  // namely, kUsbInsertAndActivate, kCableActivate.
+  void StartGuidedFlowForTransport(AuthenticatorTransport transport,
+                                   size_t mechanism_index);
+
+  // Displays a resident-key warning if needed and then calls
+  // |HideDialogAndDispatchToNativeWindowsApi|.
+  void StartWinNativeApi(size_t mechanism_index);
+
+  // Contacts a paired phone. The phone is specified by name.
+  void ContactPhone(const std::string& name, size_t mechanism_index);
+
   void StartLocationBarBubbleRequest();
 
   void DispatchRequestAsync(AuthenticatorReference* authenticator);
   void DispatchRequestAsyncInternal(const std::string& authenticator_id);
 
   void ContactNextPhoneByName(const std::string& name);
+  void PopulateMechanisms();
 
   EphemeralState ephemeral_state_;
 
@@ -570,6 +635,14 @@
   // extension.
   bool cable_extension_provided_ = false;
 
+  // mechanisms contains the entries that appear in the "transport" selection
+  // sheet and the drop-down menu.
+  std::vector<Mechanism> mechanisms_;
+
+  // current_mechanism_ contains the index of the most recently activated
+  // mechanism.
+  base::Optional<size_t> current_mechanism_;
+
   // cable_ui_type_ contains the type of UI to display for a caBLE transaction.
   base::Optional<CableUIType> cable_ui_type_;
 
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model_unittest.cc b/chrome/browser/webauthn/authenticator_request_dialog_model_unittest.cc
index c7705639..ddc6648 100644
--- a/chrome/browser/webauthn/authenticator_request_dialog_model_unittest.cc
+++ b/chrome/browser/webauthn/authenticator_request_dialog_model_unittest.cc
@@ -22,6 +22,7 @@
 #include "device/fido/authenticator_data.h"
 #include "device/fido/authenticator_get_assertion_response.h"
 #include "device/fido/fido_constants.h"
+#include "device/fido/fido_transport_protocol.h"
 #include "device/fido/public_key_credential_user_entity.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -96,7 +97,8 @@
 enum class TransportAvailabilityParam {
   kHasPlatformCredential,
   kHasWinNativeAuthenticator,
-  kHasCableExtension,
+  kHasCableV1Extension,
+  kHasCableV2Extension,
 };
 
 base::StringPiece TransportAvailabilityParamToString(
@@ -106,8 +108,10 @@
       return "kHasPlatformCredential";
     case TransportAvailabilityParam::kHasWinNativeAuthenticator:
       return "kHasWinNativeAuthenticator";
-    case TransportAvailabilityParam::kHasCableExtension:
-      return "kHasCableExtension";
+    case TransportAvailabilityParam::kHasCableV1Extension:
+      return "kHasCableV1Extension";
+    case TransportAvailabilityParam::kHasCableV2Extension:
+      return "kHasCableV2Extension";
   }
 }
 
@@ -134,160 +138,93 @@
   DISALLOW_COPY_AND_ASSIGN(AuthenticatorRequestDialogModelTest);
 };
 
-TEST_F(AuthenticatorRequestDialogModelTest, TransportAutoSelection) {
+TEST_F(AuthenticatorRequestDialogModelTest, Mechanisms) {
+  const auto mc = RequestType::kMakeCredential;
+  const auto ga = RequestType::kGetAssertion;
+  const auto usb = AuthenticatorTransport::kUsbHumanInterfaceDevice;
+  const auto internal = AuthenticatorTransport::kInternal;
+  const auto cable = AuthenticatorTransport::kCloudAssistedBluetoothLowEnergy;
+  const auto aoa = AuthenticatorTransport::kAndroidAccessory;
+  const auto v1 = TransportAvailabilityParam::kHasCableV1Extension;
+  const auto v2 = TransportAvailabilityParam::kHasCableV2Extension;
+  const auto has_winapi =
+      TransportAvailabilityParam::kHasWinNativeAuthenticator;
+  const auto has_plat = TransportAvailabilityParam::kHasPlatformCredential;
+  using t = AuthenticatorRequestDialogModel::Mechanism::Transport;
+  using p = AuthenticatorRequestDialogModel::Mechanism::Phone;
+  const auto winapi =
+      AuthenticatorRequestDialogModel::Mechanism::WindowsAPI(true);
+  const auto usb_ui = Step::kUsbInsertAndActivate;
+  const auto tss = Step::kTransportSelection;
+  const auto plat_ui = Step::kNotStarted;
+  const auto cable_ui = Step::kCableActivate;
+
   const struct {
     RequestType request_type;
-    base::flat_set<AuthenticatorTransport> available_transports;
-    base::flat_set<TransportAvailabilityParam> transport_params;
+    base::flat_set<AuthenticatorTransport> transports;
+    base::flat_set<TransportAvailabilityParam> params;
+    std::vector<std::string> phone_names;
+    std::vector<AuthenticatorRequestDialogModel::Mechanism::Type>
+        expected_mechanisms;
     Step expected_first_step;
-  } kTestCases[] = {
-      // Only a single transport is available for a GetAssertion call.
-      {RequestType::kGetAssertion,
-       {AuthenticatorTransport::kUsbHumanInterfaceDevice},
-       {},
-       Step::kUsbInsertAndActivate},
-      {RequestType::kGetAssertion,
-       {AuthenticatorTransport::kInternal},
-       {},
-       Step::kErrorInternalUnrecognized},
-      {RequestType::kGetAssertion,
-       {AuthenticatorTransport::kInternal},
-       {TransportAvailabilityParam::kHasPlatformCredential},
-       Step::kNotStarted},
-      {RequestType::kGetAssertion,
-       {AuthenticatorTransport::kCloudAssistedBluetoothLowEnergy},
-       {TransportAvailabilityParam::kHasCableExtension},
-       Step::kCableActivate},
+  } kTests[] = {
+      // If there's only a single mechanism, it should activate.
+      {mc, {usb}, {}, {}, {t(usb)}, usb_ui},
+      {ga, {usb}, {}, {}, {t(usb)}, usb_ui},
+      // ... otherwise should the selection sheet.
+      {mc, {usb, internal}, {}, {}, {t(usb), t(internal)}, tss},
+      {ga, {usb, internal}, {}, {}, {t(usb), t(internal)}, tss},
 
-      {RequestType::kGetAssertion,
-       kAllTransportsWithoutCable,
-       {},
-       Step::kTransportSelection},
+      // If the platform authenticator has a credential it should activate.
+      {ga, {usb, internal}, {has_plat}, {}, {t(usb), t(internal)}, plat_ui},
 
-      {RequestType::kGetAssertion,
-       {AuthenticatorTransport::kInternal,
-        AuthenticatorTransport::kUsbHumanInterfaceDevice},
-       {},
-       Step::kTransportSelection},
+      // If the Windows API is available without caBLE, it should activate.
+      {mc, {}, {has_winapi}, {}, {winapi}, plat_ui},
+      {ga, {}, {has_winapi}, {}, {winapi}, plat_ui},
+      // ... even if, somehow, there's another transport.
+      {mc, {usb}, {has_winapi}, {}, {t(usb), winapi}, plat_ui},
+      {ga, {usb}, {has_winapi}, {}, {t(usb), winapi}, plat_ui},
 
-      // The KeyChain contains an allowed Touch ID credential.
-      {RequestType::kGetAssertion,
-       kAllTransports,
-       {TransportAvailabilityParam::kHasPlatformCredential},
-       Step::kNotStarted},
+      // A caBLEv1 extension should cause us to go directly to caBLE.
+      {ga, {usb, cable}, {v1}, {}, {t(usb), t(cable)}, cable_ui},
+      // A caBLEv2 extension should cause us to go directly to caBLE, but also
+      // show the AOA option.
+      {ga, {usb, aoa, cable}, {v2}, {}, {t(usb), t(aoa), t(cable)}, cable_ui},
 
-      // The KeyChain does not contain an allowed Touch ID credential.
-      {RequestType::kGetAssertion,
-       {AuthenticatorTransport::kInternal},
-       {},
-       Step::kErrorInternalUnrecognized},
-      {RequestType::kGetAssertion,
-       {AuthenticatorTransport::kInternal},
-       {},
-       Step::kErrorInternalUnrecognized},
-      {RequestType::kGetAssertion,
-       kAllTransportsWithoutCable,
-       {},
-       Step::kTransportSelection},
-      {RequestType::kGetAssertion,
-       {AuthenticatorTransport::kUsbHumanInterfaceDevice,
-        AuthenticatorTransport::kInternal},
-       {},
-       Step::kTransportSelection},
+      // If there are linked phones then AOA doesn't show up, but the phones do,
+      // and sorted. The selection sheet should show.
+      {mc, {usb, aoa, cable}, {}, {"b", "a"}, {t(usb), p("a"), p("b")}, tss},
+      {ga, {usb, aoa, cable}, {}, {"b", "a"}, {t(usb), p("a"), p("b")}, tss},
 
-      // The KeyChain contains an allowed Touch ID credential, but Touch ID is
-      // not enabled by the relying party.
-      {RequestType::kGetAssertion,
-       {AuthenticatorTransport::kUsbHumanInterfaceDevice},
-       {TransportAvailabilityParam::kHasPlatformCredential},
-       Step::kUsbInsertAndActivate},
-      {RequestType::kGetAssertion,
-       {AuthenticatorTransport::kUsbHumanInterfaceDevice,
-        AuthenticatorTransport::kNearFieldCommunication},
-       {TransportAvailabilityParam::kHasPlatformCredential},
-       Step::kTransportSelection},
-
-      // If caBLE is one of the allowed transports, it has second-highest
-      // priority after Touch ID, and is auto-selected for GetAssertion
-      // operations.
-      {RequestType::kGetAssertion,
-       kAllTransports,
-       {TransportAvailabilityParam::kHasCableExtension},
-       Step::kCableActivate},
-      {RequestType::kGetAssertion,
-       {AuthenticatorTransport::kCloudAssistedBluetoothLowEnergy,
-        AuthenticatorTransport::kUsbHumanInterfaceDevice},
-       {TransportAvailabilityParam::kHasCableExtension},
-       Step::kCableActivate},
-
-      // caBLE should not enjoy this same high priority for MakeCredential
-      // calls.
-      {RequestType::kMakeCredential,
-       kAllTransports,
-       {},
-       Step::kTransportSelection},
-
-      // No transports available.
-      {RequestType::kGetAssertion, {}, {}, Step::kErrorNoAvailableTransports},
-
-      // We default to transport selection modal for MakeCredential.
-      {RequestType::kMakeCredential,
-       kAllTransports,
-       {},
-       Step::kTransportSelection},
-
-      // When only one transport is available, we still want to skip transport
-      // selection view for MakeCredential call.
-      {RequestType::kMakeCredential,
-       {AuthenticatorTransport::kUsbHumanInterfaceDevice},
-       {},
-       Step::kUsbInsertAndActivate},
-      {RequestType::kMakeCredential,
-       {AuthenticatorTransport::kInternal},
-       {},
-       Step::kNotStarted},
-      {RequestType::kMakeCredential,
-       {AuthenticatorTransport::kCloudAssistedBluetoothLowEnergy},
-       {TransportAvailabilityParam::kHasCableExtension},
-       Step::kCableActivate},
-      {RequestType::kMakeCredential,
-       {AuthenticatorTransport::kUsbHumanInterfaceDevice},
-       {},
-       Step::kUsbInsertAndActivate},
-
-      // Windows authenticator will bypass the UI unless caBLE is also
-      // available.
-      {RequestType::kGetAssertion,
-       {},
-       {TransportAvailabilityParam::kHasWinNativeAuthenticator},
-       Step::kNotStarted},
-      {RequestType::kGetAssertion,
-       {AuthenticatorTransport::kCloudAssistedBluetoothLowEnergy},
-       {TransportAvailabilityParam::kHasWinNativeAuthenticator,
-        TransportAvailabilityParam::kHasCableExtension},
-       Step::kCableActivate},
+      // On Windows, if there are linked phones we'll show a selection sheet for
+      // makeCredential.
+      {mc, {cable}, {has_winapi}, {"a"}, {winapi, p("a")}, tss},
+      // ... but not for getAssertion (currently).
+      {ga, {cable}, {has_winapi}, {"a"}, {winapi, p("a")}, plat_ui},
   };
 
-  for (const auto& test_case : kTestCases) {
-    SCOPED_TRACE(static_cast<int>(test_case.expected_first_step));
-    SCOPED_TRACE((SetToString<TransportAvailabilityParam,
-                              TransportAvailabilityParamToString>(
-        test_case.transport_params)));
+  unsigned test_num = 0;
+  for (const auto& test : kTests) {
+    SCOPED_TRACE(static_cast<int>(test.expected_first_step));
+    SCOPED_TRACE(
+        (SetToString<TransportAvailabilityParam,
+                     TransportAvailabilityParamToString>(test.params)));
     SCOPED_TRACE((SetToString<device::FidoTransportProtocol, device::ToString>(
-        test_case.available_transports)));
-    SCOPED_TRACE(RequestTypeToString(test_case.request_type));
+        test.transports)));
+    SCOPED_TRACE(RequestTypeToString(test.request_type));
+    SCOPED_TRACE(test_num++);
 
     TransportAvailabilityInfo transports_info;
     transports_info.is_ble_powered = true;
-    transports_info.request_type = test_case.request_type;
-    transports_info.available_transports = test_case.available_transports;
+    transports_info.request_type = test.request_type;
+    transports_info.available_transports = test.transports;
 
     transports_info.has_recognized_platform_authenticator_credential =
-        base::Contains(test_case.transport_params,
+        base::Contains(test.params,
                        TransportAvailabilityParam::kHasPlatformCredential);
 
     if (base::Contains(
-            test_case.transport_params,
+            test.params,
             TransportAvailabilityParam::kHasWinNativeAuthenticator)) {
       transports_info.has_win_native_api_authenticator = true;
       transports_info.win_native_api_authenticator_id = "some_authenticator_id";
@@ -295,15 +232,39 @@
 
     AuthenticatorRequestDialogModel model(/*relying_party_id=*/"example.com");
 
-    if (base::Contains(test_case.transport_params,
-                       TransportAvailabilityParam::kHasCableExtension)) {
-      model.set_cable_transport_info(true, {}, base::DoNothing(),
-                                     base::nullopt);
+    base::Optional<bool> has_v2_cable_extension;
+    if (base::Contains(test.params,
+                       TransportAvailabilityParam::kHasCableV1Extension)) {
+      has_v2_cable_extension = false;
+    }
+
+    if (base::Contains(test.params,
+                       TransportAvailabilityParam::kHasCableV2Extension)) {
+      CHECK(!has_v2_cable_extension.has_value());
+      has_v2_cable_extension = true;
+    }
+
+    if (has_v2_cable_extension.has_value() || !test.phone_names.empty()) {
+      std::vector<AuthenticatorRequestDialogModel::PairedPhone> phones;
+      for (const auto& name : test.phone_names) {
+        std::array<uint8_t, device::kP256X962Length> public_key = {0};
+        public_key[0] = base::checked_cast<uint8_t>(phones.size());
+        phones.emplace_back(name, /*contact_id=*/0, public_key);
+      }
+      model.set_cable_transport_info(has_v2_cable_extension, std::move(phones),
+                                     base::DoNothing(), base::nullopt);
     }
 
     model.StartFlow(std::move(transports_info),
                     /*use_location_bar_bubble=*/false);
-    EXPECT_EQ(test_case.expected_first_step, model.current_step());
+    EXPECT_EQ(test.expected_first_step, model.current_step());
+
+    std::vector<AuthenticatorRequestDialogModel::Mechanism::Type>
+        mechanism_types;
+    for (const auto& mech : model.mechanisms()) {
+      mechanism_types.push_back(mech.type);
+    }
+    EXPECT_EQ(test.expected_mechanisms, mechanism_types);
 
     if (!model.offer_try_again_in_ui()) {
       continue;
@@ -314,25 +275,6 @@
   }
 }
 
-TEST_F(AuthenticatorRequestDialogModelTest, TransportList) {
-  for (const bool cable_extension_provided : {false, true}) {
-    TransportAvailabilityInfo transports_info;
-    transports_info.available_transports = kAllTransports;
-    AuthenticatorRequestDialogModel model(/*relying_party_id=*/"example.com");
-    model.set_cable_transport_info(cable_extension_provided, {},
-                                   base::DoNothing(),
-                                   /*cable_qr_string=*/base::nullopt);
-    model.StartFlow(std::move(transports_info),
-                    /*use_location_bar_bubble=*/false);
-    EXPECT_THAT(model.available_transports(),
-                ::testing::UnorderedElementsAre(
-                    AuthenticatorTransport::kUsbHumanInterfaceDevice,
-                    AuthenticatorTransport::kNearFieldCommunication,
-                    AuthenticatorTransport::kInternal,
-                    AuthenticatorTransport::kCloudAssistedBluetoothLowEnergy));
-  }
-}
-
 TEST_F(AuthenticatorRequestDialogModelTest, NoAvailableTransports) {
   testing::StrictMock<MockDialogModelObserver> mock_observer;
   AuthenticatorRequestDialogModel model(/*relying_party_id=*/"example.com");
@@ -408,6 +350,7 @@
 
   for (const auto test_case : kTestCases) {
     TransportAvailabilityInfo transports_info;
+    transports_info.request_type = RequestType::kGetAssertion;
     transports_info.available_transports = {test_case.transport};
     transports_info.can_power_on_ble_adapter = true;
     transports_info.is_ble_powered = true;
@@ -435,6 +378,7 @@
 
   for (const auto test_case : kTestCases) {
     TransportAvailabilityInfo transports_info;
+    transports_info.request_type = RequestType::kGetAssertion;
     transports_info.available_transports = {test_case.transport};
     transports_info.can_power_on_ble_adapter = false;
     transports_info.is_ble_powered = false;
@@ -477,6 +421,7 @@
 
   for (const auto test_case : kTestCases) {
     TransportAvailabilityInfo transports_info;
+    transports_info.request_type = RequestType::kGetAssertion;
     transports_info.available_transports = {test_case.transport};
     transports_info.can_power_on_ble_adapter = true;
     transports_info.is_ble_powered = false;
@@ -527,17 +472,17 @@
 
   // Simulate switching back and forth between transports. The request callback
   // should only be invoked once (USB is not dispatched through the UI).
-  model.StartGuidedFlowForTransport(AuthenticatorTransport::kInternal);
+  model.StartTransportFlowForTesting(AuthenticatorTransport::kInternal);
   EXPECT_TRUE(model.should_dialog_be_hidden());
   task_environment_.FastForwardUntilNoTasksRemain();
   EXPECT_EQ(1, num_called);
-  model.StartGuidedFlowForTransport(
+  model.StartTransportFlowForTesting(
       AuthenticatorTransport::kUsbHumanInterfaceDevice);
   EXPECT_EQ(AuthenticatorRequestDialogModel::Step::kUsbInsertAndActivate,
             model.current_step());
   task_environment_.FastForwardUntilNoTasksRemain();
   EXPECT_EQ(1, num_called);
-  model.StartGuidedFlowForTransport(AuthenticatorTransport::kInternal);
+  model.StartTransportFlowForTesting(AuthenticatorTransport::kInternal);
   EXPECT_TRUE(model.should_dialog_be_hidden());
   task_environment_.FastForwardUntilNoTasksRemain();
   EXPECT_EQ(1, num_called);
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
index 68274bc..a9fcb8c 100644
--- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
+++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
@@ -702,8 +702,7 @@
   if (!weak_dialog_model_)
     return;
 
-  weak_dialog_model_->SetCurrentStep(
-      AuthenticatorRequestDialogModel::Step::kClientPinTapAgain);
+  weak_dialog_model_->FinishCollectToken();
 }
 
 void ChromeAuthenticatorRequestDelegate::OnRetryUserVerification(int attempts) {
diff --git a/chrome/browser/webauthn/chrome_webauthn_browsertest.cc b/chrome/browser/webauthn/chrome_webauthn_browsertest.cc
index d8c9429..824130a 100644
--- a/chrome/browser/webauthn/chrome_webauthn_browsertest.cc
+++ b/chrome/browser/webauthn/chrome_webauthn_browsertest.cc
@@ -227,7 +227,7 @@
             // should fallback to the lower-priority phone with the same name.
             base::SequencedTaskRunnerHandle::Get()->PostTask(
                 FROM_HERE, base::BindLambdaForTesting([this]() {
-                  parent_->model()->ContactPhone("name2");
+                  parent_->model()->ContactPhoneForTesting("name2");
                 }));
             break;
 
@@ -235,7 +235,7 @@
             // Try some other phones.
             base::SequencedTaskRunnerHandle::Get()->PostTask(
                 FROM_HERE, base::BindLambdaForTesting([this]() {
-                  parent_->model()->ContactPhone("zzz");
+                  parent_->model()->ContactPhoneForTesting("zzz");
                 }));
             break;
 
@@ -243,7 +243,7 @@
             // Try some other phones.
             base::SequencedTaskRunnerHandle::Get()->PostTask(
                 FROM_HERE, base::BindLambdaForTesting([this]() {
-                  parent_->model()->ContactPhone("aaa");
+                  parent_->model()->ContactPhoneForTesting("aaa");
                 }));
             break;
 
@@ -368,7 +368,7 @@
       }
 
       // Simulate a click on the transport selection sheet.
-      parent_->model()->ContactPhone("name2");
+      parent_->model()->ContactPhoneForTesting("name2");
     }
 
    private:
diff --git a/chrome/browser/xsurface/BUILD.gn b/chrome/browser/xsurface/BUILD.gn
index 12197dd..8f8f4b3 100644
--- a/chrome/browser/xsurface/BUILD.gn
+++ b/chrome/browser/xsurface/BUILD.gn
@@ -7,6 +7,7 @@
 android_library("java") {
   sources = [
     "android/java/src/org/chromium/chrome/browser/xsurface/FeedActionsHandler.java",
+    "android/java/src/org/chromium/chrome/browser/xsurface/FeedLoggingDependencyProvider.java",
     "android/java/src/org/chromium/chrome/browser/xsurface/HybridListRenderer.java",
     "android/java/src/org/chromium/chrome/browser/xsurface/ImageFetchClient.java",
     "android/java/src/org/chromium/chrome/browser/xsurface/ImagePrefetcher.java",
diff --git a/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/FeedActionsHandler.java b/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/FeedActionsHandler.java
index 7e10777..b78d518 100644
--- a/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/FeedActionsHandler.java
+++ b/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/FeedActionsHandler.java
@@ -37,7 +37,10 @@
     /**
      * Stores a view FeedAction for eventual upload. 'data' is a serialized FeedAction protobuf
      * message.
+     *
+     * This is in the process of being removed, replaced by FeedLoggingDependencyProvider.
      */
+    @Deprecated
     default void processViewAction(byte[] data) {}
 
     /**
diff --git a/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/FeedLoggingDependencyProvider.java b/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/FeedLoggingDependencyProvider.java
new file mode 100644
index 0000000..61429a5
--- /dev/null
+++ b/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/FeedLoggingDependencyProvider.java
@@ -0,0 +1,41 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.xsurface;
+
+/**
+ * Methods to be implemented by Chrome to support Feed logging.
+ */
+public interface FeedLoggingDependencyProvider {
+    /** Returns whether or not activity logging should be enabled. */
+    default boolean isActivityLoggingEnabled() {
+        return false;
+    }
+
+    /** Returns the account name of the signed-in user, or the empty string. */
+    default String getAccountName() {
+        return "";
+    }
+
+    /** Returns the client instance id for this chrome. */
+    default String getClientInstanceId() {
+        return "";
+    }
+
+    /** Returns the collection of currently active experiment ids. */
+    default int[] getExperimentIds() {
+        return new int[0];
+    }
+
+    /** Returns the signed-out session id */
+    default String getSignedOutSessionId() {
+        return "";
+    }
+
+    /**
+     * Stores a view FeedAction for eventual upload. 'data' is a serialized FeedAction protobuf
+     * message.
+     */
+    default void processViewAction(byte[] data) {}
+}
diff --git a/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/SurfaceScopeDependencyProvider.java b/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/SurfaceScopeDependencyProvider.java
index d43a0c1..08ee690 100644
--- a/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/SurfaceScopeDependencyProvider.java
+++ b/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/SurfaceScopeDependencyProvider.java
@@ -14,7 +14,7 @@
  *
  * Should only be called on the UI thread.
  */
-public interface SurfaceScopeDependencyProvider {
+public interface SurfaceScopeDependencyProvider extends FeedLoggingDependencyProvider {
     /** Returns the activity. */
     @Nullable
     default Activity getActivity() {
@@ -32,31 +32,6 @@
         return false;
     }
 
-    /** Returns whether or not activity logging is enabled for this surface */
-    default boolean isActivityLoggingEnabled() {
-        return false;
-    }
-
-    /** Returns the account name of the signed-in user, or the empty string. */
-    default String getAccountName() {
-        return "";
-    }
-
-    /** Returns the client instance id for this chrome. */
-    default String getClientInstanceId() {
-        return "";
-    }
-
-    /** Returns the collection of currently active experiment ids. */
-    default int[] getExperimentIds() {
-        return new int[0];
-    }
-
-    /** Returns the signed-out session id */
-    default String getSignedOutSessionId() {
-        return "";
-    }
-
     /** User-set preference for when videos are eligible to autoplay. */
     public enum AutoplayPreference {
         /** Autoplay is disabled. */
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 1b8f2de..431d57c2 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-master-1620916330-7a3b232f9d2c1b14ceee527b3c5764a18f88f4d6.profdata
+chrome-win32-master-1620939486-fdd70b8b1eac79789487b1f6bfb9d285d39b62c5.profdata
diff --git a/chrome/chrome_cleaner/ipc/mojo_chrome_prompt_ipc.cc b/chrome/chrome_cleaner/ipc/mojo_chrome_prompt_ipc.cc
index a1856f10..5d6c454 100644
--- a/chrome/chrome_cleaner/ipc/mojo_chrome_prompt_ipc.cc
+++ b/chrome/chrome_cleaner/ipc/mojo_chrome_prompt_ipc.cc
@@ -157,14 +157,11 @@
       base::BindOnce(&MojoChromePromptIPC::OnChromeResponseReceived,
                      base::Unretained(this), std::move(callback));
 
-  const auto& version_callback = base::BindRepeating(
-      &MojoChromePromptIPC::PromptUserCheckVersion, base::Unretained(this),
-      std::move(files_to_delete), std::move(registry_keys),
-      // Uses the AdaptCallbackForRepeating because we are bound by the mojo API
-      // to use a RepeatingCallback even though this only should be called once.
-      std::move(extension_ids),
-      AdaptCallbackForRepeating(std::move(response_callback)));
-  (*chrome_prompt_service_).QueryVersion(version_callback);
+  (*chrome_prompt_service_)
+      .QueryVersion(base::BindOnce(
+          &MojoChromePromptIPC::PromptUserCheckVersion, base::Unretained(this),
+          std::move(files_to_delete), std::move(registry_keys),
+          std::move(extension_ids), std::move(response_callback)));
 }
 
 }  // namespace chrome_cleaner
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index afc0ce7..a610d9c2 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -761,8 +761,14 @@
     "PredictivePrefetchingAllowedOnAllConnectionTypes",
     base::FEATURE_ENABLED_BY_DEFAULT};
 
-const base::Feature kPrefixWebAppWindowsWithAppName{
-    "PrefixWebAppWindowsWithAppName", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kPrefixWebAppWindowsWithAppName {
+  "PrefixWebAppWindowsWithAppName",
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+      base::FEATURE_ENABLED_BY_DEFAULT
+#else
+      base::FEATURE_DISABLED_BY_DEFAULT
+#endif
+};
 
 // Allows Chrome to do preconnect when prerender fails.
 const base::Feature kPrerenderFallbackToPreconnect{
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 8967e90..4e66441 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -319,6 +319,7 @@
     public_deps += [
       ":test_support_ui_android",
       "//chrome:chrome_android_core",
+      "//components/feed/core/v2:feed_core_stubs",
     ]
     if (enable_vr) {
       public_deps += [ "//chrome/browser/android/vr:test_support" ]
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java
index 8ec6f4b..fa2fd8c 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java
@@ -46,7 +46,6 @@
      */
     public static class TestAutocompleteController extends AutocompleteController {
         private final Map<String, Pair<String, AutocompleteResult>> mAutocompleteResults;
-        private final AutocompleteResult mEmptyResult;
 
         /**
          * Create new Autocomplete controller.
@@ -55,7 +54,6 @@
         public TestAutocompleteController(OnSuggestionsReceivedListener listener) {
             super(profile -> {});
             mAutocompleteResults = new HashMap<>();
-            mEmptyResult = new AutocompleteResult(null, null);
             setOnSuggestionsReceivedListener(listener);
         }
 
diff --git a/chrome/test/base/test_switches.cc b/chrome/test/base/test_switches.cc
index 9c415dc..81205746 100644
--- a/chrome/test/base/test_switches.cc
+++ b/chrome/test/base/test_switches.cc
@@ -11,6 +11,10 @@
 // Also emit full event trace logs for successful tests.
 const char kAlsoEmitSuccessLogs[] = "also-emit-success-logs";
 
+// Directory to output JavaScript code coverage. When supplied enables coverage
+// in selected browser tests.
+const char kDevtoolsCodeCoverage[] = "devtools-code-coverage";
+
 // Show the mean value of histograms that native performance tests
 // are monitoring. Note that this is only applicable for PerformanceTest
 // subclasses.
diff --git a/chrome/test/base/test_switches.h b/chrome/test/base/test_switches.h
index cc248b4ab..86adf8e 100644
--- a/chrome/test/base/test_switches.h
+++ b/chrome/test/base/test_switches.h
@@ -14,6 +14,8 @@
 // alongside the definition of their values in the .cc file.
 extern const char kAlsoEmitSuccessLogs[];
 
+extern const char kDevtoolsCodeCoverage[];
+
 extern const char kPerfTestPrintUmaMeans[];
 
 #if defined(OS_WIN)
diff --git a/chrome/test/chromedriver/net/adb_client_socket.cc b/chrome/test/chromedriver/net/adb_client_socket.cc
index 765117e3..40b0c7b 100644
--- a/chrome/test/chromedriver/net/adb_client_socket.cc
+++ b/chrome/test/chromedriver/net/adb_client_socket.cc
@@ -420,13 +420,12 @@
     scoped_refptr<net::StringIOBuffer> request_buffer =
         base::MakeRefCounted<net::StringIOBuffer>(buffer);
 
-    net::CompletionRepeatingCallback copyable_callback =
-        base::AdaptCallbackForRepeating(std::move(callback));
-    int result =
-        socket_->Write(request_buffer.get(), request_buffer->size(),
-                       copyable_callback, TRAFFIC_ANNOTATION_FOR_TESTS);
+    auto split_callback = base::SplitOnceCallback(std::move(callback));
+    int result = socket_->Write(request_buffer.get(), request_buffer->size(),
+                                std::move(split_callback.first),
+                                TRAFFIC_ANNOTATION_FOR_TESTS);
     if (result != net::ERR_IO_PENDING)
-      copyable_callback.Run(result);
+      std::move(split_callback.second).Run(result);
   }
 
   bool CheckNetResultOrDie(int result) {
@@ -510,11 +509,10 @@
   socket_ = std::make_unique<net::TCPClientSocket>(
       address_list, nullptr, nullptr, nullptr, net::NetLogSource());
 
-  net::CompletionRepeatingCallback copyable_callback =
-      base::AdaptCallbackForRepeating(std::move(callback));
-  int result = socket_->Connect(copyable_callback);
+  auto split_callback = base::SplitOnceCallback(std::move(callback));
+  int result = socket_->Connect(std::move(split_callback.first));
   if (result != net::ERR_IO_PENDING)
-    copyable_callback.Run(result);
+    std::move(split_callback.second).Run(result);
 }
 
 void AdbClientSocket::SendCommand(const std::string& command,
diff --git a/chrome/test/data/devtools/extensions/simple_background_page/background.js b/chrome/test/data/devtools/extensions/simple_background_page/background.js
new file mode 100644
index 0000000..4eb6a94d
--- /dev/null
+++ b/chrome/test/data/devtools/extensions/simple_background_page/background.js
@@ -0,0 +1,5 @@
+// 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.
+
+console.log('Hello world');
diff --git a/chrome/test/data/devtools/extensions/simple_background_page/manifest.json b/chrome/test/data/devtools/extensions/simple_background_page/manifest.json
new file mode 100644
index 0000000..86e0caa
--- /dev/null
+++ b/chrome/test/data/devtools/extensions/simple_background_page/manifest.json
@@ -0,0 +1,9 @@
+{
+   "description": "Test Extension - Simple Background Page",
+   "name": "Test Extension - Simple Background Page",
+   "version": "0.1",
+   "manifest_version": 2,
+   "background":  {
+       "scripts": [ "background.js" ]
+   }
+}
diff --git a/chrome/test/data/extensions/api_test/content_scripts/inject_div/manifest.json b/chrome/test/data/extensions/api_test/content_scripts/inject_div/manifest.json
new file mode 100644
index 0000000..6122cf3
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/content_scripts/inject_div/manifest.json
@@ -0,0 +1,12 @@
+{
+  "manifest_version": 2,
+  "name": "Script injects div",
+  "version": "0.1",
+  "description": "Injects a div using its content script",
+  "content_scripts": [{
+    "matches": ["*://*/*"],
+    "js": ["script.js"],
+    "all_frames": true,
+    "run_at": "document_end"
+  }]
+}
diff --git a/chrome/test/data/extensions/api_test/content_scripts/inject_div/script.js b/chrome/test/data/extensions/api_test/content_scripts/inject_div/script.js
new file mode 100644
index 0000000..dcaf9f2
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/content_scripts/inject_div/script.js
@@ -0,0 +1,7 @@
+// 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.
+
+var div = document.createElement('div');
+div.id = 'injected';
+document.body.appendChild(div);
diff --git a/chrome/test/data/extensions/platform_apps/web_view/a_com_webview/content_script.js b/chrome/test/data/extensions/platform_apps/web_view/a_com_webview/content_script.js
new file mode 100644
index 0000000..01bd7f3
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/a_com_webview/content_script.js
@@ -0,0 +1,8 @@
+// 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.
+
+if (document.body.childElementCount > 0)
+  chrome.test.sendMessage('WebViewTest.UNKNOWN_ELEMENT_INJECTED');
+else
+  chrome.test.sendMessage('WebViewTest.NO_ELEMENT_INJECTED');
diff --git a/chrome/test/data/extensions/platform_apps/web_view/a_com_webview/main.html b/chrome/test/data/extensions/platform_apps/web_view/a_com_webview/main.html
new file mode 100644
index 0000000..f1bdb964
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/a_com_webview/main.html
@@ -0,0 +1,10 @@
+<!--
+ * 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.
+-->
+<html>
+<body>
+  <script src="main.js"></script>
+</body>
+</html>
diff --git a/chrome/test/data/extensions/platform_apps/web_view/a_com_webview/main.js b/chrome/test/data/extensions/platform_apps/web_view/a_com_webview/main.js
new file mode 100644
index 0000000..81a2f72
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/a_com_webview/main.js
@@ -0,0 +1,35 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function createWebViewAndGuest(config) {
+  var webview = document.createElement('webview');
+  webview.addContentScripts([{
+    name: 'rule',
+    matches: ['*://*/*'],
+    js: { files: ['content_script.js'] },
+    run_at: 'document_idle'}]);
+
+  webview.src = `http://a.com:${config.testServer.port}/simple.html`;
+  document.body.appendChild(webview);
+
+  var onLoadStop = function(e) {
+    chrome.test.sendMessage('WebViewTest.LAUNCHED');
+    webview.removeEventListener('loadstop', onLoadStop);
+    webview.removeEventListener('loadabort', onLoadAbort);
+  };
+  webview.addEventListener('loadstop', onLoadStop);
+
+  var onLoadAbort = function() {
+    chrome.test.sendMessage('WebViewTest.FAILURE');
+    webview.removeEventListener('loadstop', onLoadStop);
+    webview.removeEventListener('loadabort', onLoadAbort);
+  };
+  webview.addEventListener('loadabort', onLoadAbort);
+}
+
+onload = function() {
+  chrome.test.getConfig(function(config) {
+    createWebViewAndGuest(config);
+  });
+};
diff --git a/chrome/test/data/extensions/platform_apps/web_view/a_com_webview/manifest.json b/chrome/test/data/extensions/platform_apps/web_view/a_com_webview/manifest.json
new file mode 100644
index 0000000..aad8335
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/a_com_webview/manifest.json
@@ -0,0 +1,13 @@
+{
+  "name": "<webview> which loads a.com",
+  "manifest_version": 2,
+  "version": "1",
+  "permissions": [
+    "webview"
+  ],
+  "app": {
+    "background": {
+      "scripts": ["test.js"]
+    }
+  }
+}
diff --git a/chrome/test/data/extensions/platform_apps/web_view/a_com_webview/test.js b/chrome/test/data/extensions/platform_apps/web_view/a_com_webview/test.js
new file mode 100644
index 0000000..ac544c9f
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/a_com_webview/test.js
@@ -0,0 +1,7 @@
+// 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.
+
+chrome.app.runtime.onLaunched.addListener(function() {
+  chrome.app.window.create('main.html', {}, function () {});
+});
diff --git a/chrome/test/data/webui/chromeos/ash_common/BUILD.gn b/chrome/test/data/webui/chromeos/ash_common/BUILD.gn
index 77e335f..9ae4f89 100644
--- a/chrome/test/data/webui/chromeos/ash_common/BUILD.gn
+++ b/chrome/test/data/webui/chromeos/ash_common/BUILD.gn
@@ -50,6 +50,7 @@
 js_library("navigation_view_panel_test") {
   deps = [
     "../..:chai_assert",
+    "//ash/content/common/resources:navigation_selector",
     "//ash/content/common/resources:navigation_view_panel",
   ]
 }
diff --git a/chrome/test/data/webui/chromeos/ash_common/navigation_view_panel_test.js b/chrome/test/data/webui/chromeos/ash_common/navigation_view_panel_test.js
index d52a1fb..632adf01 100644
--- a/chrome/test/data/webui/chromeos/ash_common/navigation_view_panel_test.js
+++ b/chrome/test/data/webui/chromeos/ash_common/navigation_view_panel_test.js
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {SelectorItem} from 'chrome://resources/ash/common/navigation_selector.js';
 import {NavigationViewPanelElement} from 'chrome://resources/ash/common/navigation_view_panel.js';
 
 import {assertFalse, assertTrue} from '../../chai_assert.js';
@@ -59,4 +60,30 @@
     assertTrue(dummyElement2.hidden);
     assertFalse(dummyElement1.hidden);
   });
+
+  test('defaultPage', async () => {
+    const dummyPage1 = 'dummy-page1';
+    const dummyPage2 = 'dummy-page2';
+
+    viewElement.addSelector('dummyPage1', dummyPage1);
+    viewElement.addSelector('dummyPage2', dummyPage2);
+
+    assertFalse(viewElement.shadowRoot.querySelector(`#${dummyPage1}`).hidden);
+    assertFalse(!!viewElement.shadowRoot.querySelector(`#${dummyPage2}`));
+  });
+
+  test('defaultCollapsiblePage', async () => {
+    const dummyPage1 = 'dummy-page1';
+    const dummyPage2 = 'dummy-page2';
+    const subPage = 'sub-page1';
+
+    let subItem =
+        /** @type {SelectorItem} */ ({'name': 'subItem', 'pageIs': subPage});
+
+    viewElement.addSelector('dummyPage1', dummyPage1, [subItem]);
+    viewElement.addSelector('dummyPage2', dummyPage2);
+
+    assertFalse(viewElement.shadowRoot.querySelector(`#${subPage}`).hidden);
+    assertFalse(!!viewElement.shadowRoot.querySelector(`#${dummyPage2}`));
+  });
 }
diff --git a/chrome/test/data/webui/chromeos/scanning/scanning_app_test.js b/chrome/test/data/webui/chromeos/scanning/scanning_app_test.js
index 5f1f6c96..be680ae 100644
--- a/chrome/test/data/webui/chromeos/scanning/scanning_app_test.js
+++ b/chrome/test/data/webui/chromeos/scanning/scanning_app_test.js
@@ -1419,10 +1419,9 @@
         new Date(scannerToKeep.lastScanDate) >
         new Date(scannerToEvict.lastScanDate));
 
-
+    /** @type {!Array<!ScannerSetting>} */
     const scannersToKeep =
-        /** @type {!Array<ScannerSetting>} */ (
-            new Array(MAX_NUM_SAVED_SCANNERS).fill(scannerToKeep));
+        new Array(MAX_NUM_SAVED_SCANNERS).fill(scannerToKeep);
 
     // Put |scannerToEvict| in the front of |scannersToKeep| to test that it
     // get correctly sorted to the back of the array when evicting scanners.
@@ -1456,8 +1455,8 @@
       return;
     }
 
-    const scanners = /** @type {!Array<ScannerSetting>} */ (
-        new Array(MAX_NUM_SAVED_SCANNERS));
+    /** @type {!Array<!ScannerSetting>} */
+    const scanners = new Array(MAX_NUM_SAVED_SCANNERS);
     for (let i = 0; i < MAX_NUM_SAVED_SCANNERS; i++) {
       scanners[i] = {
         name: 'Scanner ' + (i + 1),
diff --git a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/cellular_eid_dialog_test.js b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/cellular_eid_dialog_test.js
index dd94656..472f270 100644
--- a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/cellular_eid_dialog_test.js
+++ b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/cellular_eid_dialog_test.js
@@ -49,11 +49,11 @@
   test('Should render EID QRCode', async function() {
     await init({size: 2, data: [1, 0, 0, 1]});
     const qrCodeCanvas = eidDialog.$$('#qrCodeCanvas');
-    assertEquals(qrCodeCanvas.width, 50);
-    assertEquals(qrCodeCanvas.height, 50);
-    assertDeepEquals(canvasContext.getClearRectCalls(), [[0, 0, 50, 50]]);
+    assertEquals(qrCodeCanvas.width, 10);
+    assertEquals(qrCodeCanvas.height, 10);
+    assertDeepEquals(canvasContext.getClearRectCalls(), [[0, 0, 10, 10]]);
     assertDeepEquals(
-        canvasContext.getFillRectCalls(), [[20, 20, 5, 5], [25, 25, 5, 5]]);
+        canvasContext.getFillRectCalls(), [[0, 0, 5, 5], [5, 5, 5, 5]]);
   });
 
   test('should close EID when done is pressed', async function() {
diff --git a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_test.js b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_test.js
index ea0dcee..9badf3c 100644
--- a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_test.js
+++ b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_test.js
@@ -231,17 +231,11 @@
   /**
    * @param {boolean} forwardButtonShouldBeEnabled
    * @param {cellularSetup.ButtonState} backButtonState
-   * @param {boolean=} opt_cancelButtonShouldBeDisabled
    */
-  function assertButtonState(
-      forwardButtonShouldBeEnabled, backButtonState,
-      opt_cancelButtonShouldBeDisabled) {
+  function assertButtonState(forwardButtonShouldBeEnabled, backButtonState) {
     const buttonState = eSimPage.buttonState;
     assertEquals(buttonState.backward, backButtonState);
-    assertEquals(
-        buttonState.cancel,
-        opt_cancelButtonShouldBeDisabled ? cellularSetup.ButtonState.DISABLED :
-                                           cellularSetup.ButtonState.ENABLED);
+    assertEquals(buttonState.cancel, cellularSetup.ButtonState.ENABLED);
     assertEquals(
         buttonState.forward,
         forwardButtonShouldBeEnabled ? cellularSetup.ButtonState.ENABLED :
@@ -258,8 +252,7 @@
         cellular_setup.ESimPageName.PROFILE_LOADING, profileLoadingPage);
     assertButtonState(
         /*forwardButtonShouldBeEnabled=*/ false,
-        /*backButtonState=*/ cellularSetup.ButtonState.HIDDEN,
-        /*opt_cancelButtonShouldBeDisabled=*/ true);
+        /*backButtonState=*/ cellularSetup.ButtonState.HIDDEN);
     await flushAsync();
   }
 
diff --git a/chrome/test/data/webui/cr_components/chromeos/network/network_list_item_test.js b/chrome/test/data/webui/cr_components/chromeos/network/network_list_item_test.js
index 01bed18..e278131 100644
--- a/chrome/test/data/webui/cr_components/chromeos/network/network_list_item_test.js
+++ b/chrome/test/data/webui/cr_components/chromeos/network/network_list_item_test.js
@@ -126,13 +126,6 @@
       return element ? element.textContent.trim() : '';
     };
 
-    const properties = OncMojo.getDefaultManagedProperties(
-        mojom.NetworkType.kEthernet, 'eth0');
-    mojoApi_.setManagedPropertiesForTest(properties);
-    listItem.item = OncMojo.managedPropertiesToNetworkState(properties);
-    await flushAsync();
-    assertEquals('Ethernet', getTitle());
-
     const euicc = eSimManagerRemote.addEuiccForTest(/*numProfiles=*/ 2);
     const profiles = (await euicc.getProfileList()).profiles;
     assertEquals(2, profiles.length);
@@ -164,6 +157,15 @@
     assertEquals(
         listItem.i18n('networkListItemTitle', 'Cellular', 'provider2'),
         getTitle());
+
+    // Change to network state without provider name and verify that that title
+    // is displayed correctly.
+    const ethernetProperties = OncMojo.getDefaultManagedProperties(
+        mojom.NetworkType.kEthernet, 'eth0');
+    mojoApi_.setManagedPropertiesForTest(ethernetProperties);
+    listItem.item = OncMojo.managedPropertiesToNetworkState(ethernetProperties);
+    await flushAsync();
+    assertEquals('Ethernet', getTitle());
   });
 
   test('Network title is escaped', async () => {
diff --git a/chrome/test/data/webui/settings/chromeos/os_about_page_tests.js b/chrome/test/data/webui/settings/chromeos/os_about_page_tests.js
index 5aa535e0..73ea131b 100644
--- a/chrome/test/data/webui/settings/chromeos/os_about_page_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/os_about_page_tests.js
@@ -118,7 +118,7 @@
 
       fireStatusChanged(UpdateStatus.FAILED);
       assertEquals(null, icon.src);
-      assertEquals('cr:error', icon.icon);
+      assertEquals('cr:error-outline', icon.icon);
       assertEquals(0, statusMessageEl.textContent.trim().length);
 
       fireStatusChanged(UpdateStatus.DISABLED);
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc
index 8982630..8001775 100644
--- a/chromecast/browser/cast_content_browser_client.cc
+++ b/chromecast/browser/cast_content_browser_client.cc
@@ -175,16 +175,14 @@
 #endif  // BUILDFLAG(USE_V4L2_CODEC)
   });
 
-  cast_feature_list_creator_->SetExtraDisableFeatures({
-      // TODO(juke): Reenable this after solving casting issue on LAN.
-      blink::features::kMixedContentAutoupgrade,
 #if defined(OS_ANDROID)
-          ::media::kAudioFocusLossSuspendMediaSession,
-          ::media::kRequestSystemAudioFocus,
-          // Disable AAudio improve AV sync performance.
-          ::features::kUseAAudioDriver,
-#endif
+  cast_feature_list_creator_->SetExtraDisableFeatures({
+      ::media::kAudioFocusLossSuspendMediaSession,
+      ::media::kRequestSystemAudioFocus,
+      // Disable AAudio improve AV sync performance.
+      ::features::kUseAAudioDriver,
   });
+#endif
 }
 
 CastContentBrowserClient::~CastContentBrowserClient() {
@@ -533,11 +531,6 @@
     content::WebContents* web_contents,
     blink::web_pref::WebPreferences* prefs) {
   prefs->allow_scripts_to_close_windows = true;
-  // TODO(halliwell): http://crbug.com/391089. This pref defaults to to true
-  // because some content providers such as YouTube use plain http requests
-  // to retrieve media data chunks while running in a https page. This pref
-  // should be disabled once all the content providers are no longer doing that.
-  prefs->allow_running_insecure_content = true;
 
   // Enable 5% margins for WebVTT cues to keep within title-safe area
   prefs->text_track_margin_percentage = 5;
diff --git a/chromecast/browser/cast_web_contents_impl.cc b/chromecast/browser/cast_web_contents_impl.cc
index 2b389e14..278c7d8 100644
--- a/chromecast/browser/cast_web_contents_impl.cc
+++ b/chromecast/browser/cast_web_contents_impl.cc
@@ -473,10 +473,16 @@
                                 frame_host->GetRemoteAssociatedInterfaces());
   }
 
+  // TODO(b/187758538): Merge the two ConfigureFeatures() calls.
   mojo::Remote<chromecast::shell::mojom::FeatureManager> feature_manager_remote;
   frame_host->GetRemoteInterfaces()->GetInterface(
       feature_manager_remote.BindNewPipeAndPassReceiver());
   feature_manager_remote->ConfigureFeatures(GetRendererFeatures());
+  mojo::AssociatedRemote<chromecast::shell::mojom::FeatureManager>
+      feature_manager_associated_remote;
+  frame_host->GetRemoteAssociatedInterfaces()->GetInterface(
+      &feature_manager_associated_remote);
+  feature_manager_associated_remote->ConfigureFeatures(GetRendererFeatures());
 
   mojo::AssociatedRemote<components::media_control::mojom::MediaPlaybackOptions>
       media_playback_options;
diff --git a/chromecast/common/BUILD.gn b/chromecast/common/BUILD.gn
index e7f14271..311e639 100644
--- a/chromecast/common/BUILD.gn
+++ b/chromecast/common/BUILD.gn
@@ -43,6 +43,13 @@
   ]
 }
 
+cast_source_set("feature_constants") {
+  sources = [
+    "feature_constants.cc",
+    "feature_constants.h",
+  ]
+}
+
 test("cast_common_unittests") {
   testonly = true
 
diff --git a/chromecast/common/feature_constants.cc b/chromecast/common/feature_constants.cc
new file mode 100644
index 0000000..16a0fe6
--- /dev/null
+++ b/chromecast/common/feature_constants.cc
@@ -0,0 +1,13 @@
+// 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 "chromecast/common/feature_constants.h"
+
+namespace chromecast {
+namespace feature {
+
+const char kEnableTrackAppRendererFeatureUse[] = "track_renderer_feature_use";
+
+}  // namespace feature
+}  // namespace chromecast
diff --git a/chromecast/common/feature_constants.h b/chromecast/common/feature_constants.h
new file mode 100644
index 0000000..1deae897
--- /dev/null
+++ b/chromecast/common/feature_constants.h
@@ -0,0 +1,20 @@
+// 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 CHROMECAST_COMMON_FEATURE_CONSTANTS_H_
+#define CHROMECAST_COMMON_FEATURE_CONSTANTS_H_
+
+namespace chromecast {
+namespace feature {
+
+// TODO(b/187758538): Upstream more Feature Constants here.
+
+// TODO(b/187524799): Remove this feature when the related features are
+// deprecated.
+extern const char kEnableTrackAppRendererFeatureUse[];
+
+}  // namespace feature
+}  // namespace chromecast
+
+#endif  // CHROMECAST_COMMON_FEATURE_CONSTANTS_H_
diff --git a/chromecast/renderer/BUILD.gn b/chromecast/renderer/BUILD.gn
index 874fe010..acfedc7 100644
--- a/chromecast/renderer/BUILD.gn
+++ b/chromecast/renderer/BUILD.gn
@@ -40,10 +40,14 @@
     "cast_activity_url_filter_manager.h",
     "cast_content_renderer_client.cc",
     "cast_content_renderer_client.h",
+    "cast_content_settings_client.cc",
+    "cast_content_settings_client.h",
     "cast_url_loader_throttle_provider.cc",
     "cast_url_loader_throttle_provider.h",
     "cast_websocket_handshake_throttle_provider.cc",
     "cast_websocket_handshake_throttle_provider.h",
+    "feature_manager_on_associated_interface.cc",
+    "feature_manager_on_associated_interface.h",
     "identification_settings_manager_renderer.cc",
     "identification_settings_manager_renderer.h",
     "identification_settings_manager_store.h",
@@ -61,6 +65,7 @@
     "//content/public/renderer",
     "//media",
     "//mojo/public/cpp/bindings",
+    "//third_party/blink/public:blink",
     "//v8",
   ]
 
@@ -69,6 +74,7 @@
     "//chromecast/base",
     "//chromecast/common",
     "//chromecast/common:activity_url_filter",
+    "//chromecast/common:feature_constants",
     "//chromecast/common:queryable_data",
     "//chromecast/common/media",
     "//chromecast/crash",
diff --git a/chromecast/renderer/cast_content_renderer_client.cc b/chromecast/renderer/cast_content_renderer_client.cc
index cc3fdbf3..aa69a80 100644
--- a/chromecast/renderer/cast_content_renderer_client.cc
+++ b/chromecast/renderer/cast_content_renderer_client.cc
@@ -18,6 +18,7 @@
 #include "chromecast/public/media/media_capabilities_shlib.h"
 #include "chromecast/renderer/cast_url_loader_throttle_provider.h"
 #include "chromecast/renderer/cast_websocket_handshake_throttle_provider.h"
+#include "chromecast/renderer/feature_manager_on_associated_interface.h"
 #include "chromecast/renderer/identification_settings_manager_renderer.h"
 #include "chromecast/renderer/js_channel_bindings.h"
 #include "chromecast/renderer/media/key_systems_cast.h"
@@ -176,6 +177,7 @@
   DCHECK(render_frame);
 
   // Lifetime is tied to |render_frame| via content::RenderFrameObserver.
+  new FeatureManagerOnAssociatedInterface(render_frame);
   new media_control::MediaPlaybackOptions(render_frame);
 
   // Add script injection support to the RenderFrame, used by Cast platform
diff --git a/chromecast/renderer/cast_content_settings_client.cc b/chromecast/renderer/cast_content_settings_client.cc
new file mode 100644
index 0000000..d96289a8
--- /dev/null
+++ b/chromecast/renderer/cast_content_settings_client.cc
@@ -0,0 +1,57 @@
+// 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 "chromecast/renderer/cast_content_settings_client.h"
+
+#include "base/metrics/user_metrics.h"
+#include "content/public/renderer/render_frame.h"
+#include "third_party/blink/public/platform/web_url.h"
+#include "third_party/blink/public/web/web_local_frame.h"
+
+namespace {
+
+void ReportRendererFeatureUse(const std::string& app_id,
+                              const std::string& feature_name) {
+  std::string action = "Cast.Platform.RendererFeatureUse.";
+  action.append(feature_name);
+  action.append(".");
+  action.append(app_id);
+  base::RecordComputedAction(action);
+}
+
+}  // namespace
+
+namespace chromecast {
+
+CastContentSettingsClient::CastContentSettingsClient(
+    content::RenderFrame* render_frame,
+    const std::string& app_id)
+    : content::RenderFrameObserver(render_frame), app_id_(app_id) {
+  render_frame->GetWebFrame()->SetContentSettingsClient(this);
+}
+
+CastContentSettingsClient::~CastContentSettingsClient() {}
+
+bool CastContentSettingsClient::AllowRunningInsecureContent(
+    bool enabled_per_settings,
+    const blink::WebURL& url) {
+  ReportRendererFeatureUse(app_id_, "ActiveInsecureContent");
+  return true;
+}
+
+void CastContentSettingsClient::PassiveInsecureContentFound(
+    const blink::WebURL&) {
+  ReportRendererFeatureUse(app_id_, "PassiveInsecureContent");
+}
+
+bool CastContentSettingsClient::ShouldAutoupgradeMixedContent() {
+  ReportRendererFeatureUse(app_id_, "DisableAutoUpgradeMixedContent");
+  return false;
+}
+
+void CastContentSettingsClient::OnDestruct() {
+  delete this;
+}
+
+}  // namespace chromecast
diff --git a/chromecast/renderer/cast_content_settings_client.h b/chromecast/renderer/cast_content_settings_client.h
new file mode 100644
index 0000000..7e6ba2b
--- /dev/null
+++ b/chromecast/renderer/cast_content_settings_client.h
@@ -0,0 +1,43 @@
+// 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 CHROMECAST_RENDERER_CAST_CONTENT_SETTINGS_CLIENT_H_
+#define CHROMECAST_RENDERER_CAST_CONTENT_SETTINGS_CLIENT_H_
+
+#include "base/macros.h"
+#include "content/public/renderer/render_frame_observer.h"
+#include "third_party/blink/public/platform/web_content_settings_client.h"
+
+namespace chromecast {
+
+// Chromecast implementation of blink::WebContentSettingsClient.
+class CastContentSettingsClient : public content::RenderFrameObserver,
+                                  public blink::WebContentSettingsClient {
+ public:
+  CastContentSettingsClient(content::RenderFrame* render_view,
+                            const std::string& app_id);
+  CastContentSettingsClient(const CastContentSettingsClient&) = delete;
+  CastContentSettingsClient& operator=(const CastContentSettingsClient&) =
+      delete;
+
+ private:
+  ~CastContentSettingsClient() override;
+
+  // content::RenderFrameObserver implementation.
+  void OnDestruct() override;
+
+  // blink::WebContentSettingsClient implementation.
+  bool AllowRunningInsecureContent(bool enabled_per_settings,
+                                   const blink::WebURL& url) override;
+  void PassiveInsecureContentFound(const blink::WebURL&) override;
+  bool ShouldAutoupgradeMixedContent() override;
+
+  std::string app_id_;
+  // TODO(b/150022618): Add decisions from Cast service to control the
+  // availibilitiy of the Renderer features.
+};
+
+}  // namespace chromecast
+
+#endif  // CHROMECAST_RENDERER_CAST_CONTENT_SETTINGS_CLIENT_H_
diff --git a/chromecast/renderer/feature_manager_on_associated_interface.cc b/chromecast/renderer/feature_manager_on_associated_interface.cc
new file mode 100644
index 0000000..62752bb
--- /dev/null
+++ b/chromecast/renderer/feature_manager_on_associated_interface.cc
@@ -0,0 +1,80 @@
+// 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 "chromecast/renderer/feature_manager_on_associated_interface.h"
+
+#include "base/check.h"
+#include "base/logging.h"
+#include "base/values.h"
+#include "chromecast/base/cast_features.h"
+#include "chromecast/common/feature_constants.h"
+#include "chromecast/renderer/cast_content_settings_client.h"
+#include "content/public/renderer/render_frame.h"
+
+namespace chromecast {
+FeatureManagerOnAssociatedInterface::FeatureManagerOnAssociatedInterface(
+    content::RenderFrame* render_frame)
+    : content::RenderFrameObserver(render_frame), configured_(false) {
+  registry_.AddInterface(base::BindRepeating(
+      &FeatureManagerOnAssociatedInterface::OnFeatureManagerAssociatedRequest,
+      base::Unretained(this)));
+}
+
+FeatureManagerOnAssociatedInterface::~FeatureManagerOnAssociatedInterface() {}
+
+bool FeatureManagerOnAssociatedInterface::OnAssociatedInterfaceRequestForFrame(
+    const std::string& interface_name,
+    mojo::ScopedInterfaceEndpointHandle* handle) {
+  return registry_.TryBindInterface(interface_name, handle);
+}
+
+void FeatureManagerOnAssociatedInterface::OnDestruct() {
+  delete this;
+}
+
+void FeatureManagerOnAssociatedInterface::ConfigureFeatures(
+    std::vector<chromecast::shell::mojom::FeaturePtr> features) {
+  if (configured_)
+    return;
+  configured_ = true;
+  for (auto& feature : features) {
+    // If we want to add enabled/disabled status to FeaturePtr, we can overlap
+    // previous setting via [] operator
+    features_map_[feature->name] = std::move(feature);
+  }
+
+  if (FeatureEnabled(feature::kEnableTrackAppRendererFeatureUse)) {
+    std::string app_id("MissingAppId");
+    auto& feature = GetFeature(feature::kEnableTrackAppRendererFeatureUse);
+    std::string* app_id_received = feature->config.FindStringPath("app_id");
+    if (app_id_received) {
+      app_id = *app_id_received;
+    } else {
+      LOG(ERROR) << __func__ << " failed to receive valid app_id";
+    }
+    // Lifetime is tied to |render_frame| via content::RenderFrameObserver.
+    new CastContentSettingsClient(render_frame(), app_id);
+  }
+}
+
+void FeatureManagerOnAssociatedInterface::OnFeatureManagerAssociatedRequest(
+    mojo::PendingAssociatedReceiver<shell::mojom::FeatureManager>
+        pending_receiver) {
+  receivers_.Add(this, std::move(pending_receiver));
+}
+
+bool FeatureManagerOnAssociatedInterface::FeatureEnabled(
+    const std::string& feature) const {
+  return features_map_.find(feature) != features_map_.end();
+}
+
+const chromecast::shell::mojom::FeaturePtr&
+FeatureManagerOnAssociatedInterface::GetFeature(
+    const std::string& feature) const {
+  auto itor = features_map_.find(feature);
+  DCHECK(itor != features_map_.end());
+  return itor->second;
+}
+
+}  // namespace chromecast
diff --git a/chromecast/renderer/feature_manager_on_associated_interface.h b/chromecast/renderer/feature_manager_on_associated_interface.h
new file mode 100644
index 0000000..e960e2f
--- /dev/null
+++ b/chromecast/renderer/feature_manager_on_associated_interface.h
@@ -0,0 +1,71 @@
+// 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 CHROMECAST_RENDERER_FEATURE_MANAGER_ON_ASSOCIATED_INTERFACE_H_
+#define CHROMECAST_RENDERER_FEATURE_MANAGER_ON_ASSOCIATED_INTERFACE_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/values.h"
+#include "chromecast/common/mojom/feature_manager.mojom.h"
+#include "content/public/renderer/render_frame_observer.h"
+#include "mojo/public/cpp/bindings/associated_receiver_set.h"
+#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
+
+namespace chromecast {
+
+// Similar to the internal FeatureManager, but it's attached to associated
+// interface to ensure the actions are taken before the webpage is loaded.
+// TODO(b/187758538): Refactor this class with the internal FeatureManager. The
+// most likely result is we upstream and merge the internal FeatureManager to
+// this class and rename this class to FeatureManager.
+class FeatureManagerOnAssociatedInterface
+    : public content::RenderFrameObserver,
+      public shell::mojom::FeatureManager {
+ public:
+  explicit FeatureManagerOnAssociatedInterface(
+      content::RenderFrame* render_frame);
+  FeatureManagerOnAssociatedInterface(
+      const FeatureManagerOnAssociatedInterface&) = delete;
+  FeatureManagerOnAssociatedInterface& operator=(
+      const FeatureManagerOnAssociatedInterface&) = delete;
+  ~FeatureManagerOnAssociatedInterface() override;
+
+  bool FeatureEnabled(const std::string& feature) const;
+  const chromecast::shell::mojom::FeaturePtr& GetFeature(
+      const std::string& feature) const;
+
+ private:
+  // content::RenderFrameObserver implementation:
+  bool OnAssociatedInterfaceRequestForFrame(
+      const std::string& interface_name,
+      mojo::ScopedInterfaceEndpointHandle* handle) override;
+  void OnDestruct() override;
+
+  // shell::mojom::FeatureManager implementation
+  void ConfigureFeatures(
+      std::vector<chromecast::shell::mojom::FeaturePtr> features) override;
+
+  // Bind the incoming request with this implementation
+  void OnFeatureManagerAssociatedRequest(
+      mojo::PendingAssociatedReceiver<shell::mojom::FeatureManager>
+          pending_receiver);
+
+  // Flag for when the configuration message is received from the browser.
+  bool configured_;
+
+  // Map for storing enabled features, name -> FeaturePtr.
+  using FeaturesMap =
+      std::map<std::string, chromecast::shell::mojom::FeaturePtr>;
+  FeaturesMap features_map_;
+
+  blink::AssociatedInterfaceRegistry registry_;
+  mojo::AssociatedReceiverSet<shell::mojom::FeatureManager> receivers_;
+};
+
+}  // namespace chromecast
+
+#endif  // CHROMECAST_RENDERER_FEATURE_MANAGER_ON_ASSOCIATED_INTERFACE_H_
diff --git a/chromeos/components/camera_app_ui/camera_app_helper_impl.cc b/chromeos/components/camera_app_ui/camera_app_helper_impl.cc
index 0d1be7a..c42e0b5 100644
--- a/chromeos/components/camera_app_ui/camera_app_helper_impl.cc
+++ b/chromeos/components/camera_app_ui/camera_app_helper_impl.cc
@@ -18,13 +18,13 @@
 namespace chromeos_camera {
 namespace {
 
-mojom::ScreenState ToMojoScreenState(ash::ScreenState s) {
+mojom::ScreenState ToMojoScreenState(ash::ScreenBacklightState s) {
   switch (s) {
-    case ash::ScreenState::ON:
+    case ash::ScreenBacklightState::ON:
       return mojom::ScreenState::ON;
-    case ash::ScreenState::OFF:
+    case ash::ScreenBacklightState::OFF:
       return mojom::ScreenState::OFF;
-    case ash::ScreenState::OFF_AUTO:
+    case ash::ScreenBacklightState::OFF_AUTO:
       return mojom::ScreenState::OFF_AUTO;
     default:
       NOTREACHED();
@@ -132,7 +132,7 @@
     SetScreenStateMonitorCallback callback) {
   screen_state_monitor_ = mojo::Remote<ScreenStateMonitor>(std::move(monitor));
   auto&& mojo_state =
-      ToMojoScreenState(ash::ScreenBacklight::Get()->GetScreenState());
+      ToMojoScreenState(ash::ScreenBacklight::Get()->GetScreenBacklightState());
   std::move(callback).Run(mojo_state);
 }
 
@@ -220,9 +220,10 @@
     tablet_mode_monitor_->Update(false);
 }
 
-void CameraAppHelperImpl::OnScreenStateChanged(ash::ScreenState screen_state) {
+void CameraAppHelperImpl::OnScreenBacklightStateChanged(
+    ash::ScreenBacklightState screen_backlight_state) {
   if (screen_state_monitor_.is_bound())
-    screen_state_monitor_->Update(ToMojoScreenState(screen_state));
+    screen_state_monitor_->Update(ToMojoScreenState(screen_backlight_state));
 }
 
 void CameraAppHelperImpl::OnDisplayAdded(const display::Display& new_display) {
diff --git a/chromeos/components/camera_app_ui/camera_app_helper_impl.h b/chromeos/components/camera_app_ui/camera_app_helper_impl.h
index edcc3ef..7f3925c 100644
--- a/chromeos/components/camera_app_ui/camera_app_helper_impl.h
+++ b/chromeos/components/camera_app_ui/camera_app_helper_impl.h
@@ -79,7 +79,8 @@
   void OnTabletModeEnded() override;
 
   // ash::ScreenBacklightObserver overrides;
-  void OnScreenStateChanged(ash::ScreenState screen_state) override;
+  void OnScreenBacklightStateChanged(
+      ash::ScreenBacklightState screen_backlight_state) override;
 
   // display::DisplayObserver overrides;
   void OnDisplayAdded(const display::Display& new_display) override;
diff --git a/chromeos/components/diagnostics_ui/DEPS b/chromeos/components/diagnostics_ui/DEPS
index 415b9f99..c8e316b 100644
--- a/chromeos/components/diagnostics_ui/DEPS
+++ b/chromeos/components/diagnostics_ui/DEPS
@@ -9,6 +9,7 @@
   "+services/data_decoder/public",
   "+services/device/public",
   "+ui/base",
+  "+ui/events/ozone",
   "+ui/gfx",
   "+ui/resources",
   "+ui/shell_dialogs",
diff --git a/chromeos/components/diagnostics_ui/backend/BUILD.gn b/chromeos/components/diagnostics_ui/backend/BUILD.gn
index 611603f..0408f54f 100644
--- a/chromeos/components/diagnostics_ui/backend/BUILD.gn
+++ b/chromeos/components/diagnostics_ui/backend/BUILD.gn
@@ -14,6 +14,8 @@
     "diagnostics_manager.h",
     "histogram_util.cc",
     "histogram_util.h",
+    "input_data_provider.cc",
+    "input_data_provider.h",
     "log_test_helpers.cc",
     "log_test_helpers.h",
     "network_health_provider.cc",
@@ -50,6 +52,8 @@
     "//services/data_decoder/public/cpp",
     "//services/device/public/mojom",
     "//ui/base",
+    "//ui/events/ozone",
+    "//ui/events/ozone/evdev:event_device_info",
     "//ui/gfx",
     "//ui/shell_dialogs",
     "//ui/webui",
@@ -61,6 +65,7 @@
 
   sources = [
     "cpu_usage_data_unittest.cc",
+    "input_data_provider_unittest.cc",
     "log_test_helpers_unittest.cc",
     "network_health_provider_unittest.cc",
     "power_manager_client_conversions_unittest.cc",
@@ -93,6 +98,8 @@
     "//services/data_decoder/public/cpp:test_support",
     "//services/device/public/cpp:test_support",
     "//testing/gtest",
+    "//ui/events/ozone",
+    "//ui/events/ozone/evdev:event_device_info_test_utils",
     "//ui/gfx",
     "//ui/shell_dialogs",
     "//ui/webui",
diff --git a/chromeos/components/diagnostics_ui/backend/diagnostics_manager.cc b/chromeos/components/diagnostics_ui/backend/diagnostics_manager.cc
index 610c8d0..5d456d0 100644
--- a/chromeos/components/diagnostics_ui/backend/diagnostics_manager.cc
+++ b/chromeos/components/diagnostics_ui/backend/diagnostics_manager.cc
@@ -4,6 +4,7 @@
 
 #include "chromeos/components/diagnostics_ui/backend/diagnostics_manager.h"
 
+#include "chromeos/components/diagnostics_ui/backend/input_data_provider.h"
 #include "chromeos/components/diagnostics_ui/backend/session_log_handler.h"
 #include "chromeos/components/diagnostics_ui/backend/system_data_provider.h"
 #include "chromeos/components/diagnostics_ui/backend/system_routine_controller.h"
@@ -15,7 +16,8 @@
     : system_data_provider_(std::make_unique<SystemDataProvider>(
           session_log_handler->GetTelemetryLog())),
       system_routine_controller_(std::make_unique<SystemRoutineController>(
-          session_log_handler->GetRoutineLog())) {}
+          session_log_handler->GetRoutineLog())),
+      input_data_provider_(std::make_unique<InputDataProvider>()) {}
 
 DiagnosticsManager::~DiagnosticsManager() = default;
 
@@ -28,5 +30,9 @@
   return system_routine_controller_.get();
 }
 
+InputDataProvider* DiagnosticsManager::GetInputDataProvider() const {
+  return input_data_provider_.get();
+}
+
 }  // namespace diagnostics
 }  // namespace chromeos
diff --git a/chromeos/components/diagnostics_ui/backend/diagnostics_manager.h b/chromeos/components/diagnostics_ui/backend/diagnostics_manager.h
index 69bbf39..b1f8a03 100644
--- a/chromeos/components/diagnostics_ui/backend/diagnostics_manager.h
+++ b/chromeos/components/diagnostics_ui/backend/diagnostics_manager.h
@@ -13,6 +13,7 @@
 class SessionLogHandler;
 class SystemDataProvider;
 class SystemRoutineController;
+class InputDataProvider;
 
 // DiagnosticsManager is responsible for managing the lifetime of the services
 // used by the Diagnostics SWA.
@@ -26,10 +27,12 @@
 
   SystemDataProvider* GetSystemDataProvider() const;
   SystemRoutineController* GetSystemRoutineController() const;
+  InputDataProvider* GetInputDataProvider() const;
 
  private:
   std::unique_ptr<SystemDataProvider> system_data_provider_;
   std::unique_ptr<SystemRoutineController> system_routine_controller_;
+  std::unique_ptr<InputDataProvider> input_data_provider_;
 };
 
 }  // namespace diagnostics
diff --git a/chromeos/components/diagnostics_ui/backend/input_data_provider.cc b/chromeos/components/diagnostics_ui/backend/input_data_provider.cc
new file mode 100644
index 0000000..c8c928e
--- /dev/null
+++ b/chromeos/components/diagnostics_ui/backend/input_data_provider.cc
@@ -0,0 +1,167 @@
+// 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 "chromeos/components/diagnostics_ui/backend/input_data_provider.h"
+
+#include <fcntl.h>
+#include <algorithm>
+#include <vector>
+
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/ranges/algorithm.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+
+namespace chromeos {
+namespace diagnostics {
+
+namespace {
+
+bool GetEventNodeId(base::FilePath path, int* id) {
+  const std::string base_name_prefix = "event";
+
+  std::string base_name = path.BaseName().value();
+  DCHECK(base::StartsWith(base_name, base_name_prefix));
+  base_name.erase(0, base_name_prefix.length());
+  return base::StringToInt(base_name, id);
+}
+
+mojom::ConnectionType ConnectionTypeFromInputDeviceType(
+    ui::InputDeviceType type) {
+  switch (type) {
+    case ui::InputDeviceType::INPUT_DEVICE_INTERNAL:
+      return mojom::ConnectionType::kInternal;
+    case ui::InputDeviceType::INPUT_DEVICE_USB:
+      return mojom::ConnectionType::kUsb;
+    case ui::InputDeviceType::INPUT_DEVICE_BLUETOOTH:
+      return mojom::ConnectionType::kBluetooth;
+    case ui::InputDeviceType::INPUT_DEVICE_UNKNOWN:
+      return mojom::ConnectionType::kUnknown;
+  }
+}
+
+}  // namespace
+
+InputDataProvider::InputDataProvider()
+    : device_manager_(ui::CreateDeviceManager()) {
+  Initialize();
+}
+
+InputDataProvider::InputDataProvider(
+    std::unique_ptr<ui::DeviceManager> device_manager_for_test)
+    : device_manager_(std::move(device_manager_for_test)) {
+  Initialize();
+}
+
+InputDataProvider::~InputDataProvider() {
+  device_manager_->RemoveObserver(this);
+}
+
+void InputDataProvider::Initialize() {
+  device_manager_->AddObserver(this);
+  device_manager_->ScanDevices(this);
+}
+
+void InputDataProvider::BindInterface(
+    mojo::PendingReceiver<mojom::InputDataProvider> pending_receiver) {
+  receiver_.Bind(std::move(pending_receiver));
+}
+
+void InputDataProvider::GetConnectedDevices(
+    GetConnectedDevicesCallback callback) {
+  std::vector<mojom::KeyboardInfoPtr> keyboard_vector;
+  keyboard_vector.reserve(keyboards_.size());
+  for (auto& keyboard_info : keyboards_) {
+    keyboard_vector.push_back(keyboard_info.second.Clone());
+  }
+
+  std::vector<mojom::TouchDeviceInfoPtr> touch_device_vector;
+  touch_device_vector.reserve(touch_devices_.size());
+  for (auto& touch_device_info : touch_devices_) {
+    touch_device_vector.push_back(touch_device_info.second.Clone());
+  }
+
+  base::ranges::sort(keyboard_vector, std::less<>(), &mojom::KeyboardInfo::id);
+  base::ranges::sort(touch_device_vector, std::less<>(),
+                     &mojom::TouchDeviceInfo::id);
+
+  std::move(callback).Run(std::move(keyboard_vector),
+                          std::move(touch_device_vector));
+}
+
+void InputDataProvider::OnDeviceEvent(const ui::DeviceEvent& event) {
+  if (event.device_type() != ui::DeviceEvent::DeviceType::INPUT ||
+      event.action_type() == ui::DeviceEvent::ActionType::CHANGE) {
+    return;
+  }
+
+  int id = -1;
+  if (!GetEventNodeId(event.path(), &id)) {
+    LOG(ERROR) << "Ignoring DeviceEvent: invalid path " << event.path();
+    return;
+  }
+
+  if (event.action_type() == ui::DeviceEvent::ActionType::ADD) {
+    std::unique_ptr<ui::EventDeviceInfo> device_info =
+        GetDeviceInfo(event.path());
+    if (device_info == nullptr) {
+      LOG(ERROR) << "Ignoring DeviceEvent for " << event.path();
+      return;
+    }
+
+    if (device_info->HasTouchpad() ||
+        (device_info->HasTouchscreen() && !device_info->HasStylus())) {
+      AddTouchDevice(id, device_info.get());
+    } else if (device_info->HasKeyboard()) {
+      AddKeyboard(id, device_info.get());
+    }
+  } else {
+    if (keyboards_.contains(id)) {
+      keyboards_.erase(id);
+    } else if (touch_devices_.contains(id)) {
+      touch_devices_.erase(id);
+    }
+  }
+}
+
+std::unique_ptr<ui::EventDeviceInfo> InputDataProvider::GetDeviceInfo(
+    base::FilePath path) {
+  base::ScopedFD fd(open(path.value().c_str(), O_RDWR | O_NONBLOCK));
+  if (fd.get() < 0) {
+    LOG(ERROR) << "Couldn't open device path " << path;
+    return nullptr;
+  }
+
+  auto device_info = std::make_unique<ui::EventDeviceInfo>();
+  if (!device_info->Initialize(fd.get(), path)) {
+    LOG(ERROR) << "Failed to get device info for " << path;
+    return nullptr;
+  }
+  return device_info;
+}
+
+void InputDataProvider::AddTouchDevice(int id,
+                                       const ui::EventDeviceInfo* device_info) {
+  touch_devices_[id] = mojom::TouchDeviceInfo::New();
+  touch_devices_[id]->id = id;
+  touch_devices_[id]->connection_type =
+      ConnectionTypeFromInputDeviceType(device_info->device_type());
+  touch_devices_[id]->type = device_info->HasTouchpad()
+                                 ? mojom::TouchDeviceType::kPointer
+                                 : mojom::TouchDeviceType::kDirect;
+  touch_devices_[id]->name = device_info->name();
+}
+
+void InputDataProvider::AddKeyboard(int id,
+                                    const ui::EventDeviceInfo* device_info) {
+  keyboards_[id] = mojom::KeyboardInfo::New();
+  keyboards_[id]->id = id;
+  keyboards_[id]->connection_type =
+      ConnectionTypeFromInputDeviceType(device_info->device_type());
+  keyboards_[id]->name = device_info->name();
+}
+
+}  // namespace diagnostics
+}  // namespace chromeos
diff --git a/chromeos/components/diagnostics_ui/backend/input_data_provider.h b/chromeos/components/diagnostics_ui/backend/input_data_provider.h
new file mode 100644
index 0000000..53f5448
--- /dev/null
+++ b/chromeos/components/diagnostics_ui/backend/input_data_provider.h
@@ -0,0 +1,60 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_COMPONENTS_DIAGNOSTICS_UI_BACKEND_INPUT_DATA_PROVIDER_H_
+#define CHROMEOS_COMPONENTS_DIAGNOSTICS_UI_BACKEND_INPUT_DATA_PROVIDER_H_
+
+#include "base/containers/flat_map.h"
+#include "base/files/file_path.h"
+#include "chromeos/components/diagnostics_ui/mojom/input_data_provider.mojom.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "ui/events/ozone/device/device_event.h"
+#include "ui/events/ozone/device/device_event_observer.h"
+#include "ui/events/ozone/device/device_manager.h"
+#include "ui/events/ozone/evdev/event_device_info.h"
+
+namespace chromeos {
+namespace diagnostics {
+
+class InputDataProvider : public mojom::InputDataProvider,
+                          public ui::DeviceEventObserver {
+ public:
+  InputDataProvider();
+  InputDataProvider(std::unique_ptr<ui::DeviceManager> device_manager);
+  InputDataProvider(const InputDataProvider&) = delete;
+  InputDataProvider& operator=(const InputDataProvider&) = delete;
+  ~InputDataProvider() override;
+
+  void BindInterface(
+      mojo::PendingReceiver<mojom::InputDataProvider> pending_receiver);
+
+  // mojom::InputDataProvider:
+  void GetConnectedDevices(GetConnectedDevicesCallback callback) override;
+
+  // ui::DeviceEventObserver:
+  void OnDeviceEvent(const ui::DeviceEvent& event) override;
+
+ protected:
+  virtual std::unique_ptr<ui::EventDeviceInfo> GetDeviceInfo(
+      base::FilePath path);
+
+ private:
+  void Initialize();
+
+  void AddTouchDevice(int id, const ui::EventDeviceInfo* device_info);
+  void AddKeyboard(int id, const ui::EventDeviceInfo* device_info);
+
+  base::flat_map<int, mojom::KeyboardInfoPtr> keyboards_;
+  base::flat_map<int, mojom::TouchDeviceInfoPtr> touch_devices_;
+
+  mojo::Receiver<mojom::InputDataProvider> receiver_{this};
+
+  std::unique_ptr<ui::DeviceManager> device_manager_;
+};
+
+}  // namespace diagnostics
+}  // namespace chromeos
+
+#endif  // CHROMEOS_COMPONENTS_DIAGNOSTICS_UI_BACKEND_SYSTEM_DATA_PROVIDER_H_
diff --git a/chromeos/components/diagnostics_ui/backend/input_data_provider_unittest.cc b/chromeos/components/diagnostics_ui/backend/input_data_provider_unittest.cc
new file mode 100644
index 0000000..5c29f29b
--- /dev/null
+++ b/chromeos/components/diagnostics_ui/backend/input_data_provider_unittest.cc
@@ -0,0 +1,205 @@
+// 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 "chromeos/components/diagnostics_ui/backend/input_data_provider.h"
+
+#include <vector>
+
+#include "base/run_loop.h"
+#include "base/test/bind.h"
+#include "base/test/task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/ozone/device/device_event_observer.h"
+#include "ui/events/ozone/device/device_manager.h"
+#include "ui/events/ozone/evdev/event_device_test_util.h"
+
+namespace chromeos {
+namespace diagnostics {
+
+class FakeDeviceManager : public ui::DeviceManager {
+ public:
+  FakeDeviceManager() {}
+  FakeDeviceManager(const FakeDeviceManager&) = delete;
+  FakeDeviceManager& operator=(const FakeDeviceManager&) = delete;
+  ~FakeDeviceManager() override {}
+
+  // DeviceManager:
+  void ScanDevices(ui::DeviceEventObserver* observer) override {}
+  void AddObserver(ui::DeviceEventObserver* observer) override {}
+  void RemoveObserver(ui::DeviceEventObserver* observer) override {}
+};
+
+class TestInputDataProvider : public InputDataProvider {
+ public:
+  TestInputDataProvider(std::unique_ptr<ui::DeviceManager> device_manager)
+      : InputDataProvider(std::move(device_manager)) {}
+  TestInputDataProvider(const TestInputDataProvider&) = delete;
+  TestInputDataProvider& operator=(const TestInputDataProvider&) = delete;
+
+ protected:
+  std::unique_ptr<ui::EventDeviceInfo> GetDeviceInfo(
+      base::FilePath path) override {
+    std::unique_ptr<ui::EventDeviceInfo> dev_info =
+        std::make_unique<ui::EventDeviceInfo>();
+    ui::DeviceCapabilities device_caps;
+    std::string base_name = path.BaseName().value();
+    if (base_name == "event0") {
+      device_caps = ui::kLinkKeyboard;
+    } else if (base_name == "event1") {
+      device_caps = ui::kLinkTouchpad;
+    } else if (base_name == "event2") {
+      device_caps = ui::kKohakuTouchscreen;
+    } else if (base_name == "event3") {
+      device_caps = ui::kKohakuStylus;
+    } else if (base_name == "event4") {
+      device_caps = ui::kHpUsbKeyboard;
+    }
+
+    EXPECT_TRUE(ui::CapabilitiesToDeviceInfo(device_caps, dev_info.get()));
+    return dev_info;
+  }
+};
+
+class InputDataProviderTest : public testing::Test {
+ public:
+  InputDataProviderTest() {
+    auto manager = std::make_unique<FakeDeviceManager>();
+    manager_ = manager.get();
+    provider_ = std::make_unique<TestInputDataProvider>(std::move(manager));
+  }
+
+  ~InputDataProviderTest() override {
+    provider_.reset();
+    base::RunLoop().RunUntilIdle();
+  }
+
+ protected:
+  FakeDeviceManager* manager_;
+  std::unique_ptr<InputDataProvider> provider_;
+
+ private:
+  base::test::SingleThreadTaskEnvironment task_environment_;
+};
+
+TEST_F(InputDataProviderTest, GetConnectedDevices_DeviceInfoMapping) {
+  base::RunLoop run_loop;
+  ui::DeviceEvent event0(ui::DeviceEvent::DeviceType::INPUT,
+                         ui::DeviceEvent::ActionType::ADD,
+                         base::FilePath("/dev/input/event0"));
+  ui::DeviceEvent event1(ui::DeviceEvent::DeviceType::INPUT,
+                         ui::DeviceEvent::ActionType::ADD,
+                         base::FilePath("/dev/input/event1"));
+  ui::DeviceEvent event2(ui::DeviceEvent::DeviceType::INPUT,
+                         ui::DeviceEvent::ActionType::ADD,
+                         base::FilePath("/dev/input/event2"));
+  ui::DeviceEvent event3(ui::DeviceEvent::DeviceType::INPUT,
+                         ui::DeviceEvent::ActionType::ADD,
+                         base::FilePath("/dev/input/event3"));
+  provider_->OnDeviceEvent(event0);
+  provider_->OnDeviceEvent(event1);
+  provider_->OnDeviceEvent(event2);
+  provider_->OnDeviceEvent(event3);
+
+  provider_->GetConnectedDevices(base::BindLambdaForTesting(
+      [&](std::vector<mojom::KeyboardInfoPtr> keyboards,
+          std::vector<mojom::TouchDeviceInfoPtr> touch_devices) {
+        EXPECT_EQ(1ul, keyboards.size());
+        // The stylus device should be filtered out, hence only 2 touch devices.
+        EXPECT_EQ(2ul, touch_devices.size());
+
+        mojom::KeyboardInfoPtr keyboard = keyboards[0].Clone();
+        EXPECT_EQ(0u, keyboard->id);
+        EXPECT_EQ(mojom::ConnectionType::kInternal, keyboard->connection_type);
+        EXPECT_EQ("AT Translated Set 2 keyboard", keyboard->name);
+
+        mojom::TouchDeviceInfoPtr touchpad = touch_devices[0].Clone();
+        EXPECT_EQ(1u, touchpad->id);
+        EXPECT_EQ(mojom::ConnectionType::kInternal, touchpad->connection_type);
+        EXPECT_EQ(mojom::TouchDeviceType::kPointer, touchpad->type);
+        EXPECT_EQ("Atmel maXTouch Touchpad", touchpad->name);
+
+        mojom::TouchDeviceInfoPtr touchscreen = touch_devices[1].Clone();
+        EXPECT_EQ(2u, touchscreen->id);
+        EXPECT_EQ(mojom::ConnectionType::kInternal,
+                  touchscreen->connection_type);
+        EXPECT_EQ(mojom::TouchDeviceType::kDirect, touchscreen->type);
+        EXPECT_EQ("Atmel maXTouch Touchscreen", touchscreen->name);
+
+        run_loop.Quit();
+      }));
+  run_loop.Run();
+}
+
+TEST_F(InputDataProviderTest, GetConnectedDevices_AddEventAfterFirstCall) {
+  base::RunLoop run_loop;
+  provider_->GetConnectedDevices(base::BindLambdaForTesting(
+      [&](std::vector<mojom::KeyboardInfoPtr> keyboards,
+          std::vector<mojom::TouchDeviceInfoPtr> touch_devices) {
+        EXPECT_EQ(0ul, keyboards.size());
+        EXPECT_EQ(0ul, touch_devices.size());
+      }));
+
+  ui::DeviceEvent event(ui::DeviceEvent::DeviceType::INPUT,
+                        ui::DeviceEvent::ActionType::ADD,
+                        base::FilePath("/dev/input/event4"));
+  provider_->OnDeviceEvent(event);
+  provider_->GetConnectedDevices(base::BindLambdaForTesting(
+      [&](std::vector<mojom::KeyboardInfoPtr> keyboards,
+          std::vector<mojom::TouchDeviceInfoPtr> touch_devices) {
+        EXPECT_EQ(1ul, keyboards.size());
+        mojom::KeyboardInfoPtr keyboard = keyboards[0].Clone();
+        EXPECT_EQ(4u, keyboard->id);
+        EXPECT_EQ(mojom::ConnectionType::kUsb, keyboard->connection_type);
+        EXPECT_EQ("Chicony HP Elite USB Keyboard", keyboard->name);
+
+        EXPECT_EQ(0ul, touch_devices.size());
+
+        run_loop.Quit();
+      }));
+
+  run_loop.Run();
+}
+
+TEST_F(InputDataProviderTest, GetConnectedDevices_Remove) {
+  base::RunLoop run_loop;
+  ui::DeviceEvent add_touch_event(ui::DeviceEvent::DeviceType::INPUT,
+                                  ui::DeviceEvent::ActionType::ADD,
+                                  base::FilePath("/dev/input/event1"));
+  provider_->OnDeviceEvent(add_touch_event);
+  ui::DeviceEvent add_kbd_event(ui::DeviceEvent::DeviceType::INPUT,
+                                ui::DeviceEvent::ActionType::ADD,
+                                base::FilePath("/dev/input/event4"));
+  provider_->OnDeviceEvent(add_kbd_event);
+  provider_->GetConnectedDevices(base::BindLambdaForTesting(
+      [&](std::vector<mojom::KeyboardInfoPtr> keyboards,
+          std::vector<mojom::TouchDeviceInfoPtr> touch_devices) {
+        EXPECT_EQ(1ul, keyboards.size());
+        EXPECT_EQ(4u, keyboards[0]->id);
+
+        EXPECT_EQ(1ul, touch_devices.size());
+        EXPECT_EQ(1u, touch_devices[0]->id);
+      }));
+
+  ui::DeviceEvent remove_touch_event(ui::DeviceEvent::DeviceType::INPUT,
+                                     ui::DeviceEvent::ActionType::REMOVE,
+                                     base::FilePath("/dev/input/event1"));
+  provider_->OnDeviceEvent(remove_touch_event);
+  ui::DeviceEvent remove_kbd_event(ui::DeviceEvent::DeviceType::INPUT,
+                                   ui::DeviceEvent::ActionType::REMOVE,
+                                   base::FilePath("/dev/input/event4"));
+  provider_->OnDeviceEvent(remove_kbd_event);
+  provider_->GetConnectedDevices(base::BindLambdaForTesting(
+      [&](std::vector<mojom::KeyboardInfoPtr> keyboards,
+          std::vector<mojom::TouchDeviceInfoPtr> touch_devices) {
+        EXPECT_EQ(0ul, keyboards.size());
+        EXPECT_EQ(0ul, touch_devices.size());
+
+        run_loop.Quit();
+      }));
+
+  run_loop.Run();
+}
+
+}  // namespace diagnostics
+}  // namespace chromeos
diff --git a/chromeos/components/diagnostics_ui/diagnostics_ui.cc b/chromeos/components/diagnostics_ui/diagnostics_ui.cc
index 1bfe0ef..a3ca8fb 100644
--- a/chromeos/components/diagnostics_ui/diagnostics_ui.cc
+++ b/chromeos/components/diagnostics_ui/diagnostics_ui.cc
@@ -12,6 +12,7 @@
 #include "base/memory/ptr_util.h"
 #include "chromeos/components/diagnostics_ui/backend/diagnostics_manager.h"
 #include "chromeos/components/diagnostics_ui/backend/histogram_util.h"
+#include "chromeos/components/diagnostics_ui/backend/input_data_provider.h"
 #include "chromeos/components/diagnostics_ui/backend/session_log_handler.h"
 #include "chromeos/components/diagnostics_ui/backend/system_data_provider.h"
 #include "chromeos/components/diagnostics_ui/backend/system_routine_controller.h"
@@ -194,6 +195,15 @@
   }
 }
 
+void DiagnosticsDialogUI::BindInterface(
+    mojo::PendingReceiver<diagnostics::mojom::InputDataProvider> receiver) {
+  diagnostics::InputDataProvider* input_data_provider =
+      diagnostics_manager_->GetInputDataProvider();
+  if (input_data_provider) {
+    input_data_provider->BindInterface(std::move(receiver));
+  }
+}
+
 WEB_UI_CONTROLLER_TYPE_IMPL(DiagnosticsDialogUI)
 
 }  // namespace chromeos
diff --git a/chromeos/components/diagnostics_ui/diagnostics_ui.h b/chromeos/components/diagnostics_ui/diagnostics_ui.h
index b5a3590..c7b3b14b 100644
--- a/chromeos/components/diagnostics_ui/diagnostics_ui.h
+++ b/chromeos/components/diagnostics_ui/diagnostics_ui.h
@@ -8,6 +8,7 @@
 #include "base/macros.h"
 #include "base/time/time.h"
 #include "chromeos/components/diagnostics_ui/backend/session_log_handler.h"
+#include "chromeos/components/diagnostics_ui/mojom/input_data_provider.mojom-forward.h"
 #include "chromeos/components/diagnostics_ui/mojom/system_data_provider.mojom-forward.h"
 #include "chromeos/components/diagnostics_ui/mojom/system_routine_controller.mojom-forward.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
@@ -39,6 +40,9 @@
       mojo::PendingReceiver<diagnostics::mojom::SystemRoutineController>
           receiver);
 
+  void BindInterface(
+      mojo::PendingReceiver<diagnostics::mojom::InputDataProvider> receiver);
+
  private:
   WEB_UI_CONTROLLER_TYPE_DECL();
 
diff --git a/chromeos/components/eche_app_ui/mojom/BUILD.gn b/chromeos/components/eche_app_ui/mojom/BUILD.gn
index c391233..b68b4aaa 100644
--- a/chromeos/components/eche_app_ui/mojom/BUILD.gn
+++ b/chromeos/components/eche_app_ui/mojom/BUILD.gn
@@ -12,7 +12,7 @@
       types = [
         {
           mojom = "chromeos.eche_app.mojom.ScreenBacklightState"
-          cpp = "ash::ScreenState"
+          cpp = "ash::ScreenBacklightState"
         },
       ]
       traits_headers =
diff --git a/chromeos/components/eche_app_ui/mojom/types_mojom_traits.cc b/chromeos/components/eche_app_ui/mojom/types_mojom_traits.cc
index 09edcdaf..0ff427e 100644
--- a/chromeos/components/eche_app_ui/mojom/types_mojom_traits.cc
+++ b/chromeos/components/eche_app_ui/mojom/types_mojom_traits.cc
@@ -7,15 +7,15 @@
 namespace mojo {
 
 // static
-chromeos::eche_app::mojom::ScreenBacklightState
-EnumTraits<chromeos::eche_app::mojom::ScreenBacklightState,
-           ash::ScreenState>::ToMojom(ash::ScreenState input) {
+chromeos::eche_app::mojom::ScreenBacklightState EnumTraits<
+    chromeos::eche_app::mojom::ScreenBacklightState,
+    ash::ScreenBacklightState>::ToMojom(ash::ScreenBacklightState input) {
   switch (input) {
-    case ash::ScreenState::ON:
+    case ash::ScreenBacklightState::ON:
       return chromeos::eche_app::mojom::ScreenBacklightState::ON;
-    case ash::ScreenState::OFF:
+    case ash::ScreenBacklightState::OFF:
       return chromeos::eche_app::mojom::ScreenBacklightState::OFF;
-    case ash::ScreenState::OFF_AUTO:
+    case ash::ScreenBacklightState::OFF_AUTO:
       return chromeos::eche_app::mojom::ScreenBacklightState::OFF_AUTO;
   }
 
@@ -24,18 +24,18 @@
 
 // static
 bool EnumTraits<chromeos::eche_app::mojom::ScreenBacklightState,
-                ash::ScreenState>::
+                ash::ScreenBacklightState>::
     FromMojom(chromeos::eche_app::mojom::ScreenBacklightState input,
-              ash::ScreenState* output) {
+              ash::ScreenBacklightState* output) {
   switch (input) {
     case chromeos::eche_app::mojom::ScreenBacklightState::ON:
-      *output = ash::ScreenState::ON;
+      *output = ash::ScreenBacklightState::ON;
       return true;
     case chromeos::eche_app::mojom::ScreenBacklightState::OFF:
-      *output = ash::ScreenState::OFF;
+      *output = ash::ScreenBacklightState::OFF;
       return true;
     case chromeos::eche_app::mojom::ScreenBacklightState::OFF_AUTO:
-      *output = ash::ScreenState::OFF_AUTO;
+      *output = ash::ScreenBacklightState::OFF_AUTO;
       return true;
   }
   NOTREACHED();
diff --git a/chromeos/components/eche_app_ui/mojom/types_mojom_traits.h b/chromeos/components/eche_app_ui/mojom/types_mojom_traits.h
index c691776..970d0ea4 100644
--- a/chromeos/components/eche_app_ui/mojom/types_mojom_traits.h
+++ b/chromeos/components/eche_app_ui/mojom/types_mojom_traits.h
@@ -13,11 +13,11 @@
 
 template <>
 struct EnumTraits<chromeos::eche_app::mojom::ScreenBacklightState,
-                  ash::ScreenState> {
+                  ash::ScreenBacklightState> {
   static chromeos::eche_app::mojom::ScreenBacklightState ToMojom(
-      ash::ScreenState input);
+      ash::ScreenBacklightState input);
   static bool FromMojom(chromeos::eche_app::mojom::ScreenBacklightState input,
-                        ash::ScreenState* output);
+                        ash::ScreenBacklightState* output);
 };
 
 }  // namespace mojo
diff --git a/chromeos/components/eche_app_ui/system_info_provider.cc b/chromeos/components/eche_app_ui/system_info_provider.cc
index b81a1bf..d50f6fe 100644
--- a/chromeos/components/eche_app_ui/system_info_provider.cc
+++ b/chromeos/components/eche_app_ui/system_info_provider.cc
@@ -48,7 +48,8 @@
   info_receiver_.Bind(std::move(receiver));
 }
 
-void SystemInfoProvider::OnScreenStateChanged(ash::ScreenState screen_state) {
+void SystemInfoProvider::OnScreenBacklightStateChanged(
+    ash::ScreenBacklightState screen_state) {
   if (!observer_remote_.is_bound())
     return;
 
diff --git a/chromeos/components/eche_app_ui/system_info_provider.h b/chromeos/components/eche_app_ui/system_info_provider.h
index 1412b52..1ca7d82 100644
--- a/chromeos/components/eche_app_ui/system_info_provider.h
+++ b/chromeos/components/eche_app_ui/system_info_provider.h
@@ -39,7 +39,8 @@
 
  private:
   // ash::ScreenBacklightObserver overrides;
-  void OnScreenStateChanged(ash::ScreenState screen_state) override;
+  void OnScreenBacklightStateChanged(
+      ash::ScreenBacklightState screen_state) override;
 
   mojo::Receiver<mojom::SystemInfoProvider> info_receiver_{this};
   mojo::Remote<mojom::SystemInfoObserver> observer_remote_;
diff --git a/chromeos/crosapi/mojom/BUILD.gn b/chromeos/crosapi/mojom/BUILD.gn
index fd6a022..bd2cefaa 100644
--- a/chromeos/crosapi/mojom/BUILD.gn
+++ b/chromeos/crosapi/mojom/BUILD.gn
@@ -66,6 +66,10 @@
           move_only = true
           nullable_is_same_type = true
         },
+        {
+          mojom = "crosapi.mojom.UninstallSource"
+          cpp = "::apps::mojom::UninstallSource"
+        },
       ]
       traits_headers = [
         "//chromeos/crosapi/mojom/app_service_types_mojom_traits.h",
diff --git a/chromeos/crosapi/mojom/app_service.mojom b/chromeos/crosapi/mojom/app_service.mojom
index 3f7913b..5f1c3d9 100644
--- a/chromeos/crosapi/mojom/app_service.mojom
+++ b/chromeos/crosapi/mojom/app_service.mojom
@@ -23,4 +23,16 @@
 // Interacts with the app service. Implemented in lacros-chrome and called in
 // ash-chrome.
 [Stable, Uuid="2031a614-3f0b-4111-8977-fd96fd780cb7"]
-interface AppController {};
+interface AppController {
+  // Directly uninstalls |app_id| without prompting the user.
+  // If |clear_site_data| is true, any site data associated with the app will
+  // be removed.
+  // If |report_abuse| is true, the app will be reported for abuse to the Web
+  // Store.
+  [MinVersion=1]
+  Uninstall@1(
+      string app_id,
+      UninstallSource uninstall_source,
+      bool clear_site_data,
+      bool report_abuse);
+};
diff --git a/chromeos/crosapi/mojom/app_service_types.mojom b/chromeos/crosapi/mojom/app_service_types.mojom
index e442620..311ec54 100644
--- a/chromeos/crosapi/mojom/app_service_types.mojom
+++ b/chromeos/crosapi/mojom/app_service_types.mojom
@@ -187,3 +187,13 @@
   // The label shown to the user for this activity.
   string? activity_label;
 };
+
+// What caused the app to be uninstalled.
+[Stable, Extensible]
+enum UninstallSource {
+  [Default] kUnknown = 0,
+  kAppList,       // Uninstall by the user from the App List (Launcher)
+  kAppManagement, // Uninstall by the user from the App Management page
+  kShelf,         // Uninstall by the user from the Shelf
+  kMigration,     // Uninstall by app migration.
+};
diff --git a/chromeos/crosapi/mojom/app_service_types_mojom_traits.cc b/chromeos/crosapi/mojom/app_service_types_mojom_traits.cc
index 4d7b777..7c59443 100644
--- a/chromeos/crosapi/mojom/app_service_types_mojom_traits.cc
+++ b/chromeos/crosapi/mojom/app_service_types_mojom_traits.cc
@@ -482,4 +482,48 @@
   return false;
 }
 
+crosapi::mojom::UninstallSource EnumTraits<
+    crosapi::mojom::UninstallSource,
+    apps::mojom::UninstallSource>::ToMojom(apps::mojom::UninstallSource input) {
+  switch (input) {
+    case apps::mojom::UninstallSource::kUnknown:
+      return crosapi::mojom::UninstallSource::kUnknown;
+    case apps::mojom::UninstallSource::kAppList:
+      return crosapi::mojom::UninstallSource::kAppList;
+    case apps::mojom::UninstallSource::kAppManagement:
+      return crosapi::mojom::UninstallSource::kAppManagement;
+    case apps::mojom::UninstallSource::kShelf:
+      return crosapi::mojom::UninstallSource::kShelf;
+    case apps::mojom::UninstallSource::kMigration:
+      return crosapi::mojom::UninstallSource::kMigration;
+  }
+
+  NOTREACHED();
+}
+
+bool EnumTraits<crosapi::mojom::UninstallSource, apps::mojom::UninstallSource>::
+    FromMojom(crosapi::mojom::UninstallSource input,
+              apps::mojom::UninstallSource* output) {
+  switch (input) {
+    case crosapi::mojom::UninstallSource::kUnknown:
+      *output = apps::mojom::UninstallSource::kUnknown;
+      return true;
+    case crosapi::mojom::UninstallSource::kAppList:
+      *output = apps::mojom::UninstallSource::kAppList;
+      return true;
+    case crosapi::mojom::UninstallSource::kAppManagement:
+      *output = apps::mojom::UninstallSource::kAppManagement;
+      return true;
+    case crosapi::mojom::UninstallSource::kShelf:
+      *output = apps::mojom::UninstallSource::kShelf;
+      return true;
+    case crosapi::mojom::UninstallSource::kMigration:
+      *output = apps::mojom::UninstallSource::kMigration;
+      return true;
+  }
+
+  NOTREACHED();
+  return false;
+}
+
 }  // namespace mojo
diff --git a/chromeos/crosapi/mojom/app_service_types_mojom_traits.h b/chromeos/crosapi/mojom/app_service_types_mojom_traits.h
index 2b7b1cf4..347f2a3 100644
--- a/chromeos/crosapi/mojom/app_service_types_mojom_traits.h
+++ b/chromeos/crosapi/mojom/app_service_types_mojom_traits.h
@@ -240,6 +240,15 @@
                         apps::mojom::PatternMatchType* output);
 };
 
+template <>
+struct EnumTraits<crosapi::mojom::UninstallSource,
+                  apps::mojom::UninstallSource> {
+  static crosapi::mojom::UninstallSource ToMojom(
+      apps::mojom::UninstallSource input);
+  static bool FromMojom(crosapi::mojom::UninstallSource input,
+                        apps::mojom::UninstallSource* output);
+};
+
 }  // namespace mojo
 
 #endif  // CHROMEOS_CROSAPI_MOJOM_APP_SERVICE_TYPES_MOJOM_TRAITS_H_
diff --git a/chromeos/crosapi/mojom/app_service_types_traits_unittest.cc b/chromeos/crosapi/mojom/app_service_types_traits_unittest.cc
index 78f8a16..3268019 100644
--- a/chromeos/crosapi/mojom/app_service_types_traits_unittest.cc
+++ b/chromeos/crosapi/mojom/app_service_types_traits_unittest.cc
@@ -599,3 +599,48 @@
     EXPECT_EQ(condition->condition_values[0]->value, "5");
   }
 }
+
+// Test that serialization and deserialization works with uninstall source.
+TEST(AppServiceTypesTraitsTest, RoundTripUninstallSource) {
+  apps::mojom::UninstallSource input;
+  {
+    input = apps::mojom::UninstallSource::kUnknown;
+    apps::mojom::UninstallSource output;
+    ASSERT_TRUE(
+        mojo::test::SerializeAndDeserialize<crosapi::mojom::UninstallSource>(
+            input, output));
+    EXPECT_EQ(output, apps::mojom::UninstallSource::kUnknown);
+  }
+  {
+    input = apps::mojom::UninstallSource::kAppList;
+    apps::mojom::UninstallSource output;
+    ASSERT_TRUE(
+        mojo::test::SerializeAndDeserialize<crosapi::mojom::UninstallSource>(
+            input, output));
+    EXPECT_EQ(output, apps::mojom::UninstallSource::kAppList);
+  }
+  {
+    input = apps::mojom::UninstallSource::kAppManagement;
+    apps::mojom::UninstallSource output;
+    ASSERT_TRUE(
+        mojo::test::SerializeAndDeserialize<crosapi::mojom::UninstallSource>(
+            input, output));
+    EXPECT_EQ(output, apps::mojom::UninstallSource::kAppManagement);
+  }
+  {
+    input = apps::mojom::UninstallSource::kShelf;
+    apps::mojom::UninstallSource output;
+    ASSERT_TRUE(
+        mojo::test::SerializeAndDeserialize<crosapi::mojom::UninstallSource>(
+            input, output));
+    EXPECT_EQ(output, apps::mojom::UninstallSource::kShelf);
+  }
+  {
+    input = apps::mojom::UninstallSource::kMigration;
+    apps::mojom::UninstallSource output;
+    ASSERT_TRUE(
+        mojo::test::SerializeAndDeserialize<crosapi::mojom::UninstallSource>(
+            input, output));
+    EXPECT_EQ(output, apps::mojom::UninstallSource::kMigration);
+  }
+}
diff --git a/chromeos/crosapi/mojom/holding_space_service.mojom b/chromeos/crosapi/mojom/holding_space_service.mojom
index 1c085ef6..d00dd1d 100644
--- a/chromeos/crosapi/mojom/holding_space_service.mojom
+++ b/chromeos/crosapi/mojom/holding_space_service.mojom
@@ -9,11 +9,15 @@
 // Interface for the holding space service implemented in ash-chrome.
 // See //ash/public/cpp/holding_space/README.md.
 //
-// Next MinVersion: 2
+// Next MinVersion: 3
 // Next ID: 1
 [Stable, Uuid="00c78a1d-b80e-426a-9df1-428c439b3942"]
 interface HoldingSpaceService {
 
-  // Adds a printed PDF item backed by the provided absolute `file_path`.
-  [MinVersion=1] AddPrintedPdf@0(mojo_base.mojom.FilePath file_path);
+  // Adds a printed PDF item backed by the provided absolute `file_path`. If
+  // `from_incognito_profile` is true, the print job was from an incognito
+  // profile.
+  [MinVersion=1] AddPrintedPdf@0(
+      mojo_base.mojom.FilePath file_path@0,
+      [MinVersion=2] bool from_incognito_profile@1);
 };
diff --git a/chromeos/services/ime/decoder/proto_conversion.cc b/chromeos/services/ime/decoder/proto_conversion.cc
index d8fd813..a31a6e0c 100644
--- a/chromeos/services/ime/decoder/proto_conversion.cc
+++ b/chromeos/services/ime/decoder/proto_conversion.cc
@@ -110,20 +110,6 @@
   }
 }
 
-base::Optional<mojom::InputMethodApiOperation> InputMethodApiOperationToMojo(
-    NonCompliantApiMetric::InputMethodApiOperation operation) {
-  switch (operation) {
-    case NonCompliantApiMetric::OPERATION_UNSPECIFIED:
-      return base::nullopt;
-    case NonCompliantApiMetric::OPERATION_COMMIT_TEXT:
-      return mojom::InputMethodApiOperation::kCommitText;
-    case NonCompliantApiMetric::OPERATION_SET_COMPOSITION_TEXT:
-      return mojom::InputMethodApiOperation::kSetCompositionText;
-    case NonCompliantApiMetric::OPERATION_DELETE_SURROUNDING_TEXT:
-      return mojom::InputMethodApiOperation::kDeleteSurroundingText;
-  }
-}
-
 }  // namespace
 
 ime::PublicMessage OnInputMethodChangedToProto(uint64_t seq_id,
@@ -262,20 +248,5 @@
   return suggestions;
 }
 
-mojom::UkmEntryPtr ProtoToUkmEntry(const RecordUkm& record_ukm) {
-  switch (record_ukm.entry_case()) {
-    case RecordUkm::ENTRY_NOT_SET:
-      return nullptr;
-    case RecordUkm::kNonCompliantApi: {
-      auto operation = InputMethodApiOperationToMojo(
-          record_ukm.non_compliant_api().non_compliant_operation());
-      if (!operation)
-        return nullptr;
-      return mojom::UkmEntry::NewNonCompliantApi(
-          mojom::NonCompliantApiMetric::New(*operation));
-    }
-  }
-}
-
 }  // namespace ime
 }  // namespace chromeos
diff --git a/chromeos/services/ime/decoder/proto_conversion.h b/chromeos/services/ime/decoder/proto_conversion.h
index be51ff69..ebfd474 100644
--- a/chromeos/services/ime/decoder/proto_conversion.h
+++ b/chromeos/services/ime/decoder/proto_conversion.h
@@ -58,9 +58,6 @@
 std::vector<TextSuggestion> ProtoToTextSuggestions(
     const chromeos::ime::DisplaySuggestions& display_suggestions);
 
-// Converts a proto to InputChannel::UkmEntry.
-mojom::UkmEntryPtr ProtoToUkmEntry(const RecordUkm& record_ukm);
-
 }  // namespace ime
 }  // namespace chromeos
 
diff --git a/chromeos/services/ime/decoder/proto_conversion_unittest.cc b/chromeos/services/ime/decoder/proto_conversion_unittest.cc
index 1fbd4c4d..81c23df 100644
--- a/chromeos/services/ime/decoder/proto_conversion_unittest.cc
+++ b/chromeos/services/ime/decoder/proto_conversion_unittest.cc
@@ -172,19 +172,5 @@
   EXPECT_FLOAT_EQ(result->completion_candidates[0].score, 0.55);
 }
 
-TEST(ProtoConversionTest, ProtoToUkmEntry) {
-  RecordUkm record_ukm;
-  record_ukm.mutable_non_compliant_api()->set_non_compliant_operation(
-      NonCompliantApiMetric::OPERATION_SET_COMPOSITION_TEXT);
-
-  mojom::UkmEntryPtr result = ProtoToUkmEntry(record_ukm);
-
-  auto metric = mojom::NonCompliantApiMetric::New(
-      mojom::InputMethodApiOperation::kSetCompositionText);
-  auto expected = mojom::UkmEntry::New();
-  expected->set_non_compliant_api(std::move(metric));
-  EXPECT_EQ(result, expected);
-}
-
 }  // namespace ime
 }  // namespace chromeos
diff --git a/chromeos/services/ime/decoder/system_engine.cc b/chromeos/services/ime/decoder/system_engine.cc
index f2446d6..d6d9591 100644
--- a/chromeos/services/ime/decoder/system_engine.cc
+++ b/chromeos/services/ime/decoder/system_engine.cc
@@ -231,7 +231,6 @@
   }
 
   const ime::PublicMessage& reply = wrapper.public_message();
-  // TODO(crbug/1146266): Add case to handle request for suggestions.
   switch (reply.param_case()) {
     case ime::PublicMessage::kOnKeyEventReply: {
       const auto it = pending_key_event_callbacks_.find(reply.seq_id());
@@ -288,12 +287,6 @@
           ProtoToTextSuggestions(reply.display_suggestions()));
       break;
     }
-    case ime::PublicMessage::kRecordUkm: {
-      auto ukm = ProtoToUkmEntry(reply.record_ukm());
-      if (ukm)
-        remote->RecordUkm(std::move(ukm));
-      break;
-    }
     default:
       NOTREACHED();
       break;
diff --git a/chromeos/services/ime/decoder/system_engine_unittest.cc b/chromeos/services/ime/decoder/system_engine_unittest.cc
index f6c36ff..e49d918 100644
--- a/chromeos/services/ime/decoder/system_engine_unittest.cc
+++ b/chromeos/services/ime/decoder/system_engine_unittest.cc
@@ -445,29 +445,5 @@
   mock_channel.FlushForTesting();
 }
 
-TEST_F(SystemEngineTest, RecordUkmSendsMessageToReceiver) {
-  SystemEngine engine(/*platform=*/nullptr);
-  MockInputChannel mock_channel;
-  mojo::Remote<mojom::InputChannel> client;
-  ASSERT_TRUE(engine.BindRequest(kImeSpec, client.BindNewPipeAndPassReceiver(),
-                                 mock_channel.CreatePendingRemote(), {}));
-  Wrapper proto;
-  proto.mutable_public_message()
-      ->mutable_record_ukm()
-      ->mutable_non_compliant_api()
-      ->set_non_compliant_operation(
-          NonCompliantApiMetric::OPERATION_SET_COMPOSITION_TEXT);
-
-  EXPECT_CALL(mock_channel, RecordUkm)
-      .WillOnce([proto](mojom::UkmEntryPtr entry) {
-        EXPECT_EQ(entry, ProtoToUkmEntry(proto.public_message().record_ukm()));
-      });
-
-  const std::string serialized = proto.SerializeAsString();
-  decoder_entry_points_.delegate()->Process(
-      reinterpret_cast<const uint8_t*>(serialized.data()), serialized.size());
-  mock_channel.FlushForTesting();
-}
-
 }  // namespace ime
 }  // namespace chromeos
diff --git a/chromeos/services/ime/input_engine.cc b/chromeos/services/ime/input_engine.cc
index f3e785d..bee594a 100644
--- a/chromeos/services/ime/input_engine.cc
+++ b/chromeos/services/ime/input_engine.cc
@@ -232,9 +232,5 @@
   NOTIMPLEMENTED();  // Not used in the rulebased engine.
 }
 
-void InputEngine::RecordUkm(mojom::UkmEntryPtr entry) {
-  NOTIMPLEMENTED();  // Not used in the rulebased engine.
-}
-
 }  // namespace ime
 }  // namespace chromeos
diff --git a/chromeos/services/ime/input_engine.h b/chromeos/services/ime/input_engine.h
index 233a8ea..b6c731da 100644
--- a/chromeos/services/ime/input_engine.h
+++ b/chromeos/services/ime/input_engine.h
@@ -76,7 +76,6 @@
                           RequestSuggestionsCallback callback) override;
   void DisplaySuggestions(
       const std::vector<TextSuggestion>& suggestions) override;
-  void RecordUkm(mojom::UkmEntryPtr entry) override;
 
   // TODO(https://crbug.com/837156): Implement a state for the interface.
 
diff --git a/chromeos/services/ime/mock_input_channel.h b/chromeos/services/ime/mock_input_channel.h
index ce17d92..9acc0773 100644
--- a/chromeos/services/ime/mock_input_channel.h
+++ b/chromeos/services/ime/mock_input_channel.h
@@ -89,7 +89,6 @@
               DisplaySuggestions,
               (const std::vector<ime::TextSuggestion>& suggestions),
               (override));
-  MOCK_METHOD(void, RecordUkm, (mojom::UkmEntryPtr entry), (override));
 
  private:
   mojo::Receiver<mojom::InputChannel> receiver_;
diff --git a/chromeos/services/ime/public/mojom/input_engine.mojom b/chromeos/services/ime/public/mojom/input_engine.mojom
index ee1f153a..c3172f5 100644
--- a/chromeos/services/ime/public/mojom/input_engine.mojom
+++ b/chromeos/services/ime/public/mojom/input_engine.mojom
@@ -220,21 +220,6 @@
   array<SuggestionCandidate> candidates;
 };
 
-// A URL-Keyed Metric (UKM) entry.
-union UkmEntry {
-  NonCompliantApiMetric non_compliant_api;
-};
-
-enum InputMethodApiOperation {
-  kCommitText = 0,
-  kSetCompositionText = 1,
-  kDeleteSurroundingText = 2,
-};
-
-struct NonCompliantApiMetric {
-  InputMethodApiOperation non_compliant_operation;
-};
-
 // Manages access to a set of IME engines, implemented by the IME service
 // itself. The IME framework in the browser process is responsible for brokering
 // the connection between the IME service and the IME extension, but does not
@@ -368,9 +353,6 @@
 
   // Asks the system to display the given suggestions to the user
   DisplaySuggestions(array<SuggestionCandidate> suggestions);
-
-  // Record a Url-Keyed Metric (UKM).
-  RecordUkm(UkmEntry entry);
 };
 
 // Implemented in the browser process, used to perform network requests or
diff --git a/chromeos/services/ime/public/proto/messages.proto b/chromeos/services/ime/public/proto/messages.proto
index 062a14ba..af102717 100644
--- a/chromeos/services/ime/public/proto/messages.proto
+++ b/chromeos/services/ime/public/proto/messages.proto
@@ -43,7 +43,6 @@
     SuggestionsRequest suggestions_request = 15;
     SuggestionsResponse suggestions_response = 16;
     DisplaySuggestions display_suggestions = 17;
-    RecordUkm record_ukm = 18;
   }
 }
 
@@ -263,22 +262,3 @@
 message DisplaySuggestions {
   repeated SuggestionCandidate candidates = 1;
 }
-
-// Protobuf version of InputEngine::RecordUkm in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-message RecordUkm {
-  oneof entry { NonCompliantApiMetric non_compliant_api = 1; }
-}
-
-// Protobuf version of NonCompliantApiMetric in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-message NonCompliantApiMetric {
-  enum InputMethodApiOperation {
-    OPERATION_UNSPECIFIED = 0;  // Reserved
-    OPERATION_COMMIT_TEXT = 1;
-    OPERATION_SET_COMPOSITION_TEXT = 2;
-    OPERATION_DELETE_SURROUNDING_TEXT = 3;
-  }
-
-  optional InputMethodApiOperation non_compliant_operation = 1;
-}
diff --git a/components/arc/net/arc_net_host_impl.cc b/components/arc/net/arc_net_host_impl.cc
index 9606094..d751681f 100644
--- a/components/arc/net/arc_net_host_impl.cc
+++ b/components/arc/net/arc_net_host_impl.cc
@@ -528,16 +528,17 @@
                                       std::move(wifi_dict));
 
   std::string user_id_hash = chromeos::LoginState::Get()->primary_user_hash();
-  // TODO(crbug.com/730593): Remove AdaptCallbackForRepeating() by updating
+  // TODO(crbug.com/730593): Remove SplitOnceCallback() by updating
   // the callee interface.
-  auto repeating_callback =
-      base::AdaptCallbackForRepeating(std::move(callback));
+  auto split_callback = base::SplitOnceCallback(std::move(callback));
   GetManagedConfigurationHandler()->CreateConfiguration(
       user_id_hash, *properties,
       base::BindOnce(&ArcNetHostImpl::CreateNetworkSuccessCallback,
-                     weak_factory_.GetWeakPtr(), repeating_callback),
+                     weak_factory_.GetWeakPtr(),
+                     std::move(split_callback.first)),
       base::BindOnce(&ArcNetHostImpl::CreateNetworkFailureCallback,
-                     weak_factory_.GetWeakPtr(), repeating_callback));
+                     weak_factory_.GetWeakPtr(),
+                     std::move(split_callback.second)));
 }
 
 bool ArcNetHostImpl::GetNetworkPathFromGuid(const std::string& guid,
@@ -573,13 +574,15 @@
   }
 
   cached_guid_.clear();
-  // TODO(crbug.com/730593): Remove AdaptCallbackForRepeating() by updating
+  // TODO(crbug.com/730593): Remove SplitOnceCallback() by updating
   // the callee interface.
-  auto repeating_callback =
-      base::AdaptCallbackForRepeating(std::move(callback));
+  auto split_callback = base::SplitOnceCallback(std::move(callback));
   GetManagedConfigurationHandler()->RemoveConfiguration(
-      path, base::BindOnce(&ForgetNetworkSuccessCallback, repeating_callback),
-      base::BindOnce(&ForgetNetworkFailureCallback, repeating_callback));
+      path,
+      base::BindOnce(&ForgetNetworkSuccessCallback,
+                     std::move(split_callback.first)),
+      base::BindOnce(&ForgetNetworkFailureCallback,
+                     std::move(split_callback.second)));
 }
 
 void ArcNetHostImpl::StartConnect(const std::string& guid,
@@ -591,13 +594,15 @@
     return;
   }
 
-  // TODO(crbug.com/730593): Remove AdaptCallbackForRepeating() by updating
+  // TODO(crbug.com/730593): Remove SplitOnceCallback() by updating
   // the callee interface.
-  auto repeating_callback =
-      base::AdaptCallbackForRepeating(std::move(callback));
+  auto split_callback = base::SplitOnceCallback(std::move(callback));
   GetNetworkConnectionHandler()->ConnectToNetwork(
-      path, base::BindOnce(&StartConnectSuccessCallback, repeating_callback),
-      base::BindOnce(&StartConnectFailureCallback, repeating_callback),
+      path,
+      base::BindOnce(&StartConnectSuccessCallback,
+                     std::move(split_callback.first)),
+      base::BindOnce(&StartConnectFailureCallback,
+                     std::move(split_callback.second)),
       false /* check_error_state */, chromeos::ConnectCallbackMode::ON_STARTED);
 }
 
@@ -610,13 +615,15 @@
     return;
   }
 
-  // TODO(crbug.com/730593): Remove AdaptCallbackForRepeating() by updating
+  // TODO(crbug.com/730593): Remove SplitOnceCallback() by updating
   // the callee interface.
-  auto repeating_callback =
-      base::AdaptCallbackForRepeating(std::move(callback));
+  auto split_callback = base::SplitOnceCallback(std::move(callback));
   GetNetworkConnectionHandler()->DisconnectNetwork(
-      path, base::BindOnce(&StartDisconnectSuccessCallback, repeating_callback),
-      base::BindOnce(&StartDisconnectFailureCallback, repeating_callback));
+      path,
+      base::BindOnce(&StartDisconnectSuccessCallback,
+                     std::move(split_callback.first)),
+      base::BindOnce(&StartDisconnectFailureCallback,
+                     std::move(split_callback.second)));
 }
 
 void ArcNetHostImpl::GetWifiEnabledState(GetWifiEnabledStateCallback callback) {
diff --git a/components/arc/usb/usb_host_bridge.cc b/components/arc/usb/usb_host_bridge.cc
index 30c3340..bc2be262 100644
--- a/components/arc/usb/usb_host_bridge.cc
+++ b/components/arc/usb/usb_host_bridge.cc
@@ -192,12 +192,11 @@
     return;
   }
 
-  auto repeating_callback =
-      base::AdaptCallbackForRepeating(std::move(callback));
+  auto split_callback = base::SplitOnceCallback(std::move(callback));
   chromeos::PermissionBrokerClient::Get()->OpenPath(
       GetDevicePath(*iter->second),
-      base::BindOnce(&OnDeviceOpened, repeating_callback),
-      base::BindOnce(&OnDeviceOpenError, repeating_callback));
+      base::BindOnce(&OnDeviceOpened, std::move(split_callback.first)),
+      base::BindOnce(&OnDeviceOpenError, std::move(split_callback.second)));
 }
 
 void ArcUsbHostBridge::OpenDeviceDeprecated(
diff --git a/components/autofill/core/browser/autofill_client.cc b/components/autofill/core/browser/autofill_client.cc
index 4141c76..f8ffc93 100644
--- a/components/autofill/core/browser/autofill_client.cc
+++ b/components/autofill/core/browser/autofill_client.cc
@@ -66,6 +66,13 @@
   // ChromeAutofillClient (Chrome Desktop and Clank) implements this.
 }
 
+void AutofillClient::ShowVirtualCardManualFallbackBubble(
+    const CreditCard* credit_card,
+    const std::u16string& cvc) {
+  // This is overridden by platform subclasses. Currently only
+  // ChromeAutofillClient (Chrome Desktop) implements this.
+}
+
 bool AutofillClient::IsAutofillAssistantShowing() {
   return false;
 }
diff --git a/components/autofill/core/browser/autofill_client.h b/components/autofill/core/browser/autofill_client.h
index c0589e1..967f0c66 100644
--- a/components/autofill/core/browser/autofill_client.h
+++ b/components/autofill/core/browser/autofill_client.h
@@ -527,6 +527,12 @@
   virtual void ShowOfferNotificationIfApplicable(
       const AutofillOfferData* offer);
 
+  // Shows the manual fallback bubble and displya card information in
+  // |credit_card| and |cvc|.
+  virtual void ShowVirtualCardManualFallbackBubble(
+      const CreditCard* credit_card,
+      const std::u16string& cvc);
+
   // Returns true if the Autofill Assistant UI is currently being shown.
   virtual bool IsAutofillAssistantShowing();
 
diff --git a/components/autofill/core/browser/autofill_metrics.cc b/components/autofill/core/browser/autofill_metrics.cc
index b338345a..c7604e60 100644
--- a/components/autofill/core/browser/autofill_metrics.cc
+++ b/components/autofill/core/browser/autofill_metrics.cc
@@ -1875,6 +1875,9 @@
         num_unmasked_cards += 1;
         num_disused_unmasked_cards += disused_delta;
         break;
+      case CreditCard::VIRTUAL_CARD:
+        // This card type is not persisted in Chrome.
+        break;
     }
   }
 
diff --git a/components/autofill/core/browser/browser_autofill_manager.cc b/components/autofill/core/browser/browser_autofill_manager.cc
index cd68777..582b3545 100644
--- a/components/autofill/core/browser/browser_autofill_manager.cc
+++ b/components/autofill/core/browser/browser_autofill_manager.cc
@@ -1459,8 +1459,9 @@
   FormStructure* form_structure = nullptr;
   AutofillField* autofill_field = nullptr;
   if (!GetCachedFormAndField(credit_card_form_, credit_card_field_,
-                             &form_structure, &autofill_field))
+                             &form_structure, &autofill_field)) {
     return;
+  }
 
   // The originally selected masked card is |credit_card_|. So we must log
   // |credit_card_| as opposed to |credit_card| to correctly indicate that the
@@ -1469,6 +1470,13 @@
       credit_card_, *form_structure, *autofill_field, sync_state_);
 
   DCHECK(credit_card);
+
+  // If synced down card is a virtual card, show a manual fallback bubble for
+  // it in addition to filling the card.
+  if (credit_card->record_type() == CreditCard::VIRTUAL_CARD) {
+    client()->ShowVirtualCardManualFallbackBubble(credit_card, cvc);
+  }
+
   FillCreditCardForm(credit_card_query_id_, credit_card_form_,
                      credit_card_field_, *credit_card, cvc);
   if (credit_card->record_type() == CreditCard::FULL_SERVER_CARD) {
diff --git a/components/autofill/core/browser/data_model/credit_card.h b/components/autofill/core/browser/data_model/credit_card.h
index 387e493..f4a862b 100644
--- a/components/autofill/core/browser/data_model/credit_card.h
+++ b/components/autofill/core/browser/data_model/credit_card.h
@@ -52,6 +52,10 @@
     // A card from the Wallet server with full information store locally. This
     // card is not locally editable.
     FULL_SERVER_CARD,
+
+    // A card generated from a server card by the card issuer. This card is not
+    // persisted in Chrome.
+    VIRTUAL_CARD,
   };
 
   // The status of this card. Only used for server cards.
diff --git a/components/autofill/core/browser/personal_data_manager_unittest.cc b/components/autofill/core/browser/personal_data_manager_unittest.cc
index b5a6c01..71ffa33 100644
--- a/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -219,7 +219,7 @@
         base::ThreadTaskRunnerHandle::Get());
     account_database_service_->Init(base::NullCallback());
 
-    strike_database_.reset(new TestInMemoryStrikeDatabase());
+    strike_database_ = std::make_unique<TestInMemoryStrikeDatabase>();
 
     test::DisableSystemServices(prefs_.get());
   }
diff --git a/components/background_fetch/background_fetch_delegate_base.cc b/components/background_fetch/background_fetch_delegate_base.cc
index 9d5e20c1d..7088939 100644
--- a/components/background_fetch/background_fetch_delegate_base.cc
+++ b/components/background_fetch/background_fetch_delegate_base.cc
@@ -109,11 +109,11 @@
   }
 
   if (job_details->job_state == JobDetails::State::kStartedButPaused) {
-    job_details->on_resume =
-        base::BindOnce(&BackgroundFetchDelegateBase::StartDownload,
-                       GetWeakPtr(), job_id, params, has_request_body);
+    job_details->on_resume = base::BindOnce(
+        &BackgroundFetchDelegateBase::StartDownload, GetWeakPtr(), job_id,
+        std::move(params), has_request_body);
   } else {
-    StartDownload(job_id, params, has_request_body);
+    StartDownload(job_id, std::move(params), has_request_body);
   }
 
   DoUpdateUi(job_id);
@@ -195,15 +195,14 @@
   return &job_details_iter->second;
 }
 
-void BackgroundFetchDelegateBase::StartDownload(
-    const std::string& job_id,
-    const download::DownloadParams& params,
-    bool has_request_body) {
+void BackgroundFetchDelegateBase::StartDownload(const std::string& job_id,
+                                                download::DownloadParams params,
+                                                bool has_request_body) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   GetJobDetails(job_id)->current_fetch_guids.emplace(params.guid,
                                                      has_request_body);
-  GetDownloadService()->StartDownload(params);
+  GetDownloadService()->StartDownload(std::move(params));
 }
 
 void BackgroundFetchDelegateBase::Abort(const std::string& job_id) {
diff --git a/components/background_fetch/background_fetch_delegate_base.h b/components/background_fetch/background_fetch_delegate_base.h
index f5b38620..4a0e1e5 100644
--- a/components/background_fetch/background_fetch_delegate_base.h
+++ b/components/background_fetch/background_fetch_delegate_base.h
@@ -133,7 +133,7 @@
  private:
   // Starts a download according to `params` belonging to `job_id`.
   void StartDownload(const std::string& job_id,
-                     const download::DownloadParams& params,
+                     download::DownloadParams params,
                      bool has_request_body);
 
   void OnDownloadReceived(const std::string& guid,
diff --git a/components/background_sync/background_sync_permission_context_unittest.cc b/components/background_sync/background_sync_permission_context_unittest.cc
index e15d89a..5f8585d 100644
--- a/components/background_sync/background_sync_permission_context_unittest.cc
+++ b/components/background_sync/background_sync_permission_context_unittest.cc
@@ -43,9 +43,9 @@
         permissions::PermissionRequestID::RequestLocalId());
     permission_context->RequestPermission(
         web_contents(), id, url, /* user_gesture= */ false,
-        base::AdaptCallbackForRepeating(base::BindOnce(
+        base::BindOnce(
             &BackgroundSyncPermissionContextTest::TrackPermissionDecision,
-            base::Unretained(this), run_loop.QuitClosure())));
+            base::Unretained(this), run_loop.QuitClosure()));
 
     run_loop.Run();
   }
diff --git a/components/cast_channel/cast_message_handler_unittest.cc b/components/cast_channel/cast_message_handler_unittest.cc
index ef7aa00cc..d56349e 100644
--- a/components/cast_channel/cast_message_handler_unittest.cc
+++ b/components/cast_channel/cast_message_handler_unittest.cc
@@ -139,20 +139,20 @@
 
   void ExpectEnsureConnection() {
     EXPECT_CALL(*transport_,
-                SendMessage(HasMessageType(CastMessageType::kConnect), _));
+                SendMessage_(HasMessageType(CastMessageType::kConnect), _));
   }
 
   void ExpectEnsureConnectionThen(CastMessageType next_type,
                                   int request_count = 1) {
     InSequence dummy;
     ExpectEnsureConnection();
-    EXPECT_CALL(*transport_, SendMessage(HasMessageType(next_type), _))
+    EXPECT_CALL(*transport_, SendMessage_(HasMessageType(next_type), _))
         .Times(request_count)
         .WillRepeatedly(SaveArg<0>(&last_request_));
   }
 
   void CreatePendingRequests() {
-    EXPECT_CALL(*transport_, SendMessage(_, _)).Times(AnyNumber());
+    EXPECT_CALL(*transport_, SendMessage_(_, _)).Times(AnyNumber());
     handler_.LaunchSession(channel_id_, kAppId1, base::TimeDelta::Max(),
                            {"WEB"}, /* appParams */ base::nullopt,
                            launch_session_callback_.Get());
@@ -177,14 +177,14 @@
       InSequence dummy;
       // We should first send a CONNECT request to ensure a connection.
       EXPECT_CALL(*transport_,
-                  SendMessage(HasMessageType(CastMessageType::kConnect), _))
+                  SendMessage_(HasMessageType(CastMessageType::kConnect), _))
           .WillOnce(WithArg<0>([&](const CastMessage& message) {
             std::unique_ptr<base::Value> dict =
                 GetDictionaryFromCastMessage(message);
             EXPECT_EQ(connection_type, dict->FindIntKey("connType").value());
           }));
       // Then we send the actual message.
-      EXPECT_CALL(*transport_, SendMessage(_, _));
+      EXPECT_CALL(*transport_, SendMessage_(_, _));
     }
     EXPECT_EQ(Result::kOk, handler_.SendAppMessage(channel_id_, message));
   }
@@ -313,7 +313,7 @@
 }
 
 TEST_F(CastMessageHandlerTest, RequestAppAvailabilityTimesOut) {
-  EXPECT_CALL(*transport_, SendMessage(_, _)).Times(2);
+  EXPECT_CALL(*transport_, SendMessage_(_, _)).Times(2);
   handler_.RequestAppAvailability(
       &cast_socket_, "ABCDEFAB",
       base::BindOnce(&CastMessageHandlerTest::OnAppAvailability,
@@ -324,13 +324,13 @@
 }
 
 TEST_F(CastMessageHandlerTest, AppAvailabilitySentOnlyOnceWhilePending) {
-  EXPECT_CALL(*transport_, SendMessage(_, _)).Times(2);
+  EXPECT_CALL(*transport_, SendMessage_(_, _)).Times(2);
   handler_.RequestAppAvailability(
       &cast_socket_, "ABCDEFAB",
       base::BindOnce(&CastMessageHandlerTest::OnAppAvailability,
                      base::Unretained(this)));
 
-  EXPECT_CALL(*transport_, SendMessage(_, _)).Times(0);
+  EXPECT_CALL(*transport_, SendMessage_(_, _)).Times(0);
   handler_.RequestAppAvailability(
       &cast_socket_, "ABCDEFAB",
       base::BindOnce(&CastMessageHandlerTest::OnAppAvailability,
@@ -344,7 +344,7 @@
                             VirtualConnectionType::kStrong);
 
   // No-op because connection is already created the first time.
-  EXPECT_CALL(*transport_, SendMessage(_, _)).Times(0);
+  EXPECT_CALL(*transport_, SendMessage_(_, _)).Times(0);
   handler_.EnsureConnection(channel_id_, kSourceId, kDestinationId,
                             VirtualConnectionType::kStrong);
 }
@@ -356,7 +356,7 @@
 
   EXPECT_CALL(
       *transport_,
-      SendMessage(HasMessageType(CastMessageType::kCloseConnection), _));
+      SendMessage_(HasMessageType(CastMessageType::kCloseConnection), _));
   handler_.CloseConnection(channel_id_, kSourceId, kDestinationId);
 
   // Re-open virtual connection should cause CONNECT message to be sent.
@@ -384,7 +384,7 @@
   task_environment_.RunUntilIdle();
 
   // Re-open virtual connection should cause message to be sent.
-  EXPECT_CALL(*transport_, SendMessage(_, _));
+  EXPECT_CALL(*transport_, SendMessage_(_, _));
   handler_.EnsureConnection(channel_id_, kSourceId, kDestinationId,
                             VirtualConnectionType::kStrong);
 }
@@ -468,7 +468,7 @@
     InSequence dummy;
     ExpectEnsureConnection();
     EXPECT_CALL(*transport_,
-                SendMessage(HasPayloadUtf8(message.payload_utf8()), _));
+                SendMessage_(HasPayloadUtf8(message.payload_utf8()), _));
   }
 
   EXPECT_EQ(Result::kOk, handler_.SendAppMessage(channel_id_, message));
@@ -503,7 +503,7 @@
   {
     InSequence dummy;
     ExpectEnsureConnection();
-    EXPECT_CALL(*transport_, SendMessage(_, _))
+    EXPECT_CALL(*transport_, SendMessage_(_, _))
         .WillOnce(WithArg<0>([&](const auto& message) {
           std::string expected_body = R"({
             "requestId": 1,
@@ -538,7 +538,7 @@
     InSequence dummy;
     ExpectEnsureConnection();
     EXPECT_CALL(*transport_,
-                SendMessage(HasPayloadUtf8(message.payload_utf8()), _));
+                SendMessage_(HasPayloadUtf8(message.payload_utf8()), _));
   }
 
   EXPECT_EQ(Result::kOk,
@@ -561,7 +561,7 @@
   {
     InSequence dummy;
     ExpectEnsureConnection();
-    EXPECT_CALL(*transport_, SendMessage(_, _))
+    EXPECT_CALL(*transport_, SendMessage_(_, _))
         .WillOnce(WithArg<0>([&](const auto& message) {
           std::string expected_body = R"({
             "requestId": 1,
@@ -644,7 +644,7 @@
 
 // Check that set volume requests time out correctly.
 TEST_F(CastMessageHandlerTest, SetVolumeTimedOut) {
-  EXPECT_CALL(*transport_, SendMessage(_, _)).Times(AnyNumber());
+  EXPECT_CALL(*transport_, SendMessage_(_, _)).Times(AnyNumber());
 
   std::string message_str = R"({
     "sessionId": "theSessionId",
@@ -670,7 +670,7 @@
       .WillOnce(WithArg<0>([](LaunchSessionResponse response) {
         EXPECT_EQ(LaunchSessionResponse::Result::kError, response.result);
       }));
-  EXPECT_CALL(*transport_, SendMessage(_, _)).Times(AnyNumber());
+  EXPECT_CALL(*transport_, SendMessage_(_, _)).Times(AnyNumber());
   handler_.LaunchSession(channel_id_, kAppId1, base::TimeDelta::Max(), {"WEB"},
                          /* appParams */ base::nullopt,
                          expect_success_callback.Get());
@@ -688,7 +688,7 @@
   base::MockCallback<ResultCallback> expect_success_callback;
   base::MockCallback<ResultCallback> expect_failure_callback;
 
-  EXPECT_CALL(*transport_, SendMessage(_, _)).Times(AnyNumber());
+  EXPECT_CALL(*transport_, SendMessage_(_, _)).Times(AnyNumber());
   handler_.LaunchSession(channel_id_, kAppId1, base::TimeDelta::Max(), {"WEB"},
                          /* appParams */ base::nullopt,
                          launch_session_callback_.Get());
diff --git a/components/cast_channel/cast_socket_service_unittest.cc b/components/cast_channel/cast_socket_service_unittest.cc
index b517730..1e6458f 100644
--- a/components/cast_channel/cast_socket_service_unittest.cc
+++ b/components/cast_channel/cast_socket_service_unittest.cc
@@ -5,6 +5,7 @@
 #include "components/cast_channel/cast_socket_service.h"
 
 #include "base/memory/ptr_util.h"
+#include "base/test/gmock_callback_support.h"
 #include "base/test/mock_callback.h"
 #include "base/test/test_simple_task_runner.h"
 #include "components/cast_channel/cast_test_util.h"
@@ -84,11 +85,8 @@
   mock_socket->SetIPEndpoint(ip_endpoint);
   cast_socket_service_->SetSocketForTest(base::WrapUnique(mock_socket));
 
-  EXPECT_CALL(*mock_socket, ConnectInternal(_))
-      .WillOnce(WithArgs<0>(
-          Invoke([&](const MockCastSocket::MockOnOpenCallback& callback) {
-            callback.Run(mock_socket);
-          })));
+  EXPECT_CALL(*mock_socket, Connect_(_))
+      .WillOnce(base::test::RunOnceCallback<0>(mock_socket));
   EXPECT_CALL(mock_on_open_callback_, Run(mock_socket));
   EXPECT_CALL(*mock_socket, AddObserver(_));
 
diff --git a/components/cast_channel/cast_socket_unittest.cc b/components/cast_channel/cast_socket_unittest.cc
index 7159bd2a..d4bb2347 100644
--- a/components/cast_channel/cast_socket_unittest.cc
+++ b/components/cast_channel/cast_socket_unittest.cc
@@ -441,7 +441,7 @@
     socket_->SetupMockTransport();
     CastMessage challenge_proto = CreateAuthChallenge();
     EXPECT_CALL(*socket_->GetMockTransport(),
-                SendMessage(EqualsProto(challenge_proto), _))
+                SendMessage_(EqualsProto(challenge_proto), _))
         .WillOnce(PostCompletionCallbackTask<1>(net::OK));
     EXPECT_CALL(*socket_->GetMockTransport(), Start());
     EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
@@ -658,7 +658,7 @@
 
   CastMessage challenge_proto = CreateAuthChallenge();
   EXPECT_CALL(*socket_->GetMockTransport(),
-              SendMessage(EqualsProto(challenge_proto), _))
+              SendMessage_(EqualsProto(challenge_proto), _))
       .WillOnce(PostCompletionCallbackTask<1>(net::OK));
   EXPECT_CALL(*socket_->GetMockTransport(), Start());
   EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
@@ -826,7 +826,7 @@
   client_socket_factory()->SetupTcpConnect(net::SYNCHRONOUS, net::OK);
   client_socket_factory()->SetupSslConnect(net::SYNCHRONOUS, net::OK);
   EXPECT_CALL(*socket_->GetMockTransport(),
-              SendMessage(EqualsProto(CreateAuthChallenge()), _))
+              SendMessage_(EqualsProto(CreateAuthChallenge()), _))
       .WillOnce(PostCompletionCallbackTask<1>(net::ERR_CONNECTION_RESET));
 
   EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
@@ -846,7 +846,7 @@
   client_socket_factory()->SetupTcpConnect(net::SYNCHRONOUS, net::OK);
   client_socket_factory()->SetupSslConnect(net::SYNCHRONOUS, net::OK);
   EXPECT_CALL(*socket_->GetMockTransport(),
-              SendMessage(EqualsProto(CreateAuthChallenge()), _))
+              SendMessage_(EqualsProto(CreateAuthChallenge()), _))
       .WillOnce(PostCompletionCallbackTask<1>(net::ERR_CONNECTION_RESET));
   socket_->Connect(base::BindOnce(&CompleteHandler::OnConnectComplete,
                                   base::Unretained(&handler_)));
@@ -863,7 +863,7 @@
   client_socket_factory()->SetupTcpConnect(net::SYNCHRONOUS, net::OK);
   client_socket_factory()->SetupSslConnect(net::SYNCHRONOUS, net::OK);
   EXPECT_CALL(*socket_->GetMockTransport(),
-              SendMessage(EqualsProto(CreateAuthChallenge()), _))
+              SendMessage_(EqualsProto(CreateAuthChallenge()), _))
       .WillOnce(PostCompletionCallbackTask<1>(net::OK));
   client_socket_factory()->AddReadResult(net::SYNCHRONOUS, net::ERR_FAILED);
   EXPECT_CALL(*observer_, OnError(_, ChannelError::CAST_SOCKET_ERROR));
@@ -891,7 +891,7 @@
   EXPECT_CALL(*observer_, OnError(_, ChannelError::AUTHENTICATION_ERROR));
   CastMessage challenge_proto = CreateAuthChallenge();
   EXPECT_CALL(*socket_->GetMockTransport(),
-              SendMessage(EqualsProto(challenge_proto), _))
+              SendMessage_(EqualsProto(challenge_proto), _))
       .WillOnce(PostCompletionCallbackTask<1>(net::OK));
   EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
   EXPECT_CALL(*socket_->GetMockTransport(), Start());
diff --git a/components/cast_channel/cast_test_util.h b/components/cast_channel/cast_test_util.h
index 01b22c6..bcbb8d7 100644
--- a/components/cast_channel/cast_test_util.h
+++ b/components/cast_channel/cast_test_util.h
@@ -39,12 +39,12 @@
                    net::CompletionOnceCallback callback) override {
     // GMock does not handle move-only types, we need to rely on a mock method
     // that takes a repeating callback, which will work well with GMock actions.
-    SendMessage(message, base::AdaptCallbackForRepeating(std::move(callback)));
+    SendMessage_(message, callback);
   }
 
-  MOCK_METHOD2(SendMessage,
+  MOCK_METHOD2(SendMessage_,
                void(const CastMessage& message,
-                    const net::CompletionRepeatingCallback& callback));
+                    net::CompletionOnceCallback& callback));
 
   MOCK_METHOD0(Start, void(void));
 
@@ -89,15 +89,12 @@
   void OpenSocket(NetworkContextGetter network_context_getter,
                   const CastSocketOpenParams& open_params,
                   CastSocket::OnOpenCallback open_cb) override {
-    // Unit test should not call |open_cb| more than once. Just use
-    // base::AdaptCallbackForRepeating to pass |open_cb| to a mock method.
-    OpenSocketInternal(open_params.ip_endpoint,
-                       base::AdaptCallbackForRepeating(std::move(open_cb)));
+    OpenSocket_(open_params.ip_endpoint, open_cb);
   }
 
-  MOCK_METHOD2(OpenSocketInternal,
+  MOCK_METHOD2(OpenSocket_,
                void(const net::IPEndPoint& ip_endpoint,
-                    const base::RepeatingCallback<void(CastSocket*)>& open_cb));
+                    CastSocket::OnOpenCallback& open_cb));
   MOCK_CONST_METHOD1(GetSocket, CastSocket*(int channel_id));
 };
 
@@ -109,19 +106,17 @@
   ~MockCastSocket() override;
 
   void Connect(CastSocket::OnOpenCallback callback) override {
-    // Unit test should not call |open_cb| more than once. Just use
-    // base::AdaptCallbackForRepeating to pass |open_cb| to a mock method.
-    ConnectInternal(base::AdaptCallbackForRepeating(std::move(callback)));
+    Connect_(callback);
   }
 
   void Close(net::CompletionOnceCallback callback) override {
     // GMock does not handle move-only types, we need to rely on a mock method
     // that takes a repeating callback, which will work well with GMock actions.
-    Close(base::AdaptCallbackForRepeating(std::move(callback)));
+    Close_(callback);
   }
 
-  MOCK_METHOD1(ConnectInternal, void(const MockOnOpenCallback& callback));
-  MOCK_METHOD1(Close, void(const net::CompletionRepeatingCallback& callback));
+  MOCK_METHOD1(Connect_, void(CastSocket::OnOpenCallback& callback));
+  MOCK_METHOD1(Close_, void(net::CompletionOnceCallback& callback));
   MOCK_CONST_METHOD0(ready_state, ReadyState());
   MOCK_METHOD1(AddObserver, void(Observer* observer));
   MOCK_METHOD1(RemoveObserver, void(Observer* observer));
@@ -231,7 +226,7 @@
                 HAS_1_TEMPLATE_PARAMS(int, cb_idx),
                 AND_1_VALUE_PARAMS(rv)) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(testing::get<cb_idx>(args), rv));
+      FROM_HERE, base::BindOnce(std::move(testing::get<cb_idx>(args)), rv));
 }
 
 }  // namespace cast_channel
diff --git a/components/cast_channel/cast_transport_unittest.cc b/components/cast_channel/cast_transport_unittest.cc
index 43ad1c2..a3d0ce5 100644
--- a/components/cast_channel/cast_transport_unittest.cc
+++ b/components/cast_channel/cast_transport_unittest.cc
@@ -121,7 +121,7 @@
 ACTION_TEMPLATE(EnqueueCallback,
                 HAS_1_TEMPLATE_PARAMS(int, cb_idx),
                 AND_1_VALUE_PARAMS(completion_queue)) {
-  completion_queue->Push(testing::get<cb_idx>(args));
+  completion_queue->Push(std::move(testing::get<cb_idx>(args)));
 }
 
 }  // namespace
@@ -131,24 +131,24 @@
   void Read(net::IOBuffer* buffer,
             int bytes,
             net::CompletionOnceCallback callback) override {
-    Read(buffer, bytes, base::AdaptCallbackForRepeating(std::move(callback)));
+    Read_(buffer, bytes, callback);
   }
 
   void Write(net::IOBuffer* buffer,
              int bytes,
              net::CompletionOnceCallback callback) override {
-    Write(buffer, bytes, base::AdaptCallbackForRepeating(std::move(callback)));
+    Write_(buffer, bytes, callback);
   }
 
-  MOCK_METHOD3(Read,
+  MOCK_METHOD3(Read_,
                void(net::IOBuffer* buf,
                     int buf_len,
-                    const net::CompletionRepeatingCallback& callback));
+                    net::CompletionOnceCallback& callback));
 
-  MOCK_METHOD3(Write,
+  MOCK_METHOD3(Write_,
                void(net::IOBuffer* buf,
                     int buf_len,
-                    const net::CompletionRepeatingCallback& callback));
+                    net::CompletionOnceCallback& callback));
 };
 
 class CastTransportTest : public testing::Test {
@@ -186,7 +186,7 @@
   std::string serialized_message;
   EXPECT_TRUE(MessageFramer::Serialize(message, &serialized_message));
 
-  EXPECT_CALL(mock_socket_, Write(NotNull(), serialized_message.size(), _))
+  EXPECT_CALL(mock_socket_, Write_(NotNull(), serialized_message.size(), _))
       .WillOnce(DoAll(ReadBufferToString<0, 1>(&output),
                       EnqueueCallback<2>(&socket_cbs)));
   EXPECT_CALL(write_handler, Complete(net::OK));
@@ -211,13 +211,13 @@
 
   // Only one byte is written.
   EXPECT_CALL(mock_socket_,
-              Write(NotNull(), static_cast<int>(serialized_message.size()), _))
+              Write_(NotNull(), static_cast<int>(serialized_message.size()), _))
       .WillOnce(DoAll(ReadBufferToString<0, 1>(&output),
                       EnqueueCallback<2>(&socket_cbs)));
   // Remainder of bytes are written.
   EXPECT_CALL(
       mock_socket_,
-      Write(NotNull(), static_cast<int>(serialized_message.size() - 1), _))
+      Write_(NotNull(), static_cast<int>(serialized_message.size() - 1), _))
       .WillOnce(DoAll(ReadBufferToString<0, 1>(&output),
                       EnqueueCallback<2>(&socket_cbs)));
 
@@ -240,7 +240,7 @@
   CompletionQueue socket_cbs;
   CompleteHandler write_handler;
   CastMessage message = CreateCastMessage();
-  EXPECT_CALL(mock_socket_, Write(NotNull(), _, _))
+  EXPECT_CALL(mock_socket_, Write_(NotNull(), _, _))
       .WillOnce(EnqueueCallback<2>(&socket_cbs));
   EXPECT_CALL(write_handler, Complete(net::ERR_FAILED));
   EXPECT_CALL(*delegate_, OnError(ChannelError::CAST_SOCKET_ERROR));
@@ -269,16 +269,16 @@
 
   // Read bytes [0, 3].
   EXPECT_CALL(mock_socket_,
-              Read(NotNull(), MessageFramer::MessageHeader::header_size(), _))
+              Read_(NotNull(), MessageFramer::MessageHeader::header_size(), _))
       .WillOnce(DoAll(FillBufferFromString<0>(serialized_message),
                       EnqueueCallback<2>(&socket_cbs)));
 
   // Read bytes [4, n].
   EXPECT_CALL(mock_socket_,
-              Read(NotNull(),
-                   serialized_message.size() -
-                       MessageFramer::MessageHeader::header_size(),
-                   _))
+              Read_(NotNull(),
+                    serialized_message.size() -
+                        MessageFramer::MessageHeader::header_size(),
+                    _))
       .WillOnce(DoAll(FillBufferFromString<0>(serialized_message.substr(
                           MessageFramer::MessageHeader::header_size(),
                           serialized_message.size() -
@@ -288,7 +288,7 @@
 
   EXPECT_CALL(*delegate_, OnMessage(EqualsProto(message)));
   EXPECT_CALL(mock_socket_,
-              Read(NotNull(), MessageFramer::MessageHeader::header_size(), _));
+              Read_(NotNull(), MessageFramer::MessageHeader::header_size(), _));
   transport_->Start();
   RunPendingTasks();
   socket_cbs.Pop(MessageFramer::MessageHeader::header_size());
@@ -309,16 +309,16 @@
 
   // Read bytes [0, 3].
   EXPECT_CALL(mock_socket_,
-              Read(NotNull(), MessageFramer::MessageHeader::header_size(), _))
+              Read_(NotNull(), MessageFramer::MessageHeader::header_size(), _))
       .WillOnce(DoAll(FillBufferFromString<0>(serialized_message),
                       EnqueueCallback<2>(&socket_cbs)))
       .RetiresOnSaturation();
   // Read bytes [4, n-1].
   EXPECT_CALL(mock_socket_,
-              Read(NotNull(),
-                   serialized_message.size() -
-                       MessageFramer::MessageHeader::header_size(),
-                   _))
+              Read_(NotNull(),
+                    serialized_message.size() -
+                        MessageFramer::MessageHeader::header_size(),
+                    _))
       .WillOnce(DoAll(FillBufferFromString<0>(serialized_message.substr(
                           MessageFramer::MessageHeader::header_size(),
                           serialized_message.size() -
@@ -326,7 +326,7 @@
                       EnqueueCallback<2>(&socket_cbs)))
       .RetiresOnSaturation();
   // Read final byte.
-  EXPECT_CALL(mock_socket_, Read(NotNull(), 1, _))
+  EXPECT_CALL(mock_socket_, Read_(NotNull(), 1, _))
       .WillOnce(DoAll(FillBufferFromString<0>(serialized_message.substr(
                           serialized_message.size() - 1, 1)),
                       EnqueueCallback<2>(&socket_cbs)))
@@ -337,7 +337,7 @@
   socket_cbs.Pop(serialized_message.size() -
                  MessageFramer::MessageHeader::header_size() - 1);
   EXPECT_CALL(mock_socket_,
-              Read(NotNull(), MessageFramer::MessageHeader::header_size(), _));
+              Read_(NotNull(), MessageFramer::MessageHeader::header_size(), _));
   socket_cbs.Pop(1);
 }
 
@@ -352,7 +352,7 @@
 
   // Read bytes [0, 3].
   EXPECT_CALL(mock_socket_,
-              Read(NotNull(), MessageFramer::MessageHeader::header_size(), _))
+              Read_(NotNull(), MessageFramer::MessageHeader::header_size(), _))
       .WillOnce(DoAll(FillBufferFromString<0>(serialized_message),
                       EnqueueCallback<2>(&socket_cbs)))
       .RetiresOnSaturation();
@@ -378,16 +378,16 @@
 
   // Read bytes [0, 3].
   EXPECT_CALL(mock_socket_,
-              Read(NotNull(), MessageFramer::MessageHeader::header_size(), _))
+              Read_(NotNull(), MessageFramer::MessageHeader::header_size(), _))
       .WillOnce(DoAll(FillBufferFromString<0>(serialized_message),
                       EnqueueCallback<2>(&socket_cbs)))
       .RetiresOnSaturation();
   // Read bytes [4, n-1].
   EXPECT_CALL(mock_socket_,
-              Read(NotNull(),
-                   serialized_message.size() -
-                       MessageFramer::MessageHeader::header_size(),
-                   _))
+              Read_(NotNull(),
+                    serialized_message.size() -
+                        MessageFramer::MessageHeader::header_size(),
+                    _))
       .WillOnce(DoAll(FillBufferFromString<0>(serialized_message.substr(
                           MessageFramer::MessageHeader::header_size(),
                           serialized_message.size() -
@@ -422,16 +422,16 @@
   EXPECT_CALL(*delegate_, Start());
   // Read bytes [0, 3].
   EXPECT_CALL(mock_socket_,
-              Read(NotNull(), MessageFramer::MessageHeader::header_size(), _))
+              Read_(NotNull(), MessageFramer::MessageHeader::header_size(), _))
       .WillOnce(DoAll(FillBufferFromString<0>(serialized_message),
                       EnqueueCallback<2>(&socket_cbs)))
       .RetiresOnSaturation();
   // Read bytes [4, n].
   EXPECT_CALL(mock_socket_,
-              Read(NotNull(),
-                   serialized_message.size() -
-                       MessageFramer::MessageHeader::header_size(),
-                   _))
+              Read_(NotNull(),
+                    serialized_message.size() -
+                        MessageFramer::MessageHeader::header_size(),
+                    _))
       .WillOnce(DoAll(FillBufferFromString<0>(serialized_message.substr(
                           MessageFramer::MessageHeader::header_size(),
                           serialized_message.size() -
diff --git a/components/cast_channel/keep_alive_delegate_unittest.cc b/components/cast_channel/keep_alive_delegate_unittest.cc
index f71a77ed8..11df5242 100644
--- a/components/cast_channel/keep_alive_delegate_unittest.cc
+++ b/components/cast_channel/keep_alive_delegate_unittest.cc
@@ -119,7 +119,7 @@
 
 TEST_F(KeepAliveDelegateTest, TestPing) {
   EXPECT_CALL(*socket_.mock_transport(),
-              SendMessage(EqualsProto(CreateKeepAlivePingMessage()), _))
+              SendMessage_(EqualsProto(CreateKeepAlivePingMessage()), _))
       .WillOnce(PostCompletionCallbackTask<1>(net::OK));
   EXPECT_CALL(*inner_delegate_, Start());
   EXPECT_CALL(*ping_timer_, ResetTriggered()).Times(2);
@@ -137,7 +137,7 @@
 
 TEST_F(KeepAliveDelegateTest, TestPingFailed) {
   EXPECT_CALL(*socket_.mock_transport(),
-              SendMessage(EqualsProto(CreateKeepAlivePingMessage()), _))
+              SendMessage_(EqualsProto(CreateKeepAlivePingMessage()), _))
       .WillOnce(PostCompletionCallbackTask<1>(net::ERR_CONNECTION_RESET));
   EXPECT_CALL(*inner_delegate_, Start());
   EXPECT_CALL(*inner_delegate_, OnError(ChannelError::CAST_SOCKET_ERROR));
@@ -157,7 +157,7 @@
 
 TEST_F(KeepAliveDelegateTest, TestPingAndLivenessTimeout) {
   EXPECT_CALL(*socket_.mock_transport(),
-              SendMessage(EqualsProto(CreateKeepAlivePingMessage()), _))
+              SendMessage_(EqualsProto(CreateKeepAlivePingMessage()), _))
       .WillOnce(PostCompletionCallbackTask<1>(net::OK));
   EXPECT_CALL(*inner_delegate_, OnError(ChannelError::PING_TIMEOUT));
   EXPECT_CALL(*inner_delegate_, Start());
@@ -248,7 +248,7 @@
   keep_alive_->Start();
 
   EXPECT_CALL(*socket_.mock_transport(),
-              SendMessage(EqualsProto(CreateKeepAlivePingMessage()), _))
+              SendMessage_(EqualsProto(CreateKeepAlivePingMessage()), _))
       .WillOnce(PostCompletionCallbackTask<1>(net::OK));
   // Forward 1s, at time 1, fire ping timer.
   mock_time_task_runner->FastForwardBy(
diff --git a/components/download/internal/background_service/controller.h b/components/download/internal/background_service/controller.h
index 5136c1d..6993624f 100644
--- a/components/download/internal/background_service/controller.h
+++ b/components/download/internal/background_service/controller.h
@@ -78,7 +78,7 @@
   // Starts a download with |params|.  See DownloadParams::StartCallback and
   // DownloadParams::StartResponse for information on how a caller can determine
   // whether or not the download was successfully accepted and queued.
-  virtual void StartDownload(const DownloadParams& params) = 0;
+  virtual void StartDownload(DownloadParams params) = 0;
 
   // Pauses a download request associated with |guid| if one exists.
   virtual void PauseDownload(const std::string& guid) = 0;
diff --git a/components/download/internal/background_service/controller_impl.cc b/components/download/internal/background_service/controller_impl.cc
index b620c89d..6f7d48d 100644
--- a/components/download/internal/background_service/controller_impl.cc
+++ b/components/download/internal/background_service/controller_impl.cc
@@ -163,7 +163,7 @@
   return controller_state_;
 }
 
-void ControllerImpl::StartDownload(const DownloadParams& params) {
+void ControllerImpl::StartDownload(DownloadParams params) {
   DCHECK(controller_state_ == State::READY ||
          controller_state_ == State::UNAVAILABLE);
 
@@ -173,7 +173,7 @@
   if (controller_state_ != State::READY) {
     HandleStartDownloadResponse(params.client, params.guid,
                                 DownloadParams::StartResult::INTERNAL_ERROR,
-                                params.callback);
+                                std::move(params.callback));
     return;
   }
 
@@ -183,7 +183,7 @@
       model_->Get(params.guid) != nullptr) {
     HandleStartDownloadResponse(params.client, params.guid,
                                 DownloadParams::StartResult::UNEXPECTED_GUID,
-                                params.callback);
+                                std::move(params.callback));
     return;
   }
 
@@ -191,7 +191,7 @@
   if (!client) {
     HandleStartDownloadResponse(params.client, params.guid,
                                 DownloadParams::StartResult::UNEXPECTED_CLIENT,
-                                params.callback);
+                                std::move(params.callback));
     return;
   }
 
@@ -200,11 +200,11 @@
   if (client_count >= config_->max_scheduled_downloads) {
     HandleStartDownloadResponse(params.client, params.guid,
                                 DownloadParams::StartResult::BACKOFF,
-                                params.callback);
+                                std::move(params.callback));
     return;
   }
 
-  start_callbacks_[params.guid] = params.callback;
+  start_callbacks_[params.guid] = std::move(params.callback);
   Entry entry(params);
   entry.target_file_path = download_file_dir_.AppendASCII(params.guid);
   model_->Add(entry);
@@ -1105,9 +1105,9 @@
     DownloadClient client,
     const std::string& guid,
     DownloadParams::StartResult result) {
-  auto callback = start_callbacks_[guid];
+  DownloadParams::StartCallback callback = std::move(start_callbacks_[guid]);
   start_callbacks_.erase(guid);
-  HandleStartDownloadResponse(client, guid, result, callback);
+  HandleStartDownloadResponse(client, guid, result, std::move(callback));
 }
 
 void ControllerImpl::HandleStartDownloadResponse(
diff --git a/components/download/internal/background_service/controller_impl.h b/components/download/internal/background_service/controller_impl.h
index 6cd417e..a9cee37 100644
--- a/components/download/internal/background_service/controller_impl.h
+++ b/components/download/internal/background_service/controller_impl.h
@@ -72,7 +72,7 @@
   // Controller implementation.
   void Initialize(base::OnceClosure callback) override;
   State GetState() override;
-  void StartDownload(const DownloadParams& params) override;
+  void StartDownload(DownloadParams params) override;
   void PauseDownload(const std::string& guid) override;
   void ResumeDownload(const std::string& guid) override;
   void CancelDownload(const std::string& guid) override;
diff --git a/components/download/internal/background_service/controller_impl_unittest.cc b/components/download/internal/background_service/controller_impl_unittest.cc
index bd02cfc..fcfc0e3 100644
--- a/components/download/internal/background_service/controller_impl_unittest.cc
+++ b/components/download/internal/background_service/controller_impl_unittest.cc
@@ -267,7 +267,9 @@
   MockTaskScheduler* task_scheduler_;
   MockFileMonitor* file_monitor_;
 
-  DownloadParams::StartCallback start_callback_;
+  // A repeatable DownloadParams::StartCallback.
+  base::RepeatingCallback<void(const std::string&, DownloadParams::StartResult)>
+      start_callback_;
   bool init_callback_called_;
 
  private:
@@ -537,7 +539,7 @@
   EXPECT_CALL(*this,
               StartCallback(params.guid, DownloadParams::StartResult::ACCEPTED))
       .Times(1);
-  controller_->StartDownload(params);
+  controller_->StartDownload(std::move(params));
 
   // TODO(dtrainor): Compare the full DownloadParams with the full Entry.
   store_->TriggerUpdate(true);
@@ -569,12 +571,13 @@
 
   // Trigger the download.
   DownloadParams params = MakeDownloadParams();
+  auto guid = params.guid;
   EXPECT_CALL(*this,
               StartCallback(params.guid, DownloadParams::StartResult::BACKOFF))
       .Times(1);
-  controller_->StartDownload(params);
+  controller_->StartDownload(std::move(params));
 
-  EXPECT_FALSE(GuidInEntryList(store_->updated_entries(), params.guid));
+  EXPECT_FALSE(GuidInEntryList(store_->updated_entries(), guid));
 
   task_runner_->RunUntilIdle();
 }
@@ -600,7 +603,7 @@
       *this,
       StartCallback(params.guid, DownloadParams::StartResult::UNEXPECTED_GUID))
       .Times(1);
-  controller_->StartDownload(params);
+  controller_->StartDownload(std::move(params));
 
   task_runner_->RunUntilIdle();
 }
@@ -616,20 +619,23 @@
   driver_->MakeReady();
   task_runner_->RunUntilIdle();
 
-  // Trigger the download twice.
-  DownloadParams params = MakeDownloadParams();
+  // Trigger two download with the same guids.
+  DownloadParams params1 = MakeDownloadParams();
+  DownloadParams params2 = MakeDownloadParams();
+  auto guid = params1.guid;
+  params1.guid = params2.guid = guid;
   EXPECT_CALL(
       *this,
-      StartCallback(params.guid, DownloadParams::StartResult::UNEXPECTED_GUID))
+      StartCallback(params1.guid, DownloadParams::StartResult::UNEXPECTED_GUID))
       .Times(1);
-  EXPECT_CALL(*this,
-              StartCallback(params.guid, DownloadParams::StartResult::ACCEPTED))
+  EXPECT_CALL(
+      *this, StartCallback(params1.guid, DownloadParams::StartResult::ACCEPTED))
       .Times(1);
-  controller_->StartDownload(params);
-  controller_->StartDownload(params);
+  controller_->StartDownload(std::move(params1));
+  controller_->StartDownload(std::move(params2));
   store_->TriggerUpdate(true);
 
-  EXPECT_TRUE(GuidInEntryList(store_->updated_entries(), params.guid));
+  EXPECT_TRUE(GuidInEntryList(store_->updated_entries(), guid));
 
   task_runner_->RunUntilIdle();
 }
@@ -651,7 +657,7 @@
               StartCallback(params.guid,
                             DownloadParams::StartResult::UNEXPECTED_CLIENT))
       .Times(1);
-  controller_->StartDownload(params);
+  controller_->StartDownload(std::move(params));
 
   task_runner_->RunUntilIdle();
 }
@@ -668,13 +674,14 @@
 
   // Trigger the download.
   DownloadParams params = MakeDownloadParams();
+  auto guid = params.guid;
   EXPECT_CALL(
       *this,
       StartCallback(params.guid, DownloadParams::StartResult::CLIENT_CANCELLED))
       .Times(1);
-  controller_->StartDownload(params);
+  controller_->StartDownload(std::move(params));
 
-  controller_->CancelDownload(params.guid);
+  controller_->CancelDownload(guid);
   store_->TriggerUpdate(true);
 
   task_runner_->RunUntilIdle();
@@ -695,7 +702,7 @@
   EXPECT_CALL(*this, StartCallback(params.guid,
                                    DownloadParams::StartResult::INTERNAL_ERROR))
       .Times(1);
-  controller_->StartDownload(params);
+  controller_->StartDownload(std::move(params));
 
   store_->TriggerUpdate(false);
 
diff --git a/components/download/internal/background_service/download_service_impl.cc b/components/download/internal/background_service/download_service_impl.cc
index 22c38ee3..b039255 100644
--- a/components/download/internal/background_service/download_service_impl.cc
+++ b/components/download/internal/background_service/download_service_impl.cc
@@ -76,15 +76,15 @@
   }
 }
 
-void DownloadServiceImpl::StartDownload(const DownloadParams& download_params) {
+void DownloadServiceImpl::StartDownload(DownloadParams download_params) {
   stats::LogServiceApiAction(download_params.client,
                              stats::ServiceApiAction::START_DOWNLOAD);
   if (startup_completed_) {
-    controller_->StartDownload(download_params);
+    controller_->StartDownload(std::move(download_params));
   } else {
-    pending_actions_.push_back(
-        base::BindOnce(&Controller::StartDownload,
-                       base::Unretained(controller_.get()), download_params));
+    pending_actions_.push_back(base::BindOnce(
+        &Controller::StartDownload, base::Unretained(controller_.get()),
+        std::move(download_params)));
   }
 }
 
diff --git a/components/download/internal/background_service/download_service_impl.h b/components/download/internal/background_service/download_service_impl.h
index e604ab2..bfbaf53 100644
--- a/components/download/internal/background_service/download_service_impl.h
+++ b/components/download/internal/background_service/download_service_impl.h
@@ -38,7 +38,7 @@
                             TaskFinishedCallback callback) override;
   bool OnStopScheduledTask(DownloadTaskType task_type) override;
   ServiceStatus GetStatus() override;
-  void StartDownload(const DownloadParams& download_params) override;
+  void StartDownload(DownloadParams download_params) override;
   void PauseDownload(const std::string& guid) override;
   void ResumeDownload(const std::string& guid) override;
   void CancelDownload(const std::string& guid) override;
diff --git a/components/download/internal/background_service/download_service_impl_unittest.cc b/components/download/internal/background_service/download_service_impl_unittest.cc
index 9792b06..f976d79 100644
--- a/components/download/internal/background_service/download_service_impl_unittest.cc
+++ b/components/download/internal/background_service/download_service_impl_unittest.cc
@@ -67,13 +67,14 @@
 
 TEST_F(DownloadServiceImplTest, TestApiPassThrough) {
   DownloadParams params = test::BuildBasicDownloadParams();
+  auto guid = params.guid;
   SchedulingParams scheduling_params;
   scheduling_params.priority = SchedulingParams::Priority::UI;
 
   EXPECT_CALL(*controller_, GetOwnerOfDownload(_))
       .WillRepeatedly(Return(DownloadClient::TEST));
 
-  EXPECT_CALL(*controller_, StartDownload(_)).Times(0);
+  EXPECT_CALL(*controller_, StartDownload_(_)).Times(0);
   EXPECT_CALL(*controller_, PauseDownload(params.guid)).Times(0);
   EXPECT_CALL(*controller_, ResumeDownload(params.guid)).Times(0);
   EXPECT_CALL(*controller_, CancelDownload(params.guid)).Times(0);
@@ -82,7 +83,7 @@
   {
     base::HistogramTester histogram_tester;
 
-    service_->StartDownload(params);
+    service_->StartDownload(std::move(params));
 
     histogram_tester.ExpectBucketCount(
         "Download.Service.Request.ClientAction",
@@ -99,38 +100,28 @@
     histogram_tester.ExpectTotalCount(
         "Download.Service.Request.ClientAction.__Test__", 1);
   }
-  service_->PauseDownload(params.guid);
-  service_->ResumeDownload(params.guid);
-  service_->CancelDownload(params.guid);
-  service_->ChangeDownloadCriteria(params.guid, scheduling_params);
+  service_->PauseDownload(guid);
+  service_->ResumeDownload(guid);
+  service_->CancelDownload(guid);
+  service_->ChangeDownloadCriteria(guid, scheduling_params);
   task_runner_->RunUntilIdle();
 
   testing::Sequence seq1;
-  EXPECT_CALL(*controller_, StartDownload(_)).Times(1).InSequence(seq1);
-  EXPECT_CALL(*controller_, PauseDownload(params.guid))
-      .Times(1)
-      .InSequence(seq1);
-  EXPECT_CALL(*controller_, ResumeDownload(params.guid))
-      .Times(1)
-      .InSequence(seq1);
-  EXPECT_CALL(*controller_, CancelDownload(params.guid))
-      .Times(1)
-      .InSequence(seq1);
-  EXPECT_CALL(*controller_, ChangeDownloadCriteria(params.guid, _))
+  EXPECT_CALL(*controller_, StartDownload_(_)).Times(1).InSequence(seq1);
+  EXPECT_CALL(*controller_, PauseDownload(guid)).Times(1).InSequence(seq1);
+  EXPECT_CALL(*controller_, ResumeDownload(guid)).Times(1).InSequence(seq1);
+  EXPECT_CALL(*controller_, CancelDownload(guid)).Times(1).InSequence(seq1);
+  EXPECT_CALL(*controller_, ChangeDownloadCriteria(guid, _))
       .Times(1)
       .InSequence(seq1);
 
   controller_->TriggerInitCompleted();
   task_runner_->RunUntilIdle();
 
-  EXPECT_CALL(*controller_, PauseDownload(params.guid))
-      .Times(1)
-      .InSequence(seq1);
-  EXPECT_CALL(*controller_, ResumeDownload(params.guid))
-      .Times(1)
-      .InSequence(seq1);
-  service_->PauseDownload(params.guid);
-  service_->ResumeDownload(params.guid);
+  EXPECT_CALL(*controller_, PauseDownload(guid)).Times(1).InSequence(seq1);
+  EXPECT_CALL(*controller_, ResumeDownload(guid)).Times(1).InSequence(seq1);
+  service_->PauseDownload(guid);
+  service_->ResumeDownload(guid);
   task_runner_->RunUntilIdle();
 }
 
diff --git a/components/download/internal/background_service/test/mock_controller.h b/components/download/internal/background_service/test/mock_controller.h
index e9e616b..41c0864 100644
--- a/components/download/internal/background_service/test/mock_controller.h
+++ b/components/download/internal/background_service/test/mock_controller.h
@@ -24,7 +24,11 @@
   // Controller implementation.
   void Initialize(base::OnceClosure callback) override;
   MOCK_METHOD0(GetState, Controller::State());
-  MOCK_METHOD1(StartDownload, void(const DownloadParams&));
+  void StartDownload(DownloadParams download_params) override {
+    // Redirect as gmock can't handle move-only types.
+    StartDownload_(download_params);
+  }
+  MOCK_METHOD1(StartDownload_, void(DownloadParams&));
   MOCK_METHOD1(PauseDownload, void(const std::string&));
   MOCK_METHOD1(ResumeDownload, void(const std::string&));
   MOCK_METHOD1(CancelDownload, void(const std::string&));
diff --git a/components/download/public/background_service/download_params.cc b/components/download/public/background_service/download_params.cc
index 00a3ccb..b7c1e40 100644
--- a/components/download/public/background_service/download_params.cc
+++ b/components/download/public/background_service/download_params.cc
@@ -26,9 +26,9 @@
 RequestParams::RequestParams(const RequestParams& other) = default;
 
 DownloadParams::DownloadParams() : client(DownloadClient::INVALID) {}
-
-DownloadParams::DownloadParams(const DownloadParams& other) = default;
-
 DownloadParams::~DownloadParams() = default;
 
+DownloadParams::DownloadParams(DownloadParams&& other) = default;
+DownloadParams& DownloadParams::operator=(DownloadParams&& other) = default;
+
 }  // namespace download
diff --git a/components/download/public/background_service/download_params.h b/components/download/public/background_service/download_params.h
index b16c150d..bc9d1e5 100644
--- a/components/download/public/background_service/download_params.h
+++ b/components/download/public/background_service/download_params.h
@@ -143,12 +143,14 @@
   };
 
   using StartCallback =
-      base::RepeatingCallback<void(const std::string&, StartResult)>;
+      base::OnceCallback<void(const std::string&, StartResult)>;
 
   DownloadParams();
-  DownloadParams(const DownloadParams& other);
   ~DownloadParams();
 
+  DownloadParams(DownloadParams&& other);
+  DownloadParams& operator=(DownloadParams&& other);
+
   // The feature that is requesting this download.
   DownloadClient client;
 
diff --git a/components/download/public/background_service/download_service.h b/components/download/public/background_service/download_service.h
index 2b8fbc7..9feab88 100644
--- a/components/download/public/background_service/download_service.h
+++ b/components/download/public/background_service/download_service.h
@@ -76,7 +76,7 @@
   // Sends the download to the service.  A callback to
   // |DownloadParams::callback| will be triggered once the download has been
   // persisted and saved in the service.
-  virtual void StartDownload(const DownloadParams& download_params) = 0;
+  virtual void StartDownload(DownloadParams download_params) = 0;
 
   // Allows any feature to pause or resume downloads at will.  Paused downloads
   // will not start or stop based on scheduling criteria.  They will be
diff --git a/components/download/public/background_service/test/mock_download_service.h b/components/download/public/background_service/test/mock_download_service.h
index 5e73e5c2..ef280867 100644
--- a/components/download/public/background_service/test/mock_download_service.h
+++ b/components/download/public/background_service/test/mock_download_service.h
@@ -27,7 +27,13 @@
                void(DownloadTaskType task_type, TaskFinishedCallback callback));
   MOCK_METHOD1(OnStopScheduledTask, bool(DownloadTaskType task_type));
   MOCK_METHOD0(GetStatus, ServiceStatus());
-  MOCK_METHOD1(StartDownload, void(const DownloadParams& download_params));
+
+  void StartDownload(DownloadParams download_params) override {
+    // Redirect as gmock can't handle move-only types.
+    StartDownload_(download_params);
+  }
+
+  MOCK_METHOD1(StartDownload_, void(DownloadParams& download_params));
   MOCK_METHOD1(PauseDownload, void(const std::string& guid));
   MOCK_METHOD1(ResumeDownload, void(const std::string& guid));
   MOCK_METHOD1(CancelDownload, void(const std::string& guid));
diff --git a/components/download/public/background_service/test/test_download_service.cc b/components/download/public/background_service/test/test_download_service.cc
index ed58d88..7d31355 100644
--- a/components/download/public/background_service/test/test_download_service.cc
+++ b/components/download/public/background_service/test/test_download_service.cc
@@ -5,6 +5,7 @@
 #include "components/download/public/background_service/test/test_download_service.h"
 
 #include "base/bind.h"
+#include "base/no_destructor.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/download/public/background_service/client.h"
 #include "components/download/public/background_service/download_metadata.h"
@@ -65,16 +66,17 @@
                    : DownloadService::ServiceStatus::STARTING_UP;
 }
 
-void TestDownloadService::StartDownload(const DownloadParams& params) {
+void TestDownloadService::StartDownload(DownloadParams params) {
   if (!failed_download_id_.empty() && fail_at_start_) {
-    params.callback.Run(params.guid,
-                        DownloadParams::StartResult::UNEXPECTED_GUID);
+    std::move(params.callback)
+        .Run(params.guid, DownloadParams::StartResult::UNEXPECTED_GUID);
     return;
   }
 
   // The download will be accepted and queued even if the service is not ready.
-  params.callback.Run(params.guid, DownloadParams::StartResult::ACCEPTED);
-  downloads_.push_back(params);
+  std::move(params.callback)
+      .Run(params.guid, DownloadParams::StartResult::ACCEPTED);
+  downloads_.emplace_back(std::move(params));
 
   if (!is_ready_)
     return;
@@ -90,7 +92,7 @@
 
 void TestDownloadService::CancelDownload(const std::string& guid) {
   for (auto iter = downloads_.begin(); iter != downloads_.end(); ++iter) {
-    if (iter->guid == guid) {
+    if (iter->value().guid == guid) {
       downloads_.erase(iter);
       return;
     }
@@ -105,13 +107,14 @@
   return logger_.get();
 }
 
-base::Optional<DownloadParams> TestDownloadService::GetDownload(
+const base::Optional<DownloadParams>& TestDownloadService::GetDownload(
     const std::string& guid) const {
   for (const auto& download : downloads_) {
-    if (download.guid == guid)
-      return base::Optional<DownloadParams>(download);
+    if (download.value().guid == guid)
+      return download;
   }
-  return base::Optional<DownloadParams>();
+  static base::NoDestructor<base::Optional<DownloadParams>> none;
+  return *none;
 }
 
 void TestDownloadService::SetFailedDownload(
@@ -136,7 +139,7 @@
   if (!is_ready_ || downloads_.empty())
     return;
 
-  DownloadParams params = downloads_.front();
+  DownloadParams params = std::move(downloads_.front().value());
   downloads_.pop_front();
 
   if (!failed_download_id_.empty() && params.guid == failed_download_id_) {
diff --git a/components/download/public/background_service/test/test_download_service.h b/components/download/public/background_service/test/test_download_service.h
index 5999db5..d6db5ad 100644
--- a/components/download/public/background_service/test/test_download_service.h
+++ b/components/download/public/background_service/test/test_download_service.h
@@ -32,7 +32,7 @@
                             TaskFinishedCallback callback) override;
   bool OnStopScheduledTask(DownloadTaskType task_type) override;
   DownloadService::ServiceStatus GetStatus() override;
-  void StartDownload(const DownloadParams& download_params) override;
+  void StartDownload(DownloadParams download_params) override;
   void PauseDownload(const std::string& guid) override;
   void ResumeDownload(const std::string& guid) override;
   void CancelDownload(const std::string& guid) override;
@@ -40,7 +40,8 @@
                               const SchedulingParams& params) override;
   Logger* GetLogger() override;
 
-  base::Optional<DownloadParams> GetDownload(const std::string& guid) const;
+  const base::Optional<DownloadParams>& GetDownload(
+      const std::string& guid) const;
 
   // Set failed_download_id and fail_at_start.
   void SetFailedDownload(const std::string& failed_download_id,
@@ -76,7 +77,7 @@
 
   Client* client_;
 
-  std::list<DownloadParams> downloads_;
+  std::list<base::Optional<DownloadParams>> downloads_;
 
   DISALLOW_COPY_AND_ASSIGN(TestDownloadService);
 };
diff --git a/components/favicon/core/history_ui_favicon_request_handler_impl.cc b/components/favicon/core/history_ui_favicon_request_handler_impl.cc
index 0f7b57b..05940d0 100644
--- a/components/favicon/core/history_ui_favicon_request_handler_impl.cc
+++ b/components/favicon/core/history_ui_favicon_request_handler_impl.cc
@@ -131,16 +131,15 @@
   }
 
   if (can_send_history_data_getter_.Run()) {
-    // base::AdaptCallbackForRepeating() is necessary here because
+    // base::SplitOnceCallback() is necessary here because
     // |response_callback| is needed to build both the empty response and local
     // lookup callbacks. This is safe because only one of the two is called.
-    base::RepeatingCallback<void(const favicon_base::FaviconRawBitmapResult&)>
-        repeating_response_callback =
-            base::AdaptCallbackForRepeating(std::move(response_callback));
+    auto split_response_callback =
+        base::SplitOnceCallback(std::move(response_callback));
     RequestFromGoogleServer(
         page_url,
         /*empty_response_callback=*/
-        base::BindOnce(repeating_response_callback,
+        base::BindOnce(std::move(split_response_callback.first),
                        favicon_base::FaviconRawBitmapResult()),
         /*local_lookup_callback=*/
         base::BindOnce(
@@ -149,7 +148,8 @@
             // doesn't execute the callback if |this| is deleted.
             base::Unretained(favicon_service_), page_url,
             GetIconTypesForLocalQuery(), desired_size_in_pixel, kFallbackToHost,
-            repeating_response_callback, &cancelable_task_tracker_),
+            std::move(split_response_callback.second),
+            &cancelable_task_tracker_),
         origin_for_uma, request_start_time_for_uma);
     return;
   }
@@ -179,16 +179,15 @@
   }
 
   if (can_send_history_data_getter_.Run()) {
-    // base::AdaptCallbackForRepeating() is necessary here because
+    // base::SplitOnceCallback() is necessary here because
     // |response_callback| is needed to build both the empty response and local
     // lookup callbacks. This is safe because only one of the two is called.
-    base::RepeatingCallback<void(const favicon_base::FaviconImageResult&)>
-        repeating_response_callback =
-            base::AdaptCallbackForRepeating(std::move(response_callback));
+    auto split_response_callback =
+        base::SplitOnceCallback(std::move(response_callback));
     RequestFromGoogleServer(
         page_url,
         /*empty_response_callback=*/
-        base::BindOnce(repeating_response_callback,
+        base::BindOnce(std::move(split_response_callback.first),
                        favicon_base::FaviconImageResult()),
         /*local_lookup_callback=*/
         base::BindOnce(
@@ -196,7 +195,8 @@
             // base::Unretained() is safe here as RequestFromGoogleServer()
             // doesn't execture the callback if |this| is deleted.
             base::Unretained(favicon_service_), page_url,
-            repeating_response_callback, &cancelable_task_tracker_),
+            std::move(split_response_callback.second),
+            &cancelable_task_tracker_),
         origin_for_uma, request_start_time_for_uma);
     return;
   }
diff --git a/components/federated_learning/features/features.cc b/components/federated_learning/features/features.cc
index 16d550c..9647df0 100644
--- a/components/federated_learning/features/features.cc
+++ b/components/federated_learning/features/features.cc
@@ -8,6 +8,12 @@
 
 namespace federated_learning {
 
+// If enabled, the check for whether the IP address is publicly routable will be
+// bypassed when determining the eligibility for a page to be included in floc
+// computation. This is useful for developers to test FLoC in local environment.
+const base::Feature kFlocBypassIPIsPubliclyRoutableCheck{
+    "FlocBypassIPIsPubliclyRoutableCheck", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enables or disables the FlocIdComputed event logging, which happens when a
 // floc id is first computed for a browsing session or is refreshed due to a
 // long period of time has passed since the last computation.
diff --git a/components/federated_learning/features/features.h b/components/federated_learning/features/features.h
index 39f0eb0..2de1234c 100644
--- a/components/federated_learning/features/features.h
+++ b/components/federated_learning/features/features.h
@@ -10,6 +10,7 @@
 
 namespace federated_learning {
 
+extern const base::Feature kFlocBypassIPIsPubliclyRoutableCheck;
 extern const base::Feature kFlocIdComputedEventLogging;
 extern const base::Feature
     kFlocPagesWithAdResourcesDefaultIncludedInFlocComputation;
diff --git a/components/feed/core/v2/BUILD.gn b/components/feed/core/v2/BUILD.gn
index 0203c3c..72c68e3 100644
--- a/components/feed/core/v2/BUILD.gn
+++ b/components/feed/core/v2/BUILD.gn
@@ -216,6 +216,17 @@
   ]
 }
 
+source_set("feed_core_stubs") {
+  testonly = true
+  sources = [
+    "public/test/stub_feed_api.cc",
+    "public/test/stub_feed_api.h",
+    "public/test/stub_web_feed_subscriptions.cc",
+    "public/test/stub_web_feed_subscriptions.h",
+  ]
+  deps = [ ":feed_core_v2" ]
+}
+
 # Tests for :feed_core_base that can be compiled in iOS.
 # This source set is added as a dep of :core_unit_tests.
 source_set("feed_core_base_unit_tests") {
diff --git a/components/feed/core/v2/api_test/feed_api_notice_card_unittest.cc b/components/feed/core/v2/api_test/feed_api_notice_card_unittest.cc
index e4465e5..7b020b2 100644
--- a/components/feed/core/v2/api_test/feed_api_notice_card_unittest.cc
+++ b/components/feed/core/v2/api_test/feed_api_notice_card_unittest.cc
@@ -47,7 +47,7 @@
                              slice_id);
   stream_->ReportSliceViewed(surface.GetSurfaceId(), surface.GetStreamType(),
                              slice_id);
-  stream_->ReportOpenAction(surface.GetStreamType(), slice_id);
+  stream_->ReportOpenAction(GURL(), surface.GetStreamType(), slice_id);
 
   response_translator_.InjectResponse(MakeTypicalInitialModelState());
   stream_->UnloadModel(surface.GetStreamType());
diff --git a/components/feed/core/v2/api_test/feed_api_stream_unittest.cc b/components/feed/core/v2/api_test/feed_api_stream_unittest.cc
index 944d913..9bbdf59 100644
--- a/components/feed/core/v2/api_test/feed_api_stream_unittest.cc
+++ b/components/feed/core/v2/api_test/feed_api_stream_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "base/callback_helpers.h"
 #include "base/feature_list.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/metrics/user_action_tester.h"
@@ -848,7 +849,7 @@
   base::UserActionTester user_actions;
 
   stream_->ReportOpenInNewTabAction(
-      surface.GetStreamType(),
+      GURL(), surface.GetStreamType(),
       surface.initial_state->updated_slices(1).slice().slice_id());
 
   EXPECT_EQ(1, user_actions.GetActionCount(
@@ -2175,6 +2176,34 @@
   ASSERT_EQ(2, network_.send_query_call_count);
 }
 
+TEST_F(FeedApiTest, WasUrlRecentlyNavigatedFromFeed) {
+  const GURL url1("https://someurl1");
+  const GURL url2("https://someurl2");
+  EXPECT_FALSE(stream_->WasUrlRecentlyNavigatedFromFeed(url1));
+  EXPECT_FALSE(stream_->WasUrlRecentlyNavigatedFromFeed(url2));
+
+  stream_->ReportOpenAction(url1, kForYouStream, "slice");
+  stream_->ReportOpenInNewTabAction(url2, kForYouStream, "slice");
+
+  EXPECT_TRUE(stream_->WasUrlRecentlyNavigatedFromFeed(url1));
+  EXPECT_TRUE(stream_->WasUrlRecentlyNavigatedFromFeed(url2));
+}
+
+// After 10 URLs are navigated, they are forgotten in FIFO order.
+TEST_F(FeedApiTest, WasUrlRecentlyNavigatedFromFeedMaxHistory) {
+  std::vector<GURL> urls;
+  for (int i = 0; i < 11; ++i)
+    urls.emplace_back("https://someurl" + base::NumberToString(i));
+
+  for (const GURL& url : urls)
+    stream_->ReportOpenAction(url, kForYouStream, "slice");
+
+  EXPECT_FALSE(stream_->WasUrlRecentlyNavigatedFromFeed(urls[0]));
+  for (size_t i = 1; i < urls.size(); ++i) {
+    EXPECT_TRUE(stream_->WasUrlRecentlyNavigatedFromFeed(urls[i]));
+  }
+}
+
 // Keep instantiations at the bottom.
 INSTANTIATE_TEST_SUITE_P(FeedApiTest,
                          FeedStreamTestForAllStreamTypes,
diff --git a/components/feed/core/v2/feed_stream.cc b/components/feed/core/v2/feed_stream.cc
index 507d15dd..b71c539 100644
--- a/components/feed/core/v2/feed_stream.cc
+++ b/components/feed/core/v2/feed_stream.cc
@@ -53,6 +53,7 @@
 
 namespace feed {
 namespace {
+constexpr size_t kMaxRecentFeedNavigations = 10;
 
 void UpdateDebugStreamData(
     const UploadActionsTask::Result& upload_actions_result,
@@ -532,6 +533,12 @@
   PopulateDebugStreamData(result, *profile_prefs_);
 }
 
+bool FeedStream::WasUrlRecentlyNavigatedFromFeed(const GURL& url) {
+  return std::find(recent_feed_navigations_.begin(),
+                   recent_feed_navigations_.end(),
+                   url) != recent_feed_navigations_.end();
+}
+
 DebugStreamData FeedStream::GetDebugStreamData() {
   return ::feed::prefs::GetDebugStreamData(*profile_prefs_);
 }
@@ -982,8 +989,13 @@
   }
 }
 
-void FeedStream::ReportOpenAction(const StreamType& stream_type,
+void FeedStream::ReportOpenAction(const GURL& url,
+                                  const StreamType& stream_type,
                                   const std::string& slice_id) {
+  recent_feed_navigations_.insert(recent_feed_navigations_.begin(), url);
+  recent_feed_navigations_.resize(
+      std::min(kMaxRecentFeedNavigations, recent_feed_navigations_.size()));
+
   Stream& stream = GetStream(stream_type);
 
   int index = stream.surface_updater->GetSliceIndexFromSliceId(slice_id);
@@ -999,8 +1011,13 @@
 void FeedStream::ReportOpenVisitComplete(base::TimeDelta visit_time) {
   metrics_reporter_->OpenVisitComplete(visit_time);
 }
-void FeedStream::ReportOpenInNewTabAction(const StreamType& stream_type,
+void FeedStream::ReportOpenInNewTabAction(const GURL& url,
+                                          const StreamType& stream_type,
                                           const std::string& slice_id) {
+  recent_feed_navigations_.insert(recent_feed_navigations_.begin(), url);
+  recent_feed_navigations_.resize(
+      std::min(kMaxRecentFeedNavigations, recent_feed_navigations_.size()));
+
   Stream& stream = GetStream(stream_type);
   int index = stream.surface_updater->GetSliceIndexFromSliceId(slice_id);
   if (index < 0)
diff --git a/components/feed/core/v2/feed_stream.h b/components/feed/core/v2/feed_stream.h
index bdee17d..81d013e 100644
--- a/components/feed/core/v2/feed_stream.h
+++ b/components/feed/core/v2/feed_stream.h
@@ -9,6 +9,7 @@
 #include <string>
 #include <vector>
 
+#include "base/containers/circular_deque.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/observer_list.h"
 #include "base/sequenced_task_runner.h"
@@ -121,6 +122,7 @@
                              EphemeralChangeId id) override;
   void ProcessThereAndBackAgain(base::StringPiece data) override;
   void ProcessViewAction(base::StringPiece data) override;
+  bool WasUrlRecentlyNavigatedFromFeed(const GURL& url) override;
   DebugStreamData GetDebugStreamData() override;
   void ForceRefreshForDebugging() override;
   std::string DumpStateForDebugging() override;
@@ -132,10 +134,12 @@
                          const std::string& slice_id) override;
   void ReportFeedViewed(SurfaceId surface_id) override;
   void ReportPageLoaded() override;
-  void ReportOpenAction(const StreamType& stream_type,
+  void ReportOpenAction(const GURL& url,
+                        const StreamType& stream_type,
                         const std::string& slice_id) override;
   void ReportOpenVisitComplete(base::TimeDelta visit_time) override;
-  void ReportOpenInNewTabAction(const StreamType& stream_type,
+  void ReportOpenInNewTabAction(const GURL& url,
+                                const StreamType& stream_type,
                                 const std::string& slice_id) override;
   void ReportStreamScrolled(const StreamType& stream_type,
                             int distance_dp) override;
@@ -380,6 +384,8 @@
 
   bool clear_all_in_progress_ = false;
 
+  std::vector<GURL> recent_feed_navigations_;
+
   base::WeakPtrFactory<FeedStream> weak_ptr_factory_{this};
 };
 
diff --git a/components/feed/core/v2/public/feed_api.h b/components/feed/core/v2/public/feed_api.h
index 52b2631..981df1c 100644
--- a/components/feed/core/v2/public/feed_api.h
+++ b/components/feed/core/v2/public/feed_api.h
@@ -125,8 +125,12 @@
   //|feedwire::FeedAction| message.
   virtual void ProcessViewAction(base::StringPiece data) = 0;
 
-  // User interaction reporting. These should have no side-effects other than
-  // reporting metrics.
+  // Returns whether `url` is a suggested Feed URLs, recently
+  // navigated to by the user.
+  virtual bool WasUrlRecentlyNavigatedFromFeed(const GURL& url) = 0;
+
+  // User interaction reporting. Unless otherwise documented, these have no
+  // side-effects other than reporting metrics.
 
   // A slice was viewed (2/3rds of it is in the viewport). Should be called
   // once for each viewed slice in the stream.
@@ -139,14 +143,18 @@
   // A web page was loaded in response to opening a link from the Feed.
   virtual void ReportPageLoaded() = 0;
   // The user triggered the default open action, usually by tapping the card.
-  virtual void ReportOpenAction(const StreamType& stream_type,
+  // Remembers the URL for later calls to `WasUrlRecentlyNavigatedFromFeed()`.
+  virtual void ReportOpenAction(const GURL& url,
+                                const StreamType& stream_type,
                                 const std::string& slice_id) = 0;
   // The user triggered an open action, visited a web page, and then navigated
   // away or backgrouded the tab. |visit_time| is a measure of how long the
   // visited page was foregrounded.
   virtual void ReportOpenVisitComplete(base::TimeDelta visit_time) = 0;
   // The user triggered the 'open in new tab' action.
-  virtual void ReportOpenInNewTabAction(const StreamType& stream_type,
+  // Remembers the URL for later calls to `WasUrlRecentlyNavigatedFromFeed()`.
+  virtual void ReportOpenInNewTabAction(const GURL& url,
+                                        const StreamType& stream_type,
                                         const std::string& slice_id) = 0;
   // The user scrolled the feed by |distance_dp| and then stopped.
   virtual void ReportStreamScrolled(const StreamType& stream_type,
diff --git a/components/feed/core/v2/public/feed_service.cc b/components/feed/core/v2/public/feed_service.cc
index 40f8186..d0c01ef 100644
--- a/components/feed/core/v2/public/feed_service.cc
+++ b/components/feed/core/v2/public/feed_service.cc
@@ -8,6 +8,7 @@
 
 #include "base/command_line.h"
 #include "base/hash/hash.h"
+#include "base/memory/ptr_util.h"
 #include "base/rand_util.h"
 #include "base/scoped_observation.h"
 #include "base/strings/strcat.h"
@@ -233,6 +234,7 @@
       stream_delegate_.get(), profile_prefs, feed_network_.get(),
       image_fetcher_.get(), store_.get(), persistent_key_value_store_.get(),
       chrome_info);
+  api_ = stream_.get();
 
   history_observer_ = std::make_unique<HistoryObserverImpl>(
       history_service, static_cast<FeedStream*>(stream_.get()),
@@ -252,10 +254,19 @@
 #endif
 }
 
+FeedService::FeedService() = default;
+
+// static
+std::unique_ptr<FeedService> FeedService::CreateForTesting(FeedApi* api) {
+  auto result = base::WrapUnique(new FeedService());
+  result->api_ = api;
+  return result;
+}
+
 FeedService::~FeedService() = default;
 
 FeedApi* FeedService::GetStream() {
-  return stream_.get();
+  return api_;
 }
 
 void FeedService::ClearCachedData() {
diff --git a/components/feed/core/v2/public/feed_service.h b/components/feed/core/v2/public/feed_service.h
index d72ea94..e0c79a3 100644
--- a/components/feed/core/v2/public/feed_service.h
+++ b/components/feed/core/v2/public/feed_service.h
@@ -93,6 +93,7 @@
       scoped_refptr<base::SequencedTaskRunner> background_task_runner,
       const std::string& api_key,
       const ChromeInfo& chrome_info);
+  static std::unique_ptr<FeedService> CreateForTesting(FeedApi* api);
   ~FeedService() override;
   FeedService(const FeedService&) = delete;
   FeedService& operator=(const FeedService&) = delete;
@@ -120,6 +121,8 @@
   class NetworkDelegateImpl;
   class HistoryObserverImpl;
   class IdentityManagerObserverImpl;
+
+  FeedService();
 #if defined(OS_ANDROID)
   void OnApplicationStateChange(base::android::ApplicationState state);
 #endif
@@ -143,6 +146,7 @@
       application_status_listener_;
 #endif
   std::unique_ptr<FeedStream> stream_;
+  FeedApi* api_;  // Points to `stream_`, overridden for testing.
 };
 
 }  // namespace feed
diff --git a/components/feed/core/v2/public/test/stub_feed_api.cc b/components/feed/core/v2/public/test/stub_feed_api.cc
new file mode 100644
index 0000000..619abdf
--- /dev/null
+++ b/components/feed/core/v2/public/test/stub_feed_api.cc
@@ -0,0 +1,61 @@
+// 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 "components/feed/core/v2/public/test/stub_feed_api.h"
+
+namespace feed {
+
+WebFeedSubscriptions& StubFeedApi::subscriptions() {
+  return web_feed_subscriptions_;
+}
+bool StubFeedApi::IsArticlesListVisible() {
+  return {};
+}
+bool StubFeedApi::IsActivityLoggingEnabled(
+    const StreamType& stream_type) const {
+  return {};
+}
+std::string StubFeedApi::GetClientInstanceId() const {
+  return {};
+}
+std::string StubFeedApi::GetSessionId() const {
+  return {};
+}
+ImageFetchId StubFeedApi::FetchImage(
+    const GURL& url,
+    base::OnceCallback<void(NetworkResponse)> callback) {
+  return {};
+}
+PersistentKeyValueStore* StubFeedApi::GetPersistentKeyValueStore() {
+  return {};
+}
+EphemeralChangeId StubFeedApi::CreateEphemeralChange(
+    const StreamType& stream_type,
+    std::vector<feedstore::DataOperation> operations) {
+  return {};
+}
+EphemeralChangeId StubFeedApi::CreateEphemeralChangeFromPackedData(
+    const StreamType& stream_type,
+    base::StringPiece data) {
+  return {};
+}
+bool StubFeedApi::CommitEphemeralChange(const StreamType& stream_type,
+                                        EphemeralChangeId id) {
+  return {};
+}
+bool StubFeedApi::RejectEphemeralChange(const StreamType& stream_type,
+                                        EphemeralChangeId id) {
+  return {};
+}
+bool StubFeedApi::WasUrlRecentlyNavigatedFromFeed(const GURL& url) {
+  return {};
+}
+DebugStreamData StubFeedApi::GetDebugStreamData() {
+  return {};
+}
+std::string StubFeedApi::DumpStateForDebugging() {
+  return {};
+}
+
+}  // namespace feed
diff --git a/components/feed/core/v2/public/test/stub_feed_api.h b/components/feed/core/v2/public/test/stub_feed_api.h
new file mode 100644
index 0000000..ba9df90
--- /dev/null
+++ b/components/feed/core/v2/public/test/stub_feed_api.h
@@ -0,0 +1,80 @@
+// 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 COMPONENTS_FEED_CORE_V2_PUBLIC_TEST_STUB_FEED_API_H_
+#define COMPONENTS_FEED_CORE_V2_PUBLIC_TEST_STUB_FEED_API_H_
+
+#include "components/feed/core/proto/v2/store.pb.h"
+#include "components/feed/core/v2/public/feed_api.h"
+#include "components/feed/core/v2/public/test/stub_web_feed_subscriptions.h"
+
+namespace feed {
+
+class StubFeedApi : public FeedApi {
+ public:
+  WebFeedSubscriptions& subscriptions() override;
+  void AttachSurface(FeedStreamSurface*) override {}
+  void DetachSurface(FeedStreamSurface*) override {}
+  void AddUnreadContentObserver(const StreamType& stream_type,
+                                UnreadContentObserver* observer) override {}
+  void RemoveUnreadContentObserver(const StreamType& stream_type,
+                                   UnreadContentObserver* observer) override {}
+  bool IsArticlesListVisible() override;
+  bool IsActivityLoggingEnabled(const StreamType& stream_type) const override;
+  std::string GetClientInstanceId() const override;
+  std::string GetSessionId() const override;
+  void ExecuteRefreshTask(RefreshTaskId task_id) override {}
+  void LoadMore(const FeedStreamSurface& surface,
+                base::OnceCallback<void(bool)> callback) override {}
+  ImageFetchId FetchImage(
+      const GURL& url,
+      base::OnceCallback<void(NetworkResponse)> callback) override;
+  void CancelImageFetch(ImageFetchId id) override {}
+  PersistentKeyValueStore* GetPersistentKeyValueStore() override;
+  void ExecuteOperations(
+      const StreamType& stream_type,
+      std::vector<feedstore::DataOperation> operations) override {}
+  EphemeralChangeId CreateEphemeralChange(
+      const StreamType& stream_type,
+      std::vector<feedstore::DataOperation> operations) override;
+  EphemeralChangeId CreateEphemeralChangeFromPackedData(
+      const StreamType& stream_type,
+      base::StringPiece data) override;
+  bool CommitEphemeralChange(const StreamType& stream_type,
+                             EphemeralChangeId id) override;
+  bool RejectEphemeralChange(const StreamType& stream_type,
+                             EphemeralChangeId id) override;
+  void ProcessThereAndBackAgain(base::StringPiece data) override {}
+  void ProcessViewAction(base::StringPiece data) override {}
+  bool WasUrlRecentlyNavigatedFromFeed(const GURL& url) override;
+  void ReportSliceViewed(SurfaceId surface_id,
+                         const StreamType& stream_type,
+                         const std::string& slice_id) override {}
+  void ReportFeedViewed(SurfaceId surface_id) override {}
+  void ReportPageLoaded() override {}
+  void ReportOpenAction(const GURL& url,
+                        const StreamType& stream_type,
+                        const std::string& slice_id) override {}
+  void ReportOpenVisitComplete(base::TimeDelta visit_time) override {}
+  void ReportOpenInNewTabAction(const GURL& url,
+                                const StreamType& stream_type,
+                                const std::string& slice_id) override {}
+  void ReportStreamScrolled(const StreamType& stream_type,
+                            int distance_dp) override {}
+  void ReportStreamScrollStart() override {}
+  void ReportOtherUserAction(const StreamType& stream_type,
+                             FeedUserActionType action_type) override {}
+  DebugStreamData GetDebugStreamData() override;
+  void ForceRefreshForDebugging() override {}
+  std::string DumpStateForDebugging() override;
+  void SetForcedStreamUpdateForDebugging(
+      const feedui::StreamUpdate& stream_update) override {}
+
+ private:
+  StubWebFeedSubscriptions web_feed_subscriptions_;
+};
+
+}  // namespace feed
+
+#endif  // COMPONENTS_FEED_CORE_V2_PUBLIC_TEST_STUB_FEED_API_H_
diff --git a/components/feed/core/v2/public/test/stub_web_feed_subscriptions.cc b/components/feed/core/v2/public/test/stub_web_feed_subscriptions.cc
new file mode 100644
index 0000000..84c67a0
--- /dev/null
+++ b/components/feed/core/v2/public/test/stub_web_feed_subscriptions.cc
@@ -0,0 +1,13 @@
+// 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 "components/feed/core/v2/public/test/stub_web_feed_subscriptions.h"
+
+namespace feed {
+
+bool StubWebFeedSubscriptions::IsWebFeedSubscriber() {
+  return {};
+}
+
+}  // namespace feed
diff --git a/components/feed/core/v2/public/test/stub_web_feed_subscriptions.h b/components/feed/core/v2/public/test/stub_web_feed_subscriptions.h
new file mode 100644
index 0000000..e9b5133d
--- /dev/null
+++ b/components/feed/core/v2/public/test/stub_web_feed_subscriptions.h
@@ -0,0 +1,40 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_FEED_CORE_V2_PUBLIC_TEST_STUB_WEB_FEED_SUBSCRIPTIONS_H_
+#define COMPONENTS_FEED_CORE_V2_PUBLIC_TEST_STUB_WEB_FEED_SUBSCRIPTIONS_H_
+
+#include "components/feed/core/v2/public/types.h"
+#include "components/feed/core/v2/public/web_feed_subscriptions.h"
+
+namespace feed {
+
+class StubWebFeedSubscriptions : public WebFeedSubscriptions {
+ public:
+  void FollowWebFeed(
+      const WebFeedPageInformation& page_info,
+      base::OnceCallback<void(FollowWebFeedResult)> callback) override {}
+  void FollowWebFeed(
+      const std::string& web_feed_id,
+      base::OnceCallback<void(FollowWebFeedResult)> callback) override {}
+  void UnfollowWebFeed(
+      const std::string& web_feed_id,
+      base::OnceCallback<void(UnfollowWebFeedResult)> callback) override {}
+  void FindWebFeedInfoForPage(
+      const WebFeedPageInformation& page_info,
+      base::OnceCallback<void(WebFeedMetadata)> callback) override {}
+  void FindWebFeedInfoForWebFeedId(
+      const std::string& web_feed_id,
+      base::OnceCallback<void(WebFeedMetadata)> callback) override {}
+  void GetAllSubscriptions(
+      base::OnceCallback<void(std::vector<WebFeedMetadata>)> callback)
+      override {}
+  void RefreshSubscriptions(
+      base::OnceCallback<void(RefreshResult)> callback) override {}
+  bool IsWebFeedSubscriber() override;
+};
+
+}  // namespace feed
+
+#endif  // COMPONENTS_FEED_CORE_V2_PUBLIC_TEST_STUB_WEB_FEED_SUBSCRIPTIONS_H_
diff --git a/components/gcm_driver/crypto/gcm_key_store.cc b/components/gcm_driver/crypto/gcm_key_store.cc
index f279ce2..9cb0146 100644
--- a/components/gcm_driver/crypto/gcm_key_store.cc
+++ b/components/gcm_driver/crypto/gcm_key_store.cc
@@ -281,8 +281,7 @@
     return;
   }
 
-  delayed_task_controller_.AddTask(
-      base::AdaptCallbackForRepeating(std::move(done_closure)));
+  delayed_task_controller_.AddTask(std::move(done_closure));
   if (state_ == State::INITIALIZING)
     return;
 
diff --git a/components/guest_view/browser/guest_view_base.cc b/components/guest_view/browser/guest_view_base.cc
index 94951a8..6716d5e 100644
--- a/components/guest_view/browser/guest_view_base.cc
+++ b/components/guest_view/browser/guest_view_base.cc
@@ -43,15 +43,15 @@
 
 }  // namespace
 
-SetSizeParams::SetSizeParams() {
-}
-SetSizeParams::~SetSizeParams() {
-}
+SetSizeParams::SetSizeParams() = default;
+SetSizeParams::~SetSizeParams() = default;
 
+// TODO(832879): It would be better to have proper ownership semantics than
+// manually destroying guests and their WebContents.
+//
 // This observer ensures that the GuestViewBase destroys itself when its
 // embedder goes away. It also tracks when the embedder's fullscreen is
-// toggled or when its page scale factor changes so the guest can change
-// itself accordingly.
+// toggled so the guest can change itself accordingly.
 class GuestViewBase::OwnerContentsObserver : public WebContentsObserver {
  public:
   OwnerContentsObserver(GuestViewBase* guest,
@@ -61,7 +61,7 @@
         destroyed_(false),
         guest_(guest) {}
 
-  ~OwnerContentsObserver() override {}
+  ~OwnerContentsObserver() override = default;
 
   // WebContentsObserver implementation.
   void WebContentsDestroyed() override {
@@ -71,6 +71,8 @@
 
   void DidFinishNavigation(
       content::NavigationHandle* navigation_handle) override {
+    // TODO(1206312, 1205920): It is incorrect to assume that a navigation will
+    // destroy the embedder.
     // If the embedder navigates to a different page then destroy the guest.
     if (!navigation_handle->IsInMainFrame() ||
         !navigation_handle->HasCommitted() ||
@@ -149,7 +151,7 @@
       : WebContentsObserver(guest->GetOpener()->web_contents()),
         guest_(guest) {}
 
-  ~OpenerLifetimeObserver() override {}
+  ~OpenerLifetimeObserver() override = default;
 
   // WebContentsObserver implementation.
   void WebContentsDestroyed() override {
diff --git a/components/guest_view/browser/guest_view_base.h b/components/guest_view/browser/guest_view_base.h
index b879bf1..9a6c512 100644
--- a/components/guest_view/browser/guest_view_base.h
+++ b/components/guest_view/browser/guest_view_base.h
@@ -449,8 +449,8 @@
   std::unique_ptr<base::DictionaryValue> attach_params_;
 
   // This observer ensures that this guest self-destructs if the embedder goes
-  // away. It also tracks when the embedder's fullscreen is toggled or when its
-  // page scale factor changes so the guest can change itself accordingly.
+  // away. It also tracks when the embedder's fullscreen is toggled so the guest
+  // can change itself accordingly.
   std::unique_ptr<OwnerContentsObserver> owner_contents_observer_;
 
   // This observer ensures that if the guest is unattached and its opener goes
diff --git a/components/heap_profiling/multi_process/supervisor.cc b/components/heap_profiling/multi_process/supervisor.cc
index 71015b3..68414503d5 100644
--- a/components/heap_profiling/multi_process/supervisor.cc
+++ b/components/heap_profiling/multi_process/supervisor.cc
@@ -166,18 +166,15 @@
                 base::trace_event::MemoryDumpType::EXPLICITLY_TRIGGERED,
                 base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND,
                 base::trace_event::MemoryDumpDeterminism::NONE,
-                base::AdaptCallbackForRepeating(
-                    std::move(finished_dump_callback)));
+                std::move(finished_dump_callback));
       },
       std::move(finished_dump_callback));
 
   // The only reason this should return false is if tracing is already enabled,
   // which we've already checked.
-  // Use AdaptCallbackForRepeating since the argument passed to StartTracing()
-  // is intended to be a OnceCallback, but the code has not yet been migrated.
   bool result = content::TracingController::GetInstance()->StartTracing(
       GetBackgroundTracingConfig(anonymize),
-      base::AdaptCallbackForRepeating(std::move(trigger_memory_dump_callback)));
+      std::move(trigger_memory_dump_callback));
   DCHECK(result);
 }
 
diff --git a/components/language/android/BUILD.gn b/components/language/android/BUILD.gn
index 50f6042e..703069a 100644
--- a/components/language/android/BUILD.gn
+++ b/components/language/android/BUILD.gn
@@ -30,6 +30,27 @@
     "java/src/org/chromium/components/language/GeoLanguageProviderBridge.java",
   ]
 
-  deps = [ "//base:base_java" ]
+  deps = [
+    "//base:base_java",
+    "//third_party/androidx:androidx_annotation_annotation_java",
+  ]
   annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
 }
+
+android_library("language_bridge_javatests") {
+  testonly = true
+
+  sources = [ "java/src/org/chromium/components/language/AndroidLanguageMetricsBridgeTest.java" ]
+  deps = [
+    ":language_bridge_java",
+    "//base:base_java",
+    "//base:base_java_test_support",
+    "//chrome/browser/flags:java",
+    "//chrome/test/android:chrome_java_test_support",
+    "//content/public/test/android:content_java_test_support",
+    "//third_party/android_support_test_runner:rules_java",
+    "//third_party/androidx:androidx_annotation_annotation_java",
+    "//third_party/androidx:androidx_test_runner_java",
+    "//third_party/junit",
+  ]
+}
diff --git a/components/language/android/DEPS b/components/language/android/DEPS
index 771bfcf2..e1d0dc5 100644
--- a/components/language/android/DEPS
+++ b/components/language/android/DEPS
@@ -1,3 +1,10 @@
 include_rules = [
   "+components/language/content",
 ]
+
+specific_include_rules = {
+  ".*Test\.java": [
+    "+chrome/test/android",
+    "+content/public/test/android",
+  ]
+}
diff --git a/components/language/android/android_language_metrics_bridge.cc b/components/language/android/android_language_metrics_bridge.cc
index f3b6610e2..e280509 100644
--- a/components/language/android/android_language_metrics_bridge.cc
+++ b/components/language/android/android_language_metrics_bridge.cc
@@ -24,3 +24,13 @@
             : kTranslateExplicitLanguageAskLanguageRemoved,
       base::HashMetricName(base::android::ConvertJavaStringToUTF8(language)));
 }
+
+// Records the HashMetric of |value| in the sparse histogram |histogramName|.
+static void JNI_AndroidLanguageMetricsBridge_ReportHashMetricName(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jstring>& histogramName,
+    const base::android::JavaParamRef<jstring>& value) {
+  base::UmaHistogramSparse(
+      base::android::ConvertJavaStringToUTF8(histogramName),
+      base::HashMetricName(base::android::ConvertJavaStringToUTF8(value)));
+}
diff --git a/components/language/android/java/src/org/chromium/components/language/AndroidLanguageMetricsBridge.java b/components/language/android/java/src/org/chromium/components/language/AndroidLanguageMetricsBridge.java
index 6f1da6b..bc30ab11 100644
--- a/components/language/android/java/src/org/chromium/components/language/AndroidLanguageMetricsBridge.java
+++ b/components/language/android/java/src/org/chromium/components/language/AndroidLanguageMetricsBridge.java
@@ -3,12 +3,19 @@
 // found in the LICENSE file.
 
 package org.chromium.components.language;
+
+import androidx.annotation.VisibleForTesting;
+
 import org.chromium.base.annotations.NativeMethods;
 
 /**
  * A bridge to language metrics functions that require access to native code.
  */
 public class AndroidLanguageMetricsBridge {
+    @VisibleForTesting
+    public static final String OVERRIDE_LANGUAGE_HISTOGRAM =
+            "LanguageUsage.UI.Android.OverrideLanguage";
+
     /**
      * Called when a user adds or removes a language from the list of languages they
      * can read using the Explicit Language Ask prompt at 2nd run.
@@ -20,8 +27,19 @@
                 language, added);
     }
 
+    /**
+     * Report the app override language code in a sparse histogram.
+     * @param language ISO-639 code of the app override language.
+     */
+    public static void reportAppOverrideLanguage(String language) {
+        AndroidLanguageMetricsBridgeJni.get().reportHashMetricName(
+                OVERRIDE_LANGUAGE_HISTOGRAM, language);
+    }
+
     @NativeMethods
     interface Natives {
         void reportExplicitLanguageAskStateChanged(String language, boolean added);
+        // report the hash of value in |histogramName| sparse histogram.
+        void reportHashMetricName(String histogramName, String value);
     }
 }
diff --git a/components/language/android/java/src/org/chromium/components/language/AndroidLanguageMetricsBridgeTest.java b/components/language/android/java/src/org/chromium/components/language/AndroidLanguageMetricsBridgeTest.java
new file mode 100644
index 0000000..30a130ef
--- /dev/null
+++ b/components/language/android/java/src/org/chromium/components/language/AndroidLanguageMetricsBridgeTest.java
@@ -0,0 +1,58 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.language;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.content_public.browser.test.util.TestThreadUtils;
+
+import java.util.Map;
+
+/**
+ * Tests for the AndroidLanguageMetricsBridge class.
+ */
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+public class AndroidLanguageMetricsBridgeTest {
+    private static final Map<String, Integer> NAME_HASHES =
+            Map.of("en", -74147910, "af", 357286655, "hmn", 1110169461, "yue-HK", 632444664, "und",
+                    350748440, "it-CH", 1708437566, "", -1895779836);
+
+    @Rule
+    public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
+
+    @Before
+    public void setUp() throws Exception {
+        mActivityTestRule.startMainActivityOnBlankPage();
+    }
+
+    /** Test that the correct language hashes are reported for the override language */
+    @Test
+    @SmallTest
+    public void testReportingAppOverrideLangauge() {
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            for (Map.Entry<String, Integer> entry : NAME_HASHES.entrySet()) {
+                int initialCount = RecordHistogram.getHistogramValueCountForTesting(
+                        AndroidLanguageMetricsBridge.OVERRIDE_LANGUAGE_HISTOGRAM, entry.getValue());
+                AndroidLanguageMetricsBridge.reportAppOverrideLanguage(entry.getKey());
+                Assert.assertEquals(initialCount + 1,
+                        RecordHistogram.getHistogramValueCountForTesting(
+                                AndroidLanguageMetricsBridge.OVERRIDE_LANGUAGE_HISTOGRAM,
+                                entry.getValue()));
+            }
+        });
+    }
+}
diff --git a/components/media_message_center/media_session_notification_item.cc b/components/media_message_center/media_session_notification_item.cc
index 36ebba6..41e789a 100644
--- a/components/media_message_center/media_session_notification_item.cc
+++ b/components/media_message_center/media_session_notification_item.cc
@@ -187,6 +187,13 @@
   return media_message_center::SourceType::kLocalMediaSession;
 }
 
+void MediaSessionNotificationItem::Raise() {
+  if (!media_controller_remote_.is_bound())
+    return;
+
+  media_controller_remote_->Raise();
+}
+
 void MediaSessionNotificationItem::SetController(
     mojo::Remote<media_session::mojom::MediaController> controller,
     media_session::mojom::MediaSessionInfoPtr session_info) {
diff --git a/components/media_message_center/media_session_notification_item.h b/components/media_message_center/media_session_notification_item.h
index 39c451e..dc5d30f1 100644
--- a/components/media_message_center/media_session_notification_item.h
+++ b/components/media_message_center/media_session_notification_item.h
@@ -71,6 +71,10 @@
   void Dismiss() override;
   media_message_center::SourceType SourceType() override;
 
+  // Calls |Raise()| on the underlying MediaSession, which will focus the
+  // WebContents if the MediaSession is associated with one.
+  void Raise();
+
   base::WeakPtr<MediaSessionNotificationItem> GetWeakPtr() {
     return weak_ptr_factory_.GetWeakPtr();
   }
diff --git a/components/nacl/browser/pnacl_host.cc b/components/nacl/browser/pnacl_host.cc
index 2f6c54e..ec87bd7 100644
--- a/components/nacl/browser/pnacl_host.cc
+++ b/components/nacl/browser/pnacl_host.cc
@@ -617,14 +617,13 @@
   }
   pending_backend_operations_++;
 
-  base::RepeatingClosure copyable_callback =
-      base::AdaptCallbackForRepeating(std::move(callback));
+  auto split_callback = base::SplitOnceCallback(std::move(callback));
   int rv = disk_cache_->DoomEntriesBetween(
       initial_time, end_time,
       base::BindOnce(&PnaclHost::OnEntriesDoomed, base::Unretained(this),
-                     copyable_callback));
+                     std::move(split_callback.first)));
   if (rv != net::ERR_IO_PENDING)
-    OnEntriesDoomed(copyable_callback, rv);
+    OnEntriesDoomed(std::move(split_callback.second), rv);
 }
 
 void PnaclHost::OnEntriesDoomed(base::OnceClosure callback, int net_error) {
diff --git a/components/no_state_prefetch/browser/no_state_prefetch_contents.cc b/components/no_state_prefetch/browser/no_state_prefetch_contents.cc
index 7c0ea90c..dbe4e70 100644
--- a/components/no_state_prefetch/browser/no_state_prefetch_contents.cc
+++ b/components/no_state_prefetch/browser/no_state_prefetch_contents.cc
@@ -452,13 +452,11 @@
   if (process_pid_ == base::kNullProcessId)
     return;
 
-  // Using AdaptCallbackForRepeating allows for an easier transition to
-  // OnceCallbacks for https://crbug.com/714018.
   memory_instrumentation::MemoryInstrumentation::GetInstance()
       ->RequestPrivateMemoryFootprint(
-          process_pid_, base::AdaptCallbackForRepeating(base::BindOnce(
-                            &NoStatePrefetchContents::DidGetMemoryUsage,
-                            weak_factory_.GetWeakPtr())));
+          process_pid_,
+          base::BindOnce(&NoStatePrefetchContents::DidGetMemoryUsage,
+                         weak_factory_.GetWeakPtr()));
 }
 
 void NoStatePrefetchContents::DidGetMemoryUsage(
diff --git a/components/offline_pages/core/prefetch/prefetch_downloader_impl.cc b/components/offline_pages/core/prefetch/prefetch_downloader_impl.cc
index e7b979e..f20cb7a1 100644
--- a/components/offline_pages/core/prefetch/prefetch_downloader_impl.cc
+++ b/components/offline_pages/core/prefetch/prefetch_downloader_impl.cc
@@ -108,9 +108,8 @@
       net::MutableNetworkTrafficAnnotationTag(traffic_annotation);
   params.client = download::DownloadClient::OFFLINE_PAGE_PREFETCH;
   params.guid = download_id;
-  params.callback = base::AdaptCallbackForRepeating(
-      base::BindOnce(&PrefetchDownloaderImpl::OnStartDownload,
-                     weak_ptr_factory_.GetWeakPtr()));
+  params.callback = base::BindOnce(&PrefetchDownloaderImpl::OnStartDownload,
+                                   weak_ptr_factory_.GetWeakPtr());
   params.scheduling_params.network_requirements =
       download::SchedulingParams::NetworkRequirements::UNMETERED;
   params.scheduling_params.battery_requirements =
@@ -147,7 +146,7 @@
   }
 
   // The download service can queue the download even if it is not fully up yet.
-  download_service_->StartDownload(params);
+  download_service_->StartDownload(std::move(params));
 }
 
 void PrefetchDownloaderImpl::OnDownloadServiceReady(
diff --git a/components/offline_pages/core/prefetch/prefetch_downloader_impl_unittest.cc b/components/offline_pages/core/prefetch/prefetch_downloader_impl_unittest.cc
index 1678e25..5607663 100644
--- a/components/offline_pages/core/prefetch/prefetch_downloader_impl_unittest.cc
+++ b/components/offline_pages/core/prefetch/prefetch_downloader_impl_unittest.cc
@@ -76,7 +76,7 @@
                                          operation_name);
   }
 
-  base::Optional<download::DownloadParams> GetDownload(
+  const base::Optional<download::DownloadParams>& GetDownload(
       const std::string& guid) const {
     return download_service_.GetDownload(guid);
   }
@@ -109,7 +109,8 @@
   clock()->SetNow(epoch);
 
   StartDownload(kDownloadId, kDownloadLocation, kOperationName);
-  base::Optional<download::DownloadParams> params = GetDownload(kDownloadId);
+  const base::Optional<download::DownloadParams>& params =
+      GetDownload(kDownloadId);
   ASSERT_TRUE(params.has_value());
   EXPECT_EQ(kDownloadId, params->guid);
   EXPECT_EQ(download::DownloadClient::OFFLINE_PAGE_PREFETCH, params->client);
@@ -137,7 +138,8 @@
   SetUpExperimentOption();
 
   StartDownload(kDownloadId, kDownloadLocation, kOperationName);
-  base::Optional<download::DownloadParams> params = GetDownload(kDownloadId);
+  const base::Optional<download::DownloadParams>& params =
+      GetDownload(kDownloadId);
   ASSERT_TRUE(params.has_value());
   std::string header_value;
   EXPECT_TRUE(params->request_params.request_headers.GetHeader(
diff --git a/components/offline_pages/core/prefetch/test_download_service.cc b/components/offline_pages/core/prefetch/test_download_service.cc
index 5ae7f98..973611d 100644
--- a/components/offline_pages/core/prefetch/test_download_service.cc
+++ b/components/offline_pages/core/prefetch/test_download_service.cc
@@ -51,13 +51,13 @@
 }
 
 void TestDownloadService::StartDownload(
-    const download::DownloadParams& download_params) {
+    download::DownloadParams download_params) {
   if (!download_dir_.IsValid())
     CHECK(download_dir_.CreateUniqueTempDir());
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
-      base::BindRepeating(download_params.callback, download_params.guid,
-                          download::DownloadParams::ACCEPTED));
+      base::BindOnce(std::move(download_params.callback), download_params.guid,
+                     download::DownloadParams::ACCEPTED));
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(&TestDownloadService::FinishDownload,
                                 base::Unretained(this), download_params.guid));
diff --git a/components/offline_pages/core/prefetch/test_download_service.h b/components/offline_pages/core/prefetch/test_download_service.h
index d5ef24dc..3da436b 100644
--- a/components/offline_pages/core/prefetch/test_download_service.h
+++ b/components/offline_pages/core/prefetch/test_download_service.h
@@ -29,7 +29,7 @@
                             download::TaskFinishedCallback callback) override;
   bool OnStopScheduledTask(download::DownloadTaskType task_type) override;
   DownloadService::ServiceStatus GetStatus() override;
-  void StartDownload(const download::DownloadParams& download_params) override;
+  void StartDownload(download::DownloadParams download_params) override;
   void PauseDownload(const std::string& guid) override;
   void ResumeDownload(const std::string& guid) override;
   void CancelDownload(const std::string& guid) override;
diff --git a/components/omnibox/browser/android/java/src/org/chromium/components/omnibox/AutocompleteResult.java b/components/omnibox/browser/android/java/src/org/chromium/components/omnibox/AutocompleteResult.java
index 35e57d7..aa45fdd 100644
--- a/components/omnibox/browser/android/java/src/org/chromium/components/omnibox/AutocompleteResult.java
+++ b/components/omnibox/browser/android/java/src/org/chromium/components/omnibox/AutocompleteResult.java
@@ -8,13 +8,14 @@
 import android.util.SparseArray;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.core.util.ObjectsCompat;
 
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.NativeMethods;
 
 import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -51,20 +52,51 @@
         }
     };
 
+    /** An empty, initialized AutocompleteResult object. */
+    public static final AutocompleteResult EMPTY_RESULT =
+            new AutocompleteResult(0, Collections.emptyList(), null);
+
     private final @NonNull SparseArray<GroupDetails> mGroupsDetails;
-    private @NonNull List<AutocompleteMatch> mSuggestions;
+    private final @NonNull List<AutocompleteMatch> mSuggestions;
+    private final boolean mIsFromCachedResult;
     private long mNativeAutocompleteResult;
 
-    public AutocompleteResult(
-            List<AutocompleteMatch> suggestions, SparseArray<GroupDetails> groupsDetails) {
+    /**
+     * Create AutocompleteResult object that is associated with an (optional) Native
+     * AutocompleteResult object.
+     *
+     * @param nativeResult Opaque pointer to Native AutocompleteResult object (or 0 if this object
+     *         is built from local cache)
+     * @param suggestions List of AutocompleteMatch objects.
+     * @param groupsDetails Additional information about the AutocompleteMatch groups.
+     */
+    private AutocompleteResult(long nativeResult, @Nullable List<AutocompleteMatch> suggestions,
+            @Nullable SparseArray<GroupDetails> groupsDetails) {
+        // Consider all locally constructed AutocompleteResult objects as coming from Cache.
+        // These results do not have a native counterpart, meaning there's no corresponding C++
+        // structure describing the same AutocompleteResult.
+        // Note that the mNativeResult might change at any point during the lifecycle of this object
+        // to reflect relocation or destruction of the native object, so we cache this information
+        // separately.
+        mIsFromCachedResult = nativeResult != 0;
+        mNativeAutocompleteResult = nativeResult;
         mSuggestions = suggestions != null ? suggestions : new ArrayList<>();
         mGroupsDetails = groupsDetails != null ? groupsDetails : new SparseArray<>();
     }
 
-    public AutocompleteResult(long nativeResult, List<AutocompleteMatch> suggestions,
-            SparseArray<GroupDetails> groupsDetails) {
-        this(suggestions, groupsDetails);
-        mNativeAutocompleteResult = nativeResult;
+    /**
+     * Create AutocompleteResult object from cached information.
+     *
+     * Newly created AutocompleteResult object is not associated with any Native AutocompleteResult
+     * counterpart.
+     *
+     * @param suggestions List of AutocompleteMatch objects.
+     * @param groupsDetails Additional information about the AutocompleteMatch groups.
+     * @return AutocompleteResult object encompassing supplied information.
+     */
+    public static AutocompleteResult fromCache(@Nullable List<AutocompleteMatch> suggestions,
+            @Nullable SparseArray<GroupDetails> groupsDetails) {
+        return new AutocompleteResult(0, suggestions, groupsDetails);
     }
 
     @CalledByNative
@@ -80,14 +112,16 @@
                     new GroupDetails(groupNames[index], groupCollapsedStates[index]));
         }
 
-        AutocompleteResult result = new AutocompleteResult(
-                nativeAutocompleteResult, Arrays.asList(suggestions), groupsDetails);
+        AutocompleteResult result =
+                new AutocompleteResult(nativeAutocompleteResult, null, groupsDetails);
+        result.updateMatches(suggestions);
         return result;
     }
 
     @CalledByNative
     private void updateMatches(@NonNull AutocompleteMatch[] suggestions) {
-        mSuggestions = Arrays.asList(suggestions);
+        mSuggestions.clear();
+        Collections.addAll(mSuggestions, suggestions);
     }
 
     @CalledByNative
@@ -111,6 +145,10 @@
         return mGroupsDetails;
     }
 
+    public boolean isFromCachedResult() {
+        return mIsFromCachedResult;
+    }
+
     /**
      * Verifies coherency of this AutocompleteResult object with its C++ counterpart.
      * Records histogram data reflecting the outcome.
diff --git a/components/omnibox/browser/android/javatests/src/org/chromium/components/omnibox/AutocompleteResultUnitTest.java b/components/omnibox/browser/android/javatests/src/org/chromium/components/omnibox/AutocompleteResultUnitTest.java
index c834487..162f969d 100644
--- a/components/omnibox/browser/android/javatests/src/org/chromium/components/omnibox/AutocompleteResultUnitTest.java
+++ b/components/omnibox/browser/android/javatests/src/org/chromium/components/omnibox/AutocompleteResultUnitTest.java
@@ -62,8 +62,8 @@
         groupsDetails2.put(10, new GroupDetails("Hello", false));
         groupsDetails2.put(20, new GroupDetails("Test", true));
 
-        AutocompleteResult res1 = new AutocompleteResult(list1, groupsDetails1);
-        AutocompleteResult res2 = new AutocompleteResult(list2, groupsDetails2);
+        AutocompleteResult res1 = AutocompleteResult.fromCache(list1, groupsDetails1);
+        AutocompleteResult res2 = AutocompleteResult.fromCache(list2, groupsDetails2);
 
         Assert.assertEquals(res1, res2);
         Assert.assertEquals(res1.hashCode(), res2.hashCode());
@@ -86,8 +86,8 @@
         groupsDetails2.put(10, new GroupDetails("Hello", false));
         groupsDetails2.put(20, new GroupDetails("Test", true));
 
-        AutocompleteResult res1 = new AutocompleteResult(list1, groupsDetails1);
-        AutocompleteResult res2 = new AutocompleteResult(list2, groupsDetails2);
+        AutocompleteResult res1 = AutocompleteResult.fromCache(list1, groupsDetails1);
+        AutocompleteResult res2 = AutocompleteResult.fromCache(list2, groupsDetails2);
 
         Assert.assertNotEquals(res1, res2);
         Assert.assertNotEquals(res1.hashCode(), res2.hashCode());
@@ -109,8 +109,8 @@
 
         groupsDetails2.put(10, new GroupDetails("Hello", true));
 
-        AutocompleteResult res1 = new AutocompleteResult(list1, groupsDetails1);
-        AutocompleteResult res2 = new AutocompleteResult(list2, groupsDetails2);
+        AutocompleteResult res1 = AutocompleteResult.fromCache(list1, groupsDetails1);
+        AutocompleteResult res2 = AutocompleteResult.fromCache(list2, groupsDetails2);
 
         Assert.assertNotEquals(res1, res2);
         Assert.assertNotEquals(res1.hashCode(), res2.hashCode());
@@ -133,8 +133,8 @@
         groupsDetails2.put(10, new GroupDetails("Hello", false));
         groupsDetails2.put(20, new GroupDetails("Test", false));
 
-        AutocompleteResult res1 = new AutocompleteResult(list1, groupsDetails1);
-        AutocompleteResult res2 = new AutocompleteResult(list2, groupsDetails2);
+        AutocompleteResult res1 = AutocompleteResult.fromCache(list1, groupsDetails1);
+        AutocompleteResult res2 = AutocompleteResult.fromCache(list2, groupsDetails2);
 
         Assert.assertNotEquals(res1, res2);
         Assert.assertNotEquals(res1.hashCode(), res2.hashCode());
@@ -158,8 +158,8 @@
         groupsDetails2.put(20, new GroupDetails("Test", false));
         groupsDetails2.put(30, new GroupDetails("Yikes", false));
 
-        AutocompleteResult res1 = new AutocompleteResult(list1, groupsDetails1);
-        AutocompleteResult res2 = new AutocompleteResult(list2, groupsDetails2);
+        AutocompleteResult res1 = AutocompleteResult.fromCache(list1, groupsDetails1);
+        AutocompleteResult res2 = AutocompleteResult.fromCache(list2, groupsDetails2);
 
         Assert.assertNotEquals(res1, res2);
         Assert.assertNotEquals(res1.hashCode(), res2.hashCode());
@@ -173,8 +173,8 @@
         List<AutocompleteMatch> list2 = Arrays.asList(
                 buildSuggestionForIndex(1), buildSuggestionForIndex(2), buildSuggestionForIndex(4));
 
-        AutocompleteResult res1 = new AutocompleteResult(list1, null);
-        AutocompleteResult res2 = new AutocompleteResult(list2, null);
+        AutocompleteResult res1 = AutocompleteResult.fromCache(list1, null);
+        AutocompleteResult res2 = AutocompleteResult.fromCache(list2, null);
 
         Assert.assertNotEquals(res1, res2);
         Assert.assertNotEquals(res1.hashCode(), res2.hashCode());
@@ -199,9 +199,9 @@
         groupsDetails3.put(10, new GroupDetails("Hello", false));
         groupsDetails3.put(20, new GroupDetails("Test 2", false));
 
-        AutocompleteResult res1 = new AutocompleteResult(list, groupsDetails1);
-        AutocompleteResult res2 = new AutocompleteResult(list, groupsDetails2);
-        AutocompleteResult res3 = new AutocompleteResult(list, groupsDetails3);
+        AutocompleteResult res1 = AutocompleteResult.fromCache(list, groupsDetails1);
+        AutocompleteResult res2 = AutocompleteResult.fromCache(list, groupsDetails2);
+        AutocompleteResult res3 = AutocompleteResult.fromCache(list, groupsDetails3);
 
         Assert.assertNotEquals(res1, res2);
         Assert.assertNotEquals(res1, res3);
@@ -227,8 +227,8 @@
                         .addSubtype(4)
                         .build());
 
-        AutocompleteResult res1 = new AutocompleteResult(list1, null);
-        AutocompleteResult res2 = new AutocompleteResult(list2, null);
+        AutocompleteResult res1 = AutocompleteResult.fromCache(list1, null);
+        AutocompleteResult res2 = AutocompleteResult.fromCache(list2, null);
 
         Assert.assertNotEquals(res1, res2);
     }
@@ -241,8 +241,8 @@
         List<AutocompleteMatch> list2 = Arrays.asList(
                 buildSuggestionForIndex(1), buildSuggestionForIndex(2), buildSuggestionForIndex(4));
 
-        AutocompleteResult res1 = new AutocompleteResult(list1, null);
-        AutocompleteResult res2 = new AutocompleteResult(list2, null);
+        AutocompleteResult res1 = AutocompleteResult.fromCache(list1, null);
+        AutocompleteResult res2 = AutocompleteResult.fromCache(list2, null);
 
         Assert.assertNotEquals(res1, res2);
         Assert.assertNotEquals(res1.hashCode(), res2.hashCode());
@@ -253,8 +253,8 @@
     public void autocompleteResult_emptyListsAreEqual() {
         final List<AutocompleteMatch> list1 = new ArrayList<>();
         final List<AutocompleteMatch> list2 = new ArrayList<>();
-        AutocompleteResult res1 = new AutocompleteResult(list1, null);
-        AutocompleteResult res2 = new AutocompleteResult(list2, null);
+        AutocompleteResult res1 = AutocompleteResult.fromCache(list1, null);
+        AutocompleteResult res2 = AutocompleteResult.fromCache(list2, null);
         Assert.assertEquals(res1, res2);
         Assert.assertEquals(res1.hashCode(), res2.hashCode());
     }
@@ -263,8 +263,8 @@
     @SmallTest
     public void autocompleteResult_nullAndEmptyListsAreEqual() {
         final List<AutocompleteMatch> list1 = new ArrayList<>();
-        AutocompleteResult res1 = new AutocompleteResult(list1, null);
-        AutocompleteResult res2 = new AutocompleteResult(null, null);
+        AutocompleteResult res1 = AutocompleteResult.fromCache(list1, null);
+        AutocompleteResult res2 = AutocompleteResult.EMPTY_RESULT;
         Assert.assertEquals(res1, res2);
         Assert.assertEquals(res1.hashCode(), res2.hashCode());
     }
@@ -274,8 +274,8 @@
     public void autocompleteResult_emptyAndNonEmptyListsAreNotEqual() {
         List<AutocompleteMatch> list1 = Arrays.asList(buildSuggestionForIndex(1));
         final List<AutocompleteMatch> list2 = new ArrayList<>();
-        AutocompleteResult res1 = new AutocompleteResult(list1, null);
-        AutocompleteResult res2 = new AutocompleteResult(list2, null);
+        AutocompleteResult res1 = AutocompleteResult.fromCache(list1, null);
+        AutocompleteResult res2 = AutocompleteResult.fromCache(list2, null);
         Assert.assertNotEquals(res1, res2);
         Assert.assertNotEquals(res1.hashCode(), res2.hashCode());
     }
diff --git a/components/omnibox/browser/autocomplete_match.cc b/components/omnibox/browser/autocomplete_match.cc
index 000ece14..9c4d275 100644
--- a/components/omnibox/browser/autocomplete_match.cc
+++ b/components/omnibox/browser/autocomplete_match.cc
@@ -456,84 +456,6 @@
 }
 #endif
 
-std::u16string AutocompleteMatch::GetWhyThisSuggestionText() const {
-  // TODO(tommycli): Replace these placeholder strings with final ones from UX.
-  switch (type) {
-    case Type::URL_WHAT_YOU_TYPED:
-      return u"This navigation match is the exact URL you typed.";
-
-    case Type::HISTORY_URL:
-    case Type::HISTORY_TITLE:
-    case Type::HISTORY_BODY:
-    case Type::HISTORY_KEYWORD:
-      return u"This navigation match is a previously visited page from Chrome "
-             u"History.";
-
-    case Type::NAVSUGGEST:
-      return u"This navigation match is suggested by the search engine based "
-             u"on what you typed.";
-
-    case Type::SEARCH_WHAT_YOU_TYPED:
-      return u"This search query is exactly what you typed.";
-
-    case Type::SEARCH_HISTORY:
-      // TODO(tommycli): We may need to distinguish between matches sourced
-      // from search history saved in the cloud vs. locally.
-      return u"This search query is suggested by the search engine based on "
-             u"what you typed and past search queries.";
-
-    case Type::SEARCH_SUGGEST:
-    case Type::SEARCH_SUGGEST_ENTITY:
-    case Type::SEARCH_SUGGEST_TAIL:
-      return u"This search query is suggested by the search engine based on "
-             u"what you typed.";
-
-    case Type::SEARCH_SUGGEST_PERSONALIZED:
-      return u"This search query is suggested by the search engine based on "
-             u"what you typed. It has also been personalized to you.";
-
-    case Type::SEARCH_OTHER_ENGINE:
-      return u"This search query is for a non-default search engine.";
-
-    case Type::BOOKMARK_TITLE:
-      return u"This navigation matches the title of a Bookmark.";
-
-    case Type::NAVSUGGEST_PERSONALIZED:
-      return u"This navigation match is suggested by the search engine based "
-             u"on what you typed. It has also been personalized to you.";
-
-    case Type::CALCULATOR:
-      return u"This calculation is the result of evaluating your input "
-             u"provided by your default search engine.";
-
-    case Type::CLIPBOARD_URL:
-    case Type::CLIPBOARD_TEXT:
-    case Type::CLIPBOARD_IMAGE:
-      return u"This match is from the system clipboard.";
-
-    case Type::VOICE_SUGGEST:
-      return u"This match is from voice.";
-
-    case Type::DOCUMENT_SUGGESTION:
-      return u"This match is from your documents.";
-
-    case Type::PEDAL:
-      return u"This is a suggested Chrome action based on what you typed.";
-
-    case Type::EXTENSION_APP_DEPRECATED:
-    case Type::SEARCH_SUGGEST_PROFILE:
-    case Type::CONTACT_DEPRECATED:
-    case Type::PHYSICAL_WEB_DEPRECATED:
-    case Type::PHYSICAL_WEB_OVERFLOW_DEPRECATED:
-    case Type::TAB_SEARCH_DEPRECATED:
-    case Type::TILE_SUGGESTION:
-    case Type::TILE_NAVSUGGEST:
-    case Type::NUM_TYPES:
-      NOTREACHED();
-      return std::u16string();
-  }
-}
-
 // static
 bool AutocompleteMatch::MoreRelevant(const AutocompleteMatch& match1,
                                      const AutocompleteMatch& match2) {
diff --git a/components/omnibox/browser/autocomplete_match.h b/components/omnibox/browser/autocomplete_match.h
index 1fe1039..8528dab 100644
--- a/components/omnibox/browser/autocomplete_match.h
+++ b/components/omnibox/browser/autocomplete_match.h
@@ -246,10 +246,6 @@
   const gfx::VectorIcon& GetVectorIcon(bool is_bookmark) const;
 #endif
 
-  // Returns text explaining why this suggestion was displayed. Can return an
-  // empty string if there is no explanation.
-  std::u16string GetWhyThisSuggestionText() const;
-
   // Comparison function for determining whether the first match is better than
   // the second.
   static bool MoreRelevant(const AutocompleteMatch& match1,
diff --git a/components/page_load_metrics/browser/observers/use_counter_page_load_metrics_observer.cc b/components/page_load_metrics/browser/observers/use_counter_page_load_metrics_observer.cc
index c5830cc2..70a7f85 100644
--- a/components/page_load_metrics/browser/observers/use_counter_page_load_metrics_observer.cc
+++ b/components/page_load_metrics/browser/observers/use_counter_page_load_metrics_observer.cc
@@ -14,6 +14,7 @@
 using UkmFeatureList = UseCounterPageLoadMetricsObserver::UkmFeatureList;
 using WebFeature = blink::mojom::WebFeature;
 using CSSSampleId = blink::mojom::CSSSampleId;
+using PermissionsPolicyFeature = blink::mojom::PermissionsPolicyFeature;
 
 namespace {
 
@@ -72,6 +73,7 @@
   DCHECK_EQ(ukm_features_recorded_.count(), 0ul);
   DCHECK_EQ(css_properties_recorded_.count(), 0ul);
   DCHECK_EQ(animated_css_properties_recorded_.count(), 0ul);
+  DCHECK_EQ(violated_permissions_policy_features_recorded_.count(), 0ul);
 
   content::RenderFrameHost* rfh = navigation_handle->GetRenderFrameHost();
 
@@ -184,6 +186,14 @@
       UMA_HISTOGRAM_ENUMERATION(internal::kAnimatedCssPropertiesHistogramName,
                                 static_cast<CSSSampleId>(feature.value()));
       break;
+
+    case FeatureType::kPermissionsPolicyViolationEnforce:
+      if (TestAndSet(violated_permissions_policy_features_recorded_,
+                     feature.value()))
+        return;
+      UMA_HISTOGRAM_ENUMERATION(
+          internal::kPermissionsPolicyViolationHistogramName,
+          static_cast<PermissionsPolicyFeature>(feature.value()));
   }
 }
 
diff --git a/components/page_load_metrics/browser/observers/use_counter_page_load_metrics_observer.h b/components/page_load_metrics/browser/observers/use_counter_page_load_metrics_observer.h
index 54ed965..4b543028 100644
--- a/components/page_load_metrics/browser/observers/use_counter_page_load_metrics_observer.h
+++ b/components/page_load_metrics/browser/observers/use_counter_page_load_metrics_observer.h
@@ -9,6 +9,7 @@
 #include "base/containers/flat_set.h"
 #include "base/macros.h"
 #include "components/page_load_metrics/browser/page_load_metrics_observer.h"
+#include "third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom.h"
 #include "third_party/blink/public/mojom/use_counter/css_property_id.mojom.h"
 #include "third_party/blink/public/mojom/use_counter/use_counter_feature.mojom-forward.h"
 #include "third_party/blink/public/mojom/web_feature/web_feature.mojom.h"
@@ -21,6 +22,8 @@
 const char kCssPropertiesHistogramName[] = "Blink.UseCounter.CSSProperties";
 const char kAnimatedCssPropertiesHistogramName[] =
     "Blink.UseCounter.AnimatedCSSProperties";
+const char kPermissionsPolicyViolationHistogramName[] =
+    "Blink.UseCounter.PermissionsPolicy.Violation.Enforce";
 
 }  // namespace internal
 
@@ -79,6 +82,10 @@
       animated_css_properties_recorded_;
   std::bitset<static_cast<size_t>(blink::mojom::WebFeature::kNumberOfFeatures)>
       ukm_features_recorded_;
+  std::bitset<static_cast<size_t>(
+                  blink::mojom::PermissionsPolicyFeature::kMaxValue) +
+              1>
+      violated_permissions_policy_features_recorded_;
   DISALLOW_COPY_AND_ASSIGN(UseCounterPageLoadMetricsObserver);
 };
 
diff --git a/components/page_load_metrics/browser/observers/use_counter_page_load_metrics_observer_unittest.cc b/components/page_load_metrics/browser/observers/use_counter_page_load_metrics_observer_unittest.cc
index 63c42a3..6991ad9 100644
--- a/components/page_load_metrics/browser/observers/use_counter_page_load_metrics_observer_unittest.cc
+++ b/components/page_load_metrics/browser/observers/use_counter_page_load_metrics_observer_unittest.cc
@@ -31,6 +31,8 @@
       return internal::kCssPropertiesHistogramName;
     case FeatureType::kAnimatedCssProperty:
       return internal::kAnimatedCssPropertiesHistogramName;
+    case FeatureType::kPermissionsPolicyViolationEnforce:
+      return internal::kPermissionsPolicyViolationHistogramName;
   }
 }
 
@@ -109,6 +111,9 @@
       {
           {blink::mojom::UseCounterFeatureType::kWebFeature, 2},
           {blink::mojom::UseCounterFeatureType::kAnimatedCssProperty, 2},
+          {blink::mojom::UseCounterFeatureType::
+               kPermissionsPolicyViolationEnforce,
+           3},
       });
 }
 
@@ -121,11 +126,17 @@
           {blink::mojom::UseCounterFeatureType::kCssProperty, 1},
           {blink::mojom::UseCounterFeatureType::kCssProperty, 1},
           {blink::mojom::UseCounterFeatureType::kAnimatedCssProperty, 2},
+          {blink::mojom::UseCounterFeatureType::
+               kPermissionsPolicyViolationEnforce,
+           3},
           {blink::mojom::UseCounterFeatureType::kCssProperty, 3},
       },
       {
           {blink::mojom::UseCounterFeatureType::kWebFeature, 0},
           {blink::mojom::UseCounterFeatureType::kWebFeature, 2},
           {blink::mojom::UseCounterFeatureType::kAnimatedCssProperty, 2},
+          {blink::mojom::UseCounterFeatureType::
+               kPermissionsPolicyViolationEnforce,
+           3},
       });
 }
diff --git a/components/password_manager/core/browser/credential_manager_pending_request_task.cc b/components/password_manager/core/browser/credential_manager_pending_request_task.cc
index fd8ecd9..919986d8 100644
--- a/components/password_manager/core/browser/credential_manager_pending_request_task.cc
+++ b/components/password_manager/core/browser/credential_manager_pending_request_task.cc
@@ -327,20 +327,20 @@
     return;
   }
 
-  auto repeating_send_callback =
-      base::AdaptCallbackForRepeating(std::move(send_callback_));
+  auto split_send_callback = base::SplitOnceCallback(std::move(send_callback_));
   if (!delegate_->client()->PromptUserToChooseCredentials(
           std::move(local_results), origin_,
           base::BindOnce(
               &CredentialManagerPendingRequestTaskDelegate::SendPasswordForm,
-              base::Unretained(delegate_), repeating_send_callback,
+              base::Unretained(delegate_), std::move(split_send_callback.first),
               mediation_))) {
     // Since PromptUserToChooseCredentials() does not invoke the callback when
     // returning false, `repeating_send_callback` has not been run in this
     // branch yet.
     LogCredentialManagerGetResult(
         metrics_util::CredentialManagerGetResult::kNone, mediation_);
-    delegate_->SendCredential(repeating_send_callback, CredentialInfo());
+    delegate_->SendCredential(std::move(split_send_callback.second),
+                              CredentialInfo());
   }
 }
 
diff --git a/components/policy/core/common/cloud/cloud_policy_client.cc b/components/policy/core/common/cloud/cloud_policy_client.cc
index 23584b8..079f0fc 100644
--- a/components/policy/core/common/cloud/cloud_policy_client.cc
+++ b/components/policy/core/common/cloud/cloud_policy_client.cc
@@ -472,9 +472,8 @@
           this,
           /*critical=*/false, std::move(auth),
           /*oauth_token=*/base::nullopt,
-          base::AdaptCallbackForRepeating(base::BindOnce(
-              &CloudPolicyClient::OnFetchRobotAuthCodesCompleted,
-              weak_ptr_factory_.GetWeakPtr(), std::move(callback))));
+          base::BindOnce(&CloudPolicyClient::OnFetchRobotAuthCodesCompleted,
+                         weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 
   em::DeviceServiceApiAccessRequest* request =
       config->request()->mutable_service_api_access_request();
@@ -707,9 +706,8 @@
           DeviceManagementService::JobConfiguration::TYPE_REMOTE_COMMANDS, this,
           /*critical=*/false, DMAuth::FromDMToken(dm_token_),
           /*oauth_token=*/base::nullopt,
-          base::AdaptCallbackForRepeating(base::BindOnce(
-              &CloudPolicyClient::OnRemoteCommandsFetched,
-              weak_ptr_factory_.GetWeakPtr(), std::move(callback))));
+          base::BindOnce(&CloudPolicyClient::OnRemoteCommandsFetched,
+                         weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 
   em::DeviceRemoteCommandRequest* const request =
       config->request()->mutable_remote_command_request();
diff --git a/components/safe_browsing/content/web_ui/safe_browsing_ui.cc b/components/safe_browsing/content/web_ui/safe_browsing_ui.cc
index 41f7382..dae6302 100644
--- a/components/safe_browsing/content/web_ui/safe_browsing_ui.cc
+++ b/components/safe_browsing/content/web_ui/safe_browsing_ui.cc
@@ -616,6 +616,15 @@
   population_dict.SetKey("is_incognito",
                          base::Value(population.is_incognito()));
 
+  population_dict.SetKey("user_agent", base::Value(population.user_agent()));
+
+  population_dict.SetKey("number_of_profiles",
+                         base::Value(population.number_of_profiles()));
+  population_dict.SetKey("number_of_loaded_profiles",
+                         base::Value(population.number_of_loaded_profiles()));
+  population_dict.SetKey("number_of_open_profiles",
+                         base::Value(population.number_of_open_profiles()));
+
   return std::move(population_dict);
 }
 
diff --git a/components/safe_browsing/core/features.cc b/components/safe_browsing/core/features.cc
index 2a9b1bf..d26944a 100644
--- a/components/safe_browsing/core/features.cc
+++ b/components/safe_browsing/core/features.cc
@@ -30,6 +30,10 @@
 const base::Feature kAdSamplerTriggerFeature{"SafeBrowsingAdSamplerTrigger",
                                              base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kBetterTelemetryAcrossReports{
+    "SafeBrowsingBetterTelemetryAcrossReports",
+    base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kCaptureInlineJavascriptForGoogleAds{
     "CaptureInlineJavascriptForGoogleAds", base::FEATURE_DISABLED_BY_DEFAULT};
 
@@ -138,6 +142,7 @@
     {&kAdPopupTriggerFeature, true},
     {&kAdRedirectTriggerFeature, true},
     {&kAdSamplerTriggerFeature, false},
+    {&kBetterTelemetryAcrossReports, true},
     {&kCaptureInlineJavascriptForGoogleAds, true},
     {&kClientSideDetectionForAndroid, true},
     {&kClientSideDetectionWithToken, true},
@@ -146,6 +151,7 @@
     {&kLimitedListSizeForIOS, true},
     {&kPasswordProtectionForSignedInUsers, true},
     {&kPasswordProtectionWithToken, true},
+    {&kPromptEsbForDeepScanning, true},
     {&kRealTimeUrlLookupEnabled, true},
     {&kRealTimeUrlLookupEnabledWithToken, true},
     {&kRealTimeUrlLookupReferrerChain, true},
diff --git a/components/safe_browsing/core/features.h b/components/safe_browsing/core/features.h
index 65f3925..f2b6115 100644
--- a/components/safe_browsing/core/features.h
+++ b/components/safe_browsing/core/features.h
@@ -29,6 +29,10 @@
 
 extern const base::Feature kAdSamplerTriggerFeature;
 
+// Enables including some information in protection requests sent to Safe
+// Browsing.
+extern const base::Feature kBetterTelemetryAcrossReports;
+
 // Controls whether we sample inline JavaScript for ads in RIND
 // reports.
 extern const base::Feature kCaptureInlineJavascriptForGoogleAds;
diff --git a/components/safe_browsing/core/proto/csd.proto b/components/safe_browsing/core/proto/csd.proto
index 6062607..d413eda 100644
--- a/components/safe_browsing/core/proto/csd.proto
+++ b/components/safe_browsing/core/proto/csd.proto
@@ -69,6 +69,22 @@
 
   // If the user is opted in to MBB.
   optional bool is_mbb_enabled = 8;
+
+  // The simplified user agent string (e.g. Chrome/xy.0.abcd.e/Windows).
+  optional string user_agent = 9;
+
+  // The total number of profiles available on this machine. Some of these may
+  // not be fully initialized so can't be used.
+  optional int32 number_of_profiles = 10;
+
+  // The number of created and fully initialized profiles. Some of these
+  // profiles may be inactive.
+  optional int32 number_of_loaded_profiles = 11;
+
+  // The number of profiles that are currently open, i.e. have open browsers or
+  // were open the last time Chrome was running. Profiles that fail to
+  // initialize are skipped.
+  optional int32 number_of_open_profiles = 12;
 }
 
 message ClientPhishingRequest {
diff --git a/components/services/app_service/public/cpp/instance.cc b/components/services/app_service/public/cpp/instance.cc
index bfb9954..2cd00fb9 100644
--- a/components/services/app_service/public/cpp/instance.cc
+++ b/components/services/app_service/public/cpp/instance.cc
@@ -11,7 +11,15 @@
 Instance::InstanceKey::InstanceKey(aura::Window* window) : window_(window) {}
 
 bool Instance::InstanceKey::operator<(const InstanceKey& other) const {
-  return this->Window() < other.Window();
+  return Window() < other.Window();
+}
+
+bool Instance::InstanceKey::operator==(const InstanceKey& other) const {
+  return Window() == other.Window();
+}
+
+bool Instance::InstanceKey::operator!=(const InstanceKey& other) const {
+  return Window() != other.Window();
 }
 
 Instance::Instance(const std::string& app_id,
diff --git a/components/services/app_service/public/cpp/instance.h b/components/services/app_service/public/cpp/instance.h
index 552f738..3d92a52 100644
--- a/components/services/app_service/public/cpp/instance.h
+++ b/components/services/app_service/public/cpp/instance.h
@@ -35,6 +35,8 @@
     ~InstanceKey() = default;
     aura::Window* Window() const { return window_; }
     bool operator<(const InstanceKey& other) const;
+    bool operator==(const InstanceKey& other) const;
+    bool operator!=(const InstanceKey& other) const;
 
    private:
     // window_ is owned by ash and will be deleted when the user closes the
diff --git a/components/services/app_service/public/cpp/instance_registry.cc b/components/services/app_service/public/cpp/instance_registry.cc
index 84fa7cc..9b597a1 100644
--- a/components/services/app_service/public/cpp/instance_registry.cc
+++ b/components/services/app_service/public/cpp/instance_registry.cc
@@ -59,17 +59,19 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
 
   for (auto& delta : deltas) {
-    // If the window state is not kDestroyed, adds to |app_id_to_app_window_|,
-    // otherwise removes the window from |app_id_to_app_window_|.
+    // If the instance state is not kDestroyed, adds to
+    // |app_id_to_app_instance_key_|, otherwise removes the instance key from
+    // |app_id_to_app_instance_key_|.
     if (static_cast<InstanceState>(delta.get()->State() &
                                    InstanceState::kDestroyed) ==
         InstanceState::kUnknown) {
-      app_id_to_app_windows_[delta.get()->AppId()].insert(
-          delta.get()->Window());
+      app_id_to_app_instance_key_[delta.get()->AppId()].insert(
+          delta.get()->GetInstanceKey());
     } else {
-      app_id_to_app_windows_[delta.get()->AppId()].erase(delta.get()->Window());
-      if (app_id_to_app_windows_[delta.get()->AppId()].size() == 0) {
-        app_id_to_app_windows_.erase(delta.get()->AppId());
+      app_id_to_app_instance_key_[delta.get()->AppId()].erase(
+          delta.get()->GetInstanceKey());
+      if (app_id_to_app_instance_key_[delta.get()->AppId()].size() == 0) {
+        app_id_to_app_instance_key_.erase(delta.get()->AppId());
       }
     }
   }
@@ -90,11 +92,14 @@
 
 std::set<aura::Window*> InstanceRegistry::GetWindows(
     const std::string& app_id) {
-  auto it = app_id_to_app_windows_.find(app_id);
-  if (it != app_id_to_app_windows_.end()) {
-    return it->second;
+  auto it = app_id_to_app_instance_key_.find(app_id);
+  auto windows = std::set<aura::Window*>{};
+  if (it != app_id_to_app_instance_key_.end()) {
+    for (auto instance_key : it->second) {
+      windows.insert(instance_key.Window());
+    }
   }
-  return std::set<aura::Window*>{};
+  return windows;
 }
 
 InstanceState InstanceRegistry::GetState(
diff --git a/components/services/app_service/public/cpp/instance_registry.h b/components/services/app_service/public/cpp/instance_registry.h
index eeff459..0ee7b84 100644
--- a/components/services/app_service/public/cpp/instance_registry.h
+++ b/components/services/app_service/public/cpp/instance_registry.h
@@ -173,8 +173,9 @@
   std::map<const Instance::InstanceKey, InstancePtr> states_;
   Instances deltas_pending_;
 
-  // Maps from app id to app windows.
-  std::map<const std::string, std::set<aura::Window*>> app_id_to_app_windows_;
+  // Maps from app id to app instance key.
+  std::map<const std::string, std::set<const Instance::InstanceKey>>
+      app_id_to_app_instance_key_;
 
   SEQUENCE_CHECKER(my_sequence_checker_);
 };
diff --git a/content/browser/accessibility/browser_accessibility_state_impl_android.cc b/content/browser/accessibility/browser_accessibility_state_impl_android.cc
index ccbcf87b..08ac12b 100644
--- a/content/browser/accessibility/browser_accessibility_state_impl_android.cc
+++ b/content/browser/accessibility/browser_accessibility_state_impl_android.cc
@@ -6,6 +6,7 @@
 
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
+#include "base/containers/contains.h"
 #include "base/metrics/histogram_macros.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/android/content_jni_headers/BrowserAccessibilityState_jni.h"
diff --git a/content/browser/appcache/appcache_request_handler.cc b/content/browser/appcache/appcache_request_handler.cc
index 1cf47e8..92060461 100644
--- a/content/browser/appcache/appcache_request_handler.cc
+++ b/content/browser/appcache/appcache_request_handler.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/command_line.h"
+#include "base/containers/contains.h"
 #include "base/feature_list.h"
 #include "content/browser/appcache/appcache.h"
 #include "content/browser/appcache/appcache_backend_impl.h"
diff --git a/content/browser/appcache/appcache_update_job.cc b/content/browser/appcache/appcache_update_job.cc
index 6cd52bf..c21b18be 100644
--- a/content/browser/appcache/appcache_update_job.cc
+++ b/content/browser/appcache/appcache_update_job.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/compiler_specific.h"
+#include "base/containers/contains.h"
 #include "base/location.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/single_thread_task_runner.h"
diff --git a/content/browser/appcache/appcache_update_job_unittest.cc b/content/browser/appcache/appcache_update_job_unittest.cc
index cfbe874..35abdd0 100644
--- a/content/browser/appcache/appcache_update_job_unittest.cc
+++ b/content/browser/appcache/appcache_update_job_unittest.cc
@@ -12,6 +12,7 @@
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
+#include "base/containers/contains.h"
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
diff --git a/content/browser/background_sync/background_sync_manager.cc b/content/browser/background_sync/background_sync_manager.cc
index d3d08893..b25d6ea 100644
--- a/content/browser/background_sync/background_sync_manager.cc
+++ b/content/browser/background_sync/background_sync_manager.cc
@@ -10,6 +10,7 @@
 #include "base/barrier_closure.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
+#include "base/containers/contains.h"
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
 #include "base/single_thread_task_runner.h"
diff --git a/content/browser/bluetooth/bluetooth_adapter_factory_wrapper.cc b/content/browser/bluetooth/bluetooth_adapter_factory_wrapper.cc
index 8bf7c07..5d1faf5c 100644
--- a/content/browser/bluetooth/bluetooth_adapter_factory_wrapper.cc
+++ b/content/browser/bluetooth/bluetooth_adapter_factory_wrapper.cc
@@ -9,6 +9,7 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/containers/contains.h"
 #include "base/location.h"
 #include "base/no_destructor.h"
 #include "base/threading/thread_task_runner_handle.h"
diff --git a/content/browser/bluetooth/bluetooth_device_chooser_controller.cc b/content/browser/bluetooth/bluetooth_device_chooser_controller.cc
index 48d8e16..55bbd27 100644
--- a/content/browser/bluetooth/bluetooth_device_chooser_controller.cc
+++ b/content/browser/bluetooth/bluetooth_device_chooser_controller.cc
@@ -10,6 +10,7 @@
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
+#include "base/containers/contains.h"
 #include "base/containers/flat_set.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_util.h"
diff --git a/content/browser/bluetooth/frame_connected_bluetooth_devices.cc b/content/browser/bluetooth/frame_connected_bluetooth_devices.cc
index e18cb45..f6ff072 100644
--- a/content/browser/bluetooth/frame_connected_bluetooth_devices.cc
+++ b/content/browser/bluetooth/frame_connected_bluetooth_devices.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/bluetooth/frame_connected_bluetooth_devices.h"
 
+#include "base/containers/contains.h"
 #include "base/optional.h"
 #include "base/strings/string_util.h"
 #include "content/browser/web_contents/web_contents_impl.h"
diff --git a/content/browser/bluetooth/web_bluetooth_service_impl.cc b/content/browser/bluetooth/web_bluetooth_service_impl.cc
index e5227d6d..12836e99b 100644
--- a/content/browser/bluetooth/web_bluetooth_service_impl.cc
+++ b/content/browser/bluetooth/web_bluetooth_service_impl.cc
@@ -16,6 +16,7 @@
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
+#include "base/containers/contains.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 4c69bfb3..8e68d5b 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -83,6 +83,7 @@
 #include "content/browser/scheduler/responsiveness/watcher.h"
 #include "content/browser/screenlock_monitor/screenlock_monitor.h"
 #include "content/browser/screenlock_monitor/screenlock_monitor_device_source.h"
+#include "content/browser/service_sandbox_type.h"
 #include "content/browser/sms/sms_provider.h"
 #include "content/browser/speech/speech_recognition_manager_impl.h"
 #include "content/browser/speech/tts_controller_impl.h"
diff --git a/content/browser/browsing_data/browsing_data_filter_builder_impl.cc b/content/browser/browsing_data/browsing_data_filter_builder_impl.cc
index b964d6a..74b80dd 100644
--- a/content/browser/browsing_data/browsing_data_filter_builder_impl.cc
+++ b/content/browser/browsing_data/browsing_data_filter_builder_impl.cc
@@ -9,6 +9,7 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/containers/contains.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 
 using net::registry_controlled_domains::GetDomainAndRegistry;
diff --git a/content/browser/browsing_data/browsing_data_remover_impl_browsertest.cc b/content/browser/browsing_data/browsing_data_remover_impl_browsertest.cc
index 72322951..7ee579ef 100644
--- a/content/browser/browsing_data/browsing_data_remover_impl_browsertest.cc
+++ b/content/browser/browsing_data/browsing_data_remover_impl_browsertest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "base/bind.h"
+#include "base/containers/contains.h"
 #include "base/files/file_path.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/bind.h"
diff --git a/content/browser/buckets/bucket_manager_host.cc b/content/browser/buckets/bucket_manager_host.cc
index 5407242f..5a70218 100644
--- a/content/browser/buckets/bucket_manager_host.cc
+++ b/content/browser/buckets/bucket_manager_host.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/buckets/bucket_manager_host.h"
 
+#include "base/containers/contains.h"
 #include "base/types/pass_key.h"
 #include "content/browser/buckets/bucket_manager.h"
 
diff --git a/content/browser/child_process_security_policy_impl.cc b/content/browser/child_process_security_policy_impl.cc
index 8ed2f63..f487751 100644
--- a/content/browser/child_process_security_policy_impl.cc
+++ b/content/browser/child_process_security_policy_impl.cc
@@ -10,6 +10,7 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/containers/contains.h"
 #include "base/debug/crash_logging.h"
 #include "base/debug/dump_without_crashing.h"
 #include "base/feature_list.h"
diff --git a/content/browser/devtools/browser_devtools_agent_host.cc b/content/browser/devtools/browser_devtools_agent_host.cc
index cdad4cb9..6741376 100644
--- a/content/browser/devtools/browser_devtools_agent_host.cc
+++ b/content/browser/devtools/browser_devtools_agent_host.cc
@@ -102,7 +102,7 @@
         socket_callback_, tethering_task_runner_));
   }
   session->AddHandler(
-      std::make_unique<protocol::TracingHandler>(nullptr, GetIOContext()));
+      std::make_unique<protocol::TracingHandler>(GetIOContext()));
   return true;
 }
 
diff --git a/content/browser/devtools/protocol/tracing_handler.cc b/content/browser/devtools/protocol/tracing_handler.cc
index 7b8a791..31e7622 100644
--- a/content/browser/devtools/protocol/tracing_handler.cc
+++ b/content/browser/devtools/protocol/tracing_handler.cc
@@ -509,11 +509,9 @@
   base::WeakPtrFactory<PerfettoTracingSession> weak_factory_{this};
 };
 
-TracingHandler::TracingHandler(FrameTreeNode* frame_tree_node,
-                               DevToolsIOContext* io_context)
+TracingHandler::TracingHandler(DevToolsIOContext* io_context)
     : DevToolsDomainHandler(Tracing::Metainfo::domainName),
       io_context_(io_context),
-      frame_tree_node_(frame_tree_node),
       did_initiate_recording_(false),
       return_as_stream_(false),
       gzip_compression_(false),
@@ -541,6 +539,7 @@
 
 void TracingHandler::SetRenderer(int process_host_id,
                                  RenderFrameHostImpl* frame_host) {
+  frame_host_ = frame_host;
   if (!video_consumer_ || !frame_host)
     return;
   video_consumer_->SetFrameSinkId(
@@ -851,7 +850,7 @@
 void TracingHandler::SetupProcessFilter(
     base::ProcessId gpu_pid,
     RenderFrameHost* new_render_frame_host) {
-  if (!frame_tree_node_)
+  if (!frame_host_)
     return;
 
   base::ProcessId browser_pid = base::Process::Current().Pid();
@@ -863,10 +862,9 @@
   if (new_render_frame_host)
     AppendProcessId(new_render_frame_host, &included_process_ids);
 
-  for (FrameTreeNode* node :
-       frame_tree_node_->frame_tree()->SubtreeNodes(frame_tree_node_)) {
-    RenderFrameHost* frame_host = node->current_frame_host();
-    if (frame_host)
+  DCHECK(!frame_host_->GetParent());
+  for (FrameTreeNode* node : frame_host_->frame_tree()->Nodes()) {
+    if (RenderFrameHost* frame_host = node->current_frame_host())
       AppendProcessId(frame_host, &included_process_ids);
   }
 
@@ -901,7 +899,7 @@
     bool gzip_compression,
     bool proto_format,
     perfetto::BackendType tracing_backend) {
-  if (frame_tree_node_ != nullptr)
+  if (frame_host_ != nullptr)
     return;
   auto* startup_config = tracing::TraceStartupConfig::GetInstance();
   if (!startup_config->AttemptAdoptBySessionOwner(
@@ -1121,13 +1119,13 @@
 
 void TracingHandler::EmitFrameTree() {
   auto data = std::make_unique<base::trace_event::TracedValue>();
-  if (frame_tree_node_) {
-    data->SetInteger("frameTreeNodeId", frame_tree_node_->frame_tree_node_id());
+  if (frame_host_) {
+    DCHECK(!frame_host_->GetParent());
+    data->SetInteger("frameTreeNodeId",
+                     frame_host_->frame_tree_node()->frame_tree_node_id());
     data->SetBoolean("persistentIds", true);
     data->BeginArray("frames");
-    FrameTree::NodeRange subtree =
-        frame_tree_node_->frame_tree()->SubtreeNodes(frame_tree_node_);
-    for (FrameTreeNode* node : subtree) {
+    for (FrameTreeNode* node : frame_host_->frame_tree()->Nodes()) {
       data->BeginDictionary();
       FillFrameData(data.get(), node, node->current_frame_host(),
                     node->current_url());
diff --git a/content/browser/devtools/protocol/tracing_handler.h b/content/browser/devtools/protocol/tracing_handler.h
index d5b55451..cd4f2b8 100644
--- a/content/browser/devtools/protocol/tracing_handler.h
+++ b/content/browser/devtools/protocol/tracing_handler.h
@@ -40,7 +40,6 @@
 class DevToolsAgentHostImpl;
 class DevToolsVideoConsumer;
 class DevToolsIOContext;
-class FrameTreeNode;
 class NavigationRequest;
 class RenderFrameHost;
 class RenderProcessHost;
@@ -49,8 +48,7 @@
 
 class TracingHandler : public DevToolsDomainHandler, public Tracing::Backend {
  public:
-  CONTENT_EXPORT TracingHandler(FrameTreeNode* frame_tree_node,
-                                DevToolsIOContext* io_context);
+  CONTENT_EXPORT explicit TracingHandler(DevToolsIOContext* io_context);
   CONTENT_EXPORT ~TracingHandler() override;
 
   static std::vector<TracingHandler*> ForAgentHost(DevToolsAgentHostImpl* host);
@@ -150,7 +148,9 @@
 
   std::unique_ptr<Tracing::Frontend> frontend_;
   DevToolsIOContext* io_context_;
-  FrameTreeNode* frame_tree_node_;
+  // This will be null in agents not attached to a frame host,
+  // or while WebContents is detached.
+  RenderFrameHostImpl* frame_host_ = nullptr;
   bool did_initiate_recording_;
   bool return_as_stream_;
   bool gzip_compression_;
diff --git a/content/browser/devtools/protocol/tracing_handler_unittest.cc b/content/browser/devtools/protocol/tracing_handler_unittest.cc
index 676e419..7530a42 100644
--- a/content/browser/devtools/protocol/tracing_handler_unittest.cc
+++ b/content/browser/devtools/protocol/tracing_handler_unittest.cc
@@ -74,7 +74,7 @@
 class TracingHandlerTest : public testing::Test {
  public:
   void SetUp() override {
-    tracing_handler_ = std::make_unique<TracingHandler>(nullptr, nullptr);
+    tracing_handler_ = std::make_unique<TracingHandler>(nullptr);
   }
 
   void TearDown() override { tracing_handler_.reset(); }
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index 40499c0..c1bc41af 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -342,8 +342,8 @@
       session->GetClient()->MayReadLocalFiles()));
   session->AddHandler(std::make_unique<protocol::SecurityHandler>());
   if (!frame_tree_node_ || !frame_tree_node_->parent()) {
-    session->AddHandler(std::make_unique<protocol::TracingHandler>(
-        frame_tree_node_, GetIOContext()));
+    session->AddHandler(
+        std::make_unique<protocol::TracingHandler>(GetIOContext()));
   }
   session->AddHandler(std::make_unique<protocol::LogHandler>());
 #if !defined(OS_ANDROID)
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc
index b448fbc6..86081010 100644
--- a/content/browser/download/download_browsertest.cc
+++ b/content/browser/download/download_browsertest.cc
@@ -13,6 +13,7 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/containers/contains.h"
 #include "base/feature_list.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
diff --git a/content/browser/download/download_manager_impl_unittest.cc b/content/browser/download/download_manager_impl_unittest.cc
index af1bea9..a289f01 100644
--- a/content/browser/download/download_manager_impl_unittest.cc
+++ b/content/browser/download/download_manager_impl_unittest.cc
@@ -806,15 +806,24 @@
   ASSERT_FALSE(download_manager_->GetDownloadByGuid(kGuid));
 }
 
+class DownloadManagerWithExpirationTest : public DownloadManagerTest {
+ public:
+  DownloadManagerWithExpirationTest() {
+    std::map<std::string, std::string> params = {
+        {download::kExpiredDownloadDeleteTimeFinchKey,
+         base::NumberToString(1)}};
+    scoped_feature_list_.InitAndEnableFeatureWithParameters(
+        download::features::kDeleteExpiredDownloads, params);
+  }
+  ~DownloadManagerWithExpirationTest() override = default;
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
 // Verifies that expired canceled or interrupted downloads are deleted
 // correctly.
-TEST_F(DownloadManagerTest, DeleteExpiredDownload) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  std::map<std::string, std::string> params = {
-      {download::kExpiredDownloadDeleteTimeFinchKey, base::NumberToString(1)}};
-  scoped_feature_list.InitAndEnableFeatureWithParameters(
-      download::features::kDeleteExpiredDownloads, params);
-
+TEST_F(DownloadManagerWithExpirationTest, DeleteExpiredDownload) {
   std::vector<GURL> url_chain;
   url_chain.emplace_back("http://example.com/1.zip");
   auto expired_start_time = base::Time::Now() - base::TimeDelta::FromDays(10);
diff --git a/content/browser/file_system_access/file_system_access_file_writer_impl_unittest.cc b/content/browser/file_system_access/file_system_access_file_writer_impl_unittest.cc
index 0266b7b6..be08631 100644
--- a/content/browser/file_system_access/file_system_access_file_writer_impl_unittest.cc
+++ b/content/browser/file_system_access/file_system_access_file_writer_impl_unittest.cc
@@ -11,6 +11,7 @@
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
+#include "base/containers/contains.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/guid.h"
 #include "base/strings/string_number_conversions.h"
diff --git a/content/browser/file_system_access/file_system_chooser_browsertest.cc b/content/browser/file_system_access/file_system_chooser_browsertest.cc
index a19b8f0..2123cef 100644
--- a/content/browser/file_system_access/file_system_chooser_browsertest.cc
+++ b/content/browser/file_system_access/file_system_chooser_browsertest.cc
@@ -5,6 +5,7 @@
 #include <string>
 #include <vector>
 
+#include "base/containers/contains.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
diff --git a/content/browser/file_system_access/file_system_chooser_unittest.cc b/content/browser/file_system_access/file_system_chooser_unittest.cc
index 0b6108751..aea995b 100644
--- a/content/browser/file_system_access/file_system_chooser_unittest.cc
+++ b/content/browser/file_system_access/file_system_chooser_unittest.cc
@@ -5,6 +5,7 @@
 #include "content/browser/file_system_access/file_system_chooser.h"
 
 #include "base/callback_helpers.h"
+#include "base/containers/contains.h"
 #include "base/files/file_path.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
diff --git a/content/browser/find_request_manager.cc b/content/browser/find_request_manager.cc
index 81fdab3..8edc4a0 100644
--- a/content/browser/find_request_manager.cc
+++ b/content/browser/find_request_manager.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/containers/contains.h"
 #include "base/containers/queue.h"
 #include "content/browser/find_in_page_client.h"
 #include "content/browser/renderer_host/render_frame_host_impl.h"
diff --git a/content/browser/hid/hid_service.cc b/content/browser/hid/hid_service.cc
index 5506349d..f3cea98 100644
--- a/content/browser/hid/hid_service.cc
+++ b/content/browser/hid/hid_service.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/callback_helpers.h"
+#include "base/containers/contains.h"
 #include "base/debug/stack_trace.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/content_browser_client.h"
diff --git a/content/browser/host_zoom_map_impl.cc b/content/browser/host_zoom_map_impl.cc
index 247e738..34bc4797 100644
--- a/content/browser/host_zoom_map_impl.cc
+++ b/content/browser/host_zoom_map_impl.cc
@@ -9,6 +9,7 @@
 #include <memory>
 #include <utility>
 
+#include "base/containers/contains.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/default_clock.h"
diff --git a/content/browser/interest_group/ad_auction_service_impl.cc b/content/browser/interest_group/ad_auction_service_impl.cc
index 70666796..8e64ed7 100644
--- a/content/browser/interest_group/ad_auction_service_impl.cc
+++ b/content/browser/interest_group/ad_auction_service_impl.cc
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/check.h"
+#include "base/containers/contains.h"
 #include "base/optional.h"
 #include "base/strings/stringprintf.h"
 #include "content/browser/devtools/devtools_instrumentation.h"
diff --git a/content/browser/interest_group/interest_group_browsertest.cc b/content/browser/interest_group/interest_group_browsertest.cc
index 565f82e..1e29d7e 100644
--- a/content/browser/interest_group/interest_group_browsertest.cc
+++ b/content/browser/interest_group/interest_group_browsertest.cc
@@ -8,6 +8,7 @@
 
 #include "base/callback.h"
 #include "base/callback_forward.h"
+#include "base/containers/contains.h"
 #include "base/containers/flat_set.h"
 #include "base/optional.h"
 #include "base/run_loop.h"
diff --git a/content/browser/media/active_media_session_controller.cc b/content/browser/media/active_media_session_controller.cc
index 2818177..8cb0e28 100644
--- a/content/browser/media/active_media_session_controller.cc
+++ b/content/browser/media/active_media_session_controller.cc
@@ -8,6 +8,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/containers/contains.h"
 #include "base/metrics/histogram_macros.h"
 #include "content/browser/browser_main_loop.h"
 #include "content/browser/media/media_keys_listener_manager_impl.h"
diff --git a/content/browser/media/audible_metrics.cc b/content/browser/media/audible_metrics.cc
index 13b7569..4305d4d5 100644
--- a/content/browser/media/audible_metrics.cc
+++ b/content/browser/media/audible_metrics.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "base/containers/contains.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/time/default_tick_clock.h"
 
diff --git a/content/browser/media/session/media_session_browsertest.cc b/content/browser/media/session/media_session_browsertest.cc
index 68ee509e..76e6ba5 100644
--- a/content/browser/media/session/media_session_browsertest.cc
+++ b/content/browser/media/session/media_session_browsertest.cc
@@ -6,6 +6,7 @@
 
 #include "base/callback_helpers.h"
 #include "base/command_line.h"
+#include "base/containers/contains.h"
 #include "base/optional.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc
index 66f477a2..c8161892 100644
--- a/content/browser/navigation_browsertest.cc
+++ b/content/browser/navigation_browsertest.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/command_line.h"
+#include "base/containers/contains.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/guid.h"
diff --git a/content/browser/net/trust_token_browsertest.cc b/content/browser/net/trust_token_browsertest.cc
index 3d52bfd0..00555a57 100644
--- a/content/browser/net/trust_token_browsertest.cc
+++ b/content/browser/net/trust_token_browsertest.cc
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/base64.h"
+#include "base/containers/contains.h"
 #include "base/run_loop.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_piece.h"
diff --git a/content/browser/net/trust_token_parameters_browsertest.cc b/content/browser/net/trust_token_parameters_browsertest.cc
index 5785989f..6f8b1f1c 100644
--- a/content/browser/net/trust_token_parameters_browsertest.cc
+++ b/content/browser/net/trust_token_parameters_browsertest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/containers/contains.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/bind.h"
 #include "base/test/scoped_feature_list.h"
diff --git a/content/browser/payments/payment_app_database.cc b/content/browser/payments/payment_app_database.cc
index 7323edf7..836a2eb9 100644
--- a/content/browser/payments/payment_app_database.cc
+++ b/content/browser/payments/payment_app_database.cc
@@ -9,6 +9,7 @@
 
 #include "base/base64.h"
 #include "base/bind.h"
+#include "base/containers/contains.h"
 #include "base/optional.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
diff --git a/content/browser/prerender/prerender_browsertest.cc b/content/browser/prerender/prerender_browsertest.cc
index 4f7199a1..4ad502e 100644
--- a/content/browser/prerender/prerender_browsertest.cc
+++ b/content/browser/prerender/prerender_browsertest.cc
@@ -808,6 +808,27 @@
   TestHostPrerenderingState(GetUrl("/page_with_blank_iframe.html"));
 }
 
+// Tests that an inner WebContents can be attached in a prerendered page.
+IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, ActivatePageWithInnerContents) {
+  const GURL kInitialUrl = GetUrl("/prerender/add_prerender.html");
+  const GURL kPrerenderingUrl = GetUrl("/page_with_blank_iframe.html");
+  const GURL kInnerContentsUrl = GetUrl("/title1.html");
+  ASSERT_TRUE(NavigateToURL(shell(), kInitialUrl));
+
+  const int host_id = AddPrerender(kPrerenderingUrl);
+  RenderFrameHostImpl* prerendered_render_frame_host =
+      GetPrerenderedMainFrameHost(host_id);
+  WebContentsImpl* inner_contents =
+      static_cast<WebContentsImpl*>(CreateAndAttachInnerContents(
+          prerendered_render_frame_host->child_at(0)->current_frame_host()));
+  ASSERT_TRUE(NavigateToURLFromRenderer(inner_contents, kInnerContentsUrl));
+
+  NavigatePrimaryPage(kPrerenderingUrl);
+  EXPECT_EQ(web_contents()->GetURL(), kPrerenderingUrl);
+  EXPECT_EQ(GetRequestCount(kPrerenderingUrl), 1);
+  EXPECT_EQ(GetRequestCount(kInnerContentsUrl), 1);
+}
+
 // Tests that RenderFrameHost::ForEachRenderFrameHost behaves correctly when
 // prerendering.
 IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, ForEachRenderFrameHost) {
diff --git a/content/browser/quota/quota_change_dispatcher_unittest.cc b/content/browser/quota/quota_change_dispatcher_unittest.cc
index c4cbf7d..600b2612 100644
--- a/content/browser/quota/quota_change_dispatcher_unittest.cc
+++ b/content/browser/quota/quota_change_dispatcher_unittest.cc
@@ -8,6 +8,7 @@
 
 #include "base/barrier_closure.h"
 #include "base/command_line.h"
+#include "base/containers/contains.h"
 #include "base/run_loop.h"
 #include "base/task/post_task.h"
 #include "base/task/task_traits.h"
diff --git a/content/browser/renderer_host/frame_tree_node_blame_context_unittest.cc b/content/browser/renderer_host/frame_tree_node_blame_context_unittest.cc
index ac6ed20..b8f0838 100644
--- a/content/browser/renderer_host/frame_tree_node_blame_context_unittest.cc
+++ b/content/browser/renderer_host/frame_tree_node_blame_context_unittest.cc
@@ -9,6 +9,7 @@
 #include <set>
 #include <string>
 
+#include "base/containers/contains.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/trace_event_analyzer.h"
 #include "base/trace_event/traced_value.h"
diff --git a/content/browser/renderer_host/media/media_devices_manager.cc b/content/browser/renderer_host/media/media_devices_manager.cc
index 2ee2179f6..20046d2 100644
--- a/content/browser/renderer_host/media/media_devices_manager.cc
+++ b/content/browser/renderer_host/media/media_devices_manager.cc
@@ -14,6 +14,7 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/containers/contains.h"
 #include "base/location.h"
 #include "base/sequence_checker.h"
 #include "base/stl_util.h"
diff --git a/content/browser/renderer_host/media/media_devices_manager_unittest.cc b/content/browser/renderer_host/media/media_devices_manager_unittest.cc
index efd860e..48b6fe5 100644
--- a/content/browser/renderer_host/media/media_devices_manager_unittest.cc
+++ b/content/browser/renderer_host/media/media_devices_manager_unittest.cc
@@ -9,6 +9,7 @@
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
+#include "base/containers/contains.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
diff --git a/content/browser/renderer_host/media/video_capture_controller.cc b/content/browser/renderer_host/media/video_capture_controller.cc
index 575f9f7..c9163ed 100644
--- a/content/browser/renderer_host/media/video_capture_controller.cc
+++ b/content/browser/renderer_host/media/video_capture_controller.cc
@@ -12,6 +12,7 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/containers/contains.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "build/build_config.h"
diff --git a/content/browser/renderer_host/media/video_capture_host.cc b/content/browser/renderer_host/media/video_capture_host.cc
index cf98b8cc..176bdb0 100644
--- a/content/browser/renderer_host/media/video_capture_host.cc
+++ b/content/browser/renderer_host/media/video_capture_host.cc
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
+#include "base/containers/contains.h"
 #include "content/browser/browser_main_loop.h"
 #include "content/browser/renderer_host/media/media_stream_manager.h"
 #include "content/browser/renderer_host/media/video_capture_manager.h"
diff --git a/content/browser/renderer_host/media/video_capture_manager.cc b/content/browser/renderer_host/media/video_capture_manager.cc
index 4f2e302..26407a4 100644
--- a/content/browser/renderer_host/media/video_capture_manager.cc
+++ b/content/browser/renderer_host/media/video_capture_manager.cc
@@ -12,6 +12,7 @@
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/command_line.h"
+#include "base/containers/contains.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_functions.h"
diff --git a/content/browser/renderer_host/plugin_registry_impl.cc b/content/browser/renderer_host/plugin_registry_impl.cc
index a6d6188f..68ccb16a 100644
--- a/content/browser/renderer_host/plugin_registry_impl.cc
+++ b/content/browser/renderer_host/plugin_registry_impl.cc
@@ -5,6 +5,7 @@
 #include "content/browser/renderer_host/plugin_registry_impl.h"
 
 #include "base/bind.h"
+#include "base/containers/contains.h"
 #include "base/no_destructor.h"
 #include "content/browser/plugin_service_impl.h"
 #include "content/public/browser/content_browser_client.h"
diff --git a/content/browser/renderer_host/raw_clipboard_host_impl.cc b/content/browser/renderer_host/raw_clipboard_host_impl.cc
index 2c965cb..da26b77 100644
--- a/content/browser/renderer_host/raw_clipboard_host_impl.cc
+++ b/content/browser/renderer_host/raw_clipboard_host_impl.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "base/bind.h"
+#include "base/containers/contains.h"
 #include "base/i18n/number_formatting.h"
 #include "base/memory/ptr_util.h"
 #include "content/browser/permissions/permission_controller_impl.h"
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index a252a48..6079854 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -14,6 +14,7 @@
 #include "base/callback_helpers.h"
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
+#include "base/containers/contains.h"
 #include "base/containers/queue.h"
 #include "base/debug/alias.h"
 #include "base/debug/crash_logging.h"
diff --git a/content/browser/renderer_host/render_frame_proxy_host.cc b/content/browser/renderer_host/render_frame_proxy_host.cc
index 72e0067..5dd7f71 100644
--- a/content/browser/renderer_host/render_frame_proxy_host.cc
+++ b/content/browser/renderer_host/render_frame_proxy_host.cc
@@ -11,6 +11,7 @@
 
 #include "base/callback.h"
 #include "base/containers/circular_deque.h"
+#include "base/containers/contains.h"
 #include "base/hash/hash.h"
 #include "base/lazy_instance.h"
 #include "base/no_destructor.h"
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 0d3cf79..8a3b9fa4 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -22,6 +22,7 @@
 #include "base/clang_profiling_buildflags.h"
 #include "base/command_line.h"
 #include "base/containers/adapters.h"
+#include "base/containers/contains.h"
 #include "base/debug/alias.h"
 #include "base/debug/crash_logging.h"
 #include "base/debug/dump_without_crashing.h"
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 88f3f760..2dc0eb92 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -18,6 +18,7 @@
 #include "base/callback_helpers.h"
 #include "base/check.h"
 #include "base/command_line.h"
+#include "base/containers/contains.h"
 #include "base/debug/alias.h"
 #include "base/debug/dump_without_crashing.h"
 #include "base/files/file_path.h"
diff --git a/content/browser/renderer_host/render_widget_host_view_base.cc b/content/browser/renderer_host/render_widget_host_view_base.cc
index fe8443d..890aa9ee 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.cc
+++ b/content/browser/renderer_host/render_widget_host_view_base.cc
@@ -5,6 +5,7 @@
 #include "content/browser/renderer_host/render_widget_host_view_base.h"
 
 #include "base/bind.h"
+#include "base/containers/contains.h"
 #include "base/logging.h"
 #include "base/unguessable_token.h"
 #include "build/build_config.h"
diff --git a/content/browser/service_sandbox_type.h b/content/browser/service_sandbox_type.h
index d64c355..8da72d4 100644
--- a/content/browser/service_sandbox_type.h
+++ b/content/browser/service_sandbox_type.h
@@ -42,6 +42,18 @@
              : sandbox::policy::SandboxType::kNoSandbox;
 }
 
+// data_decoder::mojom::DataDecoderService
+namespace data_decoder {
+namespace mojom {
+class DataDecoderService;
+}
+}  // namespace data_decoder
+template <>
+inline sandbox::policy::SandboxType
+content::GetServiceSandboxType<data_decoder::mojom::DataDecoderService>() {
+  return sandbox::policy::SandboxType::kService;
+}
+
 // media::mojom::CdmService
 namespace media {
 namespace mojom {
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc
index d773bcd9..4a1b904 100644
--- a/content/browser/service_worker/embedded_worker_instance.cc
+++ b/content/browser/service_worker/embedded_worker_instance.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/callback_helpers.h"
+#include "base/containers/contains.h"
 #include "base/feature_list.h"
 #include "base/macros.h"
 #include "base/metrics/histogram_macros.h"
diff --git a/content/browser/service_worker/service_worker_container_host.cc b/content/browser/service_worker/service_worker_container_host.cc
index 0a9f181..bda4e04 100644
--- a/content/browser/service_worker/service_worker_container_host.cc
+++ b/content/browser/service_worker/service_worker_container_host.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/callback_helpers.h"
+#include "base/containers/contains.h"
 #include "base/guid.h"
 #include "base/strings/stringprintf.h"
 #include "components/services/storage/public/cpp/storage_key.h"
diff --git a/content/browser/service_worker/service_worker_context_core_unittest.cc b/content/browser/service_worker/service_worker_context_core_unittest.cc
index 026d20f1..af564f0 100644
--- a/content/browser/service_worker/service_worker_context_core_unittest.cc
+++ b/content/browser/service_worker/service_worker_context_core_unittest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "base/callback_helpers.h"
+#include "base/containers/contains.h"
 #include "base/test/bind.h"
 #include "components/services/storage/public/cpp/storage_key.h"
 #include "content/browser/service_worker/embedded_worker_test_helper.h"
diff --git a/content/browser/service_worker/service_worker_context_unittest.cc b/content/browser/service_worker/service_worker_context_unittest.cc
index fd9fdaee..2b9febc 100644
--- a/content/browser/service_worker/service_worker_context_unittest.cc
+++ b/content/browser/service_worker/service_worker_context_unittest.cc
@@ -9,6 +9,7 @@
 #include <memory>
 
 #include "base/bind.h"
+#include "base/containers/contains.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/run_loop.h"
 #include "base/scoped_observation.h"
diff --git a/content/browser/service_worker/service_worker_process_manager.cc b/content/browser/service_worker/service_worker_process_manager.cc
index 26eb47a..7a5a45f 100644
--- a/content/browser/service_worker/service_worker_process_manager.cc
+++ b/content/browser/service_worker/service_worker_process_manager.cc
@@ -9,6 +9,7 @@
 #include <algorithm>
 #include <utility>
 
+#include "base/containers/contains.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/browser/site_instance_impl.h"
diff --git a/content/browser/service_worker/service_worker_script_cache_map.cc b/content/browser/service_worker/service_worker_script_cache_map.cc
index f215974..2a3ece3 100644
--- a/content/browser/service_worker/service_worker_script_cache_map.cc
+++ b/content/browser/service_worker/service_worker_script_cache_map.cc
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #include "base/check_op.h"
+#include "base/containers/contains.h"
 #include "components/services/storage/public/cpp/storage_key.h"
 #include "content/browser/service_worker/service_worker_consts.h"
 #include "content/browser/service_worker/service_worker_context_core.h"
diff --git a/content/browser/site_instance_impl.cc b/content/browser/site_instance_impl.cc
index a2f1859..00033b6 100644
--- a/content/browser/site_instance_impl.cc
+++ b/content/browser/site_instance_impl.cc
@@ -8,6 +8,7 @@
 #include <tuple>
 
 #include "base/command_line.h"
+#include "base/containers/contains.h"
 #include "base/debug/crash_logging.h"
 #include "base/debug/dump_without_crashing.h"
 #include "base/lazy_instance.h"
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 65810aeb..8fe0360 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -22,6 +22,7 @@
 #include "base/callback.h"
 #include "base/callback_helpers.h"
 #include "base/command_line.h"
+#include "base/containers/contains.h"
 #include "base/feature_list.h"
 #include "base/json/json_reader.h"
 #include "base/location.h"
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index b30c367c..88f575bd 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -16,6 +16,7 @@
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/command_line.h"
+#include "base/containers/contains.h"
 #include "base/containers/flat_set.h"
 #include "base/feature_list.h"
 #include "base/location.h"
diff --git a/content/browser/storage_partition_impl_unittest.cc b/content/browser/storage_partition_impl_unittest.cc
index 59ff210..ab7cf844 100644
--- a/content/browser/storage_partition_impl_unittest.cc
+++ b/content/browser/storage_partition_impl_unittest.cc
@@ -13,6 +13,7 @@
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
+#include "base/containers/contains.h"
 #include "base/files/file_util.h"
 #include "base/location.h"
 #include "base/run_loop.h"
diff --git a/content/browser/tracing/background_tracing_active_scenario.cc b/content/browser/tracing/background_tracing_active_scenario.cc
index 7af1a70..95bede30 100644
--- a/content/browser/tracing/background_tracing_active_scenario.cc
+++ b/content/browser/tracing/background_tracing_active_scenario.cc
@@ -363,9 +363,7 @@
   tracing_timer_.reset();
 
   // |callback| is only run once, but we need 2 callbacks pointing to it.
-  auto run_callback = callback
-                          ? base::AdaptCallbackForRepeating(std::move(callback))
-                          : base::NullCallback();
+  auto split_callback = base::SplitOnceCallback(std::move(callback));
 
   base::OnceClosure on_begin_finalization_success = base::BindOnce(
       [](base::WeakPtr<BackgroundTracingActiveScenario> weak_this,
@@ -383,7 +381,7 @@
               std::move(callback), /*is_allowed_finalization=*/true);
         }
       },
-      weak_ptr_factory_.GetWeakPtr(), run_callback);
+      weak_ptr_factory_.GetWeakPtr(), std::move(split_callback.first));
 
   base::OnceClosure on_begin_finalization_failure = base::BindOnce(
       [](base::WeakPtr<BackgroundTracingActiveScenario> weak_this,
@@ -400,7 +398,7 @@
           std::move(callback).Run(false);
         }
       },
-      weak_ptr_factory_.GetWeakPtr(), run_callback);
+      weak_ptr_factory_.GetWeakPtr(), std::move(split_callback.second));
 
   tracing_session_->BeginFinalizing(std::move(on_begin_finalization_success),
                                     std::move(on_begin_finalization_failure),
diff --git a/content/browser/tracing/tracing_ui.cc b/content/browser/tracing/tracing_ui.cc
index 851c566..dcfee22 100644
--- a/content/browser/tracing/tracing_ui.cc
+++ b/content/browser/tracing/tracing_ui.cc
@@ -214,11 +214,10 @@
   // to take ownership of |callback| even though it won't call |callback|
   // sometimes, as it binds |callback| into other callbacks before it makes that
   // decision. So we must give it one copy and keep one ourselves.
-  auto repeating_callback =
-      base::AdaptCallbackForRepeating(std::move(callback));
-  if (!OnBeginJSONRequest(path, repeating_callback)) {
+  auto split_callback = base::SplitOnceCallback(std::move(callback));
+  if (!OnBeginJSONRequest(path, std::move(split_callback.first))) {
     std::string error("##ERROR##");
-    std::move(repeating_callback)
+    std::move(split_callback.second)
         .Run(base::RefCountedString::TakeString(&error));
   }
 }
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 44a3f38..9130449 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -15,6 +15,7 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/containers/contains.h"
 #include "base/containers/flat_set.h"
 #include "base/debug/dump_without_crashing.h"
 #include "base/feature_list.h"
@@ -2200,7 +2201,7 @@
   DCHECK(!inner_web_contents_impl->node_.outer_web_contents());
   auto* render_frame_host_impl =
       static_cast<RenderFrameHostImpl*>(render_frame_host);
-  DCHECK_EQ(&frame_tree_, render_frame_host_impl->frame_tree());
+  DCHECK_EQ(this, render_frame_host_impl->delegate()->GetAsWebContents());
 
   // Mark |render_frame_host_impl| as outer delegate frame.
   render_frame_host_impl->SetIsOuterDelegateFrame(true);
@@ -6791,7 +6792,7 @@
 
   FrameTreeNode* outer_node =
       FrameTreeNode::GloballyFindByID(GetOuterDelegateFrameTreeNodeId());
-  outer_contents->frame_tree_.SetFocusedFrame(outer_node, nullptr);
+  outer_node->frame_tree()->SetFocusedFrame(outer_node, nullptr);
 
   // For a browser initiated focus change, let embedding renderer know of the
   // change. Otherwise, if the currently focused element is just across a
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc
index ec63eaa12..0bdbdc3 100644
--- a/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/callback_helpers.h"
 #include "base/check.h"
 #include "base/command_line.h"
+#include "base/containers/contains.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/content/browser/webauth/authenticator_common.cc b/content/browser/webauth/authenticator_common.cc
index 1df356cf..198f70b7 100644
--- a/content/browser/webauth/authenticator_common.cc
+++ b/content/browser/webauth/authenticator_common.cc
@@ -13,6 +13,7 @@
 #include "base/bind.h"
 #include "base/check.h"
 #include "base/command_line.h"
+#include "base/containers/contains.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/notreached.h"
 #include "base/rand_util.h"
diff --git a/content/child/blink_platform_impl.cc b/content/child/blink_platform_impl.cc
index 4e060554..a1e434b 100644
--- a/content/child/blink_platform_impl.cc
+++ b/content/child/blink_platform_impl.cc
@@ -44,6 +44,7 @@
 #include "net/base/net_errors.h"
 #include "services/network/public/cpp/features.h"
 #include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
+#include "third_party/blink/public/platform/user_metrics_action.h"
 #include "third_party/blink/public/platform/web_data.h"
 #include "third_party/blink/public/platform/web_security_origin.h"
 #include "third_party/blink/public/platform/web_string.h"
diff --git a/content/common/font_list_fuchsia.cc b/content/common/font_list_fuchsia.cc
index a8c5b600..54778cf7 100644
--- a/content/common/font_list_fuchsia.cc
+++ b/content/common/font_list_fuchsia.cc
@@ -4,12 +4,14 @@
 
 #include "content/common/font_list.h"
 
+#include <memory>
+
 #include "base/values.h"
 
 namespace content {
 
 std::unique_ptr<base::ListValue> GetFontList_SlowBlocking() {
-  return std::unique_ptr<base::ListValue>(new base::ListValue);
+  return std::make_unique<base::ListValue>();
 }
 
 }  // namespace content
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h
index 9663a9a5..a328efa 100644
--- a/content/public/browser/web_contents.h
+++ b/content/public/browser/web_contents.h
@@ -653,7 +653,7 @@
   virtual void DispatchBeforeUnload(bool auto_cancel) = 0;
 
   // Attaches |inner_web_contents| to the container frame |render_frame_host|,
-  // which should be in this WebContents' FrameTree. This outer WebContents
+  // which must be in a FrameTree for this WebContents. This outer WebContents
   // takes ownership of |inner_web_contents|.
   // Note: |render_frame_host| will be swapped out and destroyed during the
   // process. Generally a frame same-process with its parent is the right choice
diff --git a/content/renderer/categorized_worker_pool.cc b/content/renderer/categorized_worker_pool.cc
index c80d269..93c021f 100644
--- a/content/renderer/categorized_worker_pool.cc
+++ b/content/renderer/categorized_worker_pool.cc
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/containers/contains.h"
 #include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
diff --git a/content/shell/browser/shell_devtools_bindings.cc b/content/shell/browser/shell_devtools_bindings.cc
index 46574b8..5b2f537 100644
--- a/content/shell/browser/shell_devtools_bindings.cc
+++ b/content/shell/browser/shell_devtools_bindings.cc
@@ -11,6 +11,7 @@
 #include "base/base64.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
+#include "base/containers/contains.h"
 #include "base/guid.h"
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
diff --git a/content/shell/browser/shell_platform_delegate_android.cc b/content/shell/browser/shell_platform_delegate_android.cc
index 4ca23d0..1a1490b 100644
--- a/content/shell/browser/shell_platform_delegate_android.cc
+++ b/content/shell/browser/shell_platform_delegate_android.cc
@@ -9,6 +9,7 @@
 #include "base/android/jni_string.h"
 #include "base/android/scoped_java_ref.h"
 #include "base/command_line.h"
+#include "base/containers/contains.h"
 #include "base/notreached.h"
 #include "base/strings/string_piece.h"
 #include "content/public/browser/render_widget_host_view.h"
diff --git a/content/shell/browser/shell_platform_delegate_aura.cc b/content/shell/browser/shell_platform_delegate_aura.cc
index 13ee15e..17d5403c 100644
--- a/content/shell/browser/shell_platform_delegate_aura.cc
+++ b/content/shell/browser/shell_platform_delegate_aura.cc
@@ -4,6 +4,7 @@
 
 #include "content/shell/browser/shell_platform_delegate.h"
 
+#include "base/containers/contains.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "content/shell/browser/shell.h"
diff --git a/content/shell/browser/shell_platform_delegate_mac.mm b/content/shell/browser/shell_platform_delegate_mac.mm
index b2c5f9b..89edca7 100644
--- a/content/shell/browser/shell_platform_delegate_mac.mm
+++ b/content/shell/browser/shell_platform_delegate_mac.mm
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 
+#include "base/containers/contains.h"
 #import "base/mac/foundation_util.h"
 #import "base/mac/scoped_nsobject.h"
 #include "base/notreached.h"
diff --git a/content/shell/browser/shell_platform_delegate_views.cc b/content/shell/browser/shell_platform_delegate_views.cc
index 887526e..ccff1a3 100644
--- a/content/shell/browser/shell_platform_delegate_views.cc
+++ b/content/shell/browser/shell_platform_delegate_views.cc
@@ -9,6 +9,7 @@
 #include <memory>
 
 #include "base/command_line.h"
+#include "base/containers/contains.h"
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
diff --git a/content/test/mock_background_sync_controller.cc b/content/test/mock_background_sync_controller.cc
index b0fbac4..16174c61 100644
--- a/content/test/mock_background_sync_controller.cc
+++ b/content/test/mock_background_sync_controller.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "content/test/mock_background_sync_controller.h"
+#include "base/containers/contains.h"
 #include "base/metrics/field_trial_params.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/time/time.h"
diff --git a/content/test/web_contents_observer_consistency_checker.cc b/content/test/web_contents_observer_consistency_checker.cc
index 80c908ff..be10621 100644
--- a/content/test/web_contents_observer_consistency_checker.cc
+++ b/content/test/web_contents_observer_consistency_checker.cc
@@ -4,6 +4,7 @@
 
 #include "content/test/web_contents_observer_consistency_checker.h"
 
+#include "base/containers/contains.h"
 #include "base/memory/ptr_util.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
diff --git a/content/utility/utility_main.cc b/content/utility/utility_main.cc
index 30fd82d..791ef50 100644
--- a/content/utility/utility_main.cc
+++ b/content/utility/utility_main.cc
@@ -103,8 +103,15 @@
   base::SingleThreadTaskExecutor main_thread_task_executor(message_pump_type);
   base::PlatformThread::SetName("CrUtilityMain");
 
-  if (parameters.command_line.HasSwitch(switches::kUtilityStartupDialog))
-    WaitForDebugger("Utility");
+  if (parameters.command_line.HasSwitch(switches::kUtilityStartupDialog)) {
+    auto dialog_match = parameters.command_line.GetSwitchValueASCII(
+        switches::kUtilityStartupDialog);
+    auto sub_type =
+        parameters.command_line.GetSwitchValueASCII(switches::kUtilitySubType);
+    if (dialog_match.empty() || dialog_match == sub_type) {
+      WaitForDebugger(sub_type.empty() ? "Utility" : sub_type);
+    }
+  }
 
 #if defined(OS_LINUX) || defined(OS_CHROMEOS)
   // Initializes the sandbox before any threads are created.
diff --git a/content/web_test/browser/fake_bluetooth_delegate.cc b/content/web_test/browser/fake_bluetooth_delegate.cc
index 20fc784..ee20ff3 100644
--- a/content/web_test/browser/fake_bluetooth_delegate.cc
+++ b/content/web_test/browser/fake_bluetooth_delegate.cc
@@ -4,6 +4,7 @@
 
 #include "content/web_test/browser/fake_bluetooth_delegate.h"
 
+#include "base/containers/contains.h"
 #include "content/public/browser/web_contents.h"
 #include "content/web_test/browser/web_test_control_host.h"
 #include "device/bluetooth/bluetooth_device.h"
diff --git a/content/web_test/browser/web_test_background_fetch_delegate.cc b/content/web_test/browser/web_test_background_fetch_delegate.cc
index f03b74e6..1696314e 100644
--- a/content/web_test/browser/web_test_background_fetch_delegate.cc
+++ b/content/web_test/browser/web_test_background_fetch_delegate.cc
@@ -300,7 +300,7 @@
   params.traffic_annotation =
       net::MutableNetworkTrafficAnnotationTag(traffic_annotation);
 
-  download_service_->StartDownload(params);
+  download_service_->StartDownload(std::move(params));
 }
 
 void WebTestBackgroundFetchDelegate::Abort(const std::string& job_unique_id) {
diff --git a/content/web_test/browser/web_test_shell_platform_delegate_mac.mm b/content/web_test/browser/web_test_shell_platform_delegate_mac.mm
index 1f415ac..66b2609 100644
--- a/content/web_test/browser/web_test_shell_platform_delegate_mac.mm
+++ b/content/web_test/browser/web_test_shell_platform_delegate_mac.mm
@@ -4,6 +4,7 @@
 
 #include "content/web_test/browser/web_test_shell_platform_delegate.h"
 
+#include "base/containers/contains.h"
 #import "base/mac/foundation_util.h"
 #include "content/browser/renderer_host/render_widget_host_view_mac.h"
 #include "content/public/browser/render_frame_host.h"
diff --git a/content/web_test/browser/web_test_shell_platform_delegate_views.cc b/content/web_test/browser/web_test_shell_platform_delegate_views.cc
index bfca5af..8e3276d 100644
--- a/content/web_test/browser/web_test_shell_platform_delegate_views.cc
+++ b/content/web_test/browser/web_test_shell_platform_delegate_views.cc
@@ -4,6 +4,7 @@
 
 #include "content/web_test/browser/web_test_shell_platform_delegate.h"
 
+#include "base/containers/contains.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "content/shell/browser/shell.h"
diff --git a/content/web_test/renderer/test_runner.cc b/content/web_test/renderer/test_runner.cc
index 0a251e6..3ad64c70 100644
--- a/content/web_test/renderer/test_runner.cc
+++ b/content/web_test/renderer/test_runner.cc
@@ -14,6 +14,7 @@
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/command_line.h"
+#include "base/containers/contains.h"
 #include "base/containers/unique_ptr_adapters.h"
 #include "base/logging.h"
 #include "base/macros.h"
diff --git a/crypto/ec_private_key.cc b/crypto/ec_private_key.cc
index 28bbe3f..e4feb04b 100644
--- a/crypto/ec_private_key.cc
+++ b/crypto/ec_private_key.cc
@@ -87,28 +87,6 @@
   return result;
 }
 
-// static
-std::unique_ptr<ECPrivateKey> ECPrivateKey::DeriveFromSecret(
-    base::span<const uint8_t> secret) {
-  bssl::UniquePtr<EC_GROUP> group(
-      EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
-  if (!group)
-    return nullptr;
-
-  bssl::UniquePtr<EC_KEY> ec_key(
-      EC_KEY_derive_from_secret(group.get(), secret.data(), secret.size()));
-  if (!ec_key)
-    return nullptr;
-
-  std::unique_ptr<ECPrivateKey> result(new ECPrivateKey());
-  result->key_.reset(EVP_PKEY_new());
-  if (!result->key_ || !EVP_PKEY_set1_EC_KEY(result->key_.get(), ec_key.get()))
-    return nullptr;
-
-  CHECK_EQ(EVP_PKEY_EC, EVP_PKEY_id(result->key_.get()));
-  return result;
-}
-
 std::unique_ptr<ECPrivateKey> ECPrivateKey::Copy() const {
   std::unique_ptr<ECPrivateKey> copy(new ECPrivateKey());
   copy->key_ = bssl::UpRef(key_);
diff --git a/crypto/ec_private_key.h b/crypto/ec_private_key.h
index de69709..3e26599 100644
--- a/crypto/ec_private_key.h
+++ b/crypto/ec_private_key.h
@@ -50,12 +50,6 @@
   static std::unique_ptr<ECPrivateKey> CreateFromEncryptedPrivateKeyInfo(
       base::span<const uint8_t> encrypted_private_key_info);
 
-  // Creates a new instance by deriving private key from |secret|, and generates
-  // public key points accordingly. The created key will use the NIST P-256
-  // curve. This can return nullptr if initialization fails.
-  static std::unique_ptr<ECPrivateKey> DeriveFromSecret(
-      base::span<const uint8_t> secret);
-
   // Returns a copy of the object.
   std::unique_ptr<ECPrivateKey> Copy() const;
 
diff --git a/crypto/ec_private_key_unittest.cc b/crypto/ec_private_key_unittest.cc
index 8a9cca7..cfec13c 100644
--- a/crypto/ec_private_key_unittest.cc
+++ b/crypto/ec_private_key_unittest.cc
@@ -123,70 +123,6 @@
             raw_public_key);
 }
 
-TEST(ECPrivateKeyUnitTest, DeriveFromSecret) {
-  static const uint8_t kSecret[] = {
-      0x90, 0x48, 0x0a, 0x51, 0x77, 0xa3, 0x72, 0xfb, 0xba, 0x0f, 0x08,
-      0x5e, 0xc5, 0x6f, 0x8f, 0x6d, 0x1c, 0xaf, 0xa9, 0x8a, 0xdf, 0xa9,
-      0x7c, 0x38, 0x70, 0x47, 0xb9, 0x72, 0xcc, 0x5c, 0xaa, 0xc2,
-  };
-
-  static const uint8_t kPrivateKeyInfo[] = {
-      0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
-      0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
-      0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20,
-      0x0e, 0x87, 0xc8, 0x4d, 0x92, 0x14, 0x52, 0x93, 0x96, 0xad, 0x63, 0x9a,
-      0x6a, 0xa7, 0xeb, 0x56, 0x5c, 0xaf, 0xab, 0x69, 0x06, 0xd4, 0x37, 0xf8,
-      0x7d, 0xd7, 0x04, 0xa9, 0xec, 0x6e, 0x2e, 0x96, 0xa1, 0x44, 0x03, 0x42,
-      0x00, 0x04, 0xe2, 0xf5, 0x86, 0x4a, 0xf6, 0xe0, 0x7d, 0x19, 0x94, 0x2d,
-      0x54, 0x16, 0x58, 0x98, 0x62, 0x78, 0xf2, 0x8f, 0x30, 0x77, 0x93, 0x7d,
-      0x2c, 0x17, 0x29, 0xe5, 0x50, 0x42, 0xed, 0x8d, 0x6c, 0x31, 0x34, 0x16,
-      0x20, 0x4f, 0xcc, 0x50, 0x09, 0xaf, 0x8d, 0x56, 0x56, 0x73, 0xe3, 0xb9,
-      0x5a, 0x15, 0xbf, 0x73, 0x25, 0x91, 0xa0, 0xaf, 0x8f, 0x64, 0x19, 0xf4,
-      0x17, 0x8e, 0x7a, 0x05, 0x76, 0x23,
-  };
-
-  static const uint8_t kSubjectPublicKeyInfo[] = {
-      0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
-      0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
-      0x42, 0x00, 0x04, 0xe2, 0xf5, 0x86, 0x4a, 0xf6, 0xe0, 0x7d, 0x19, 0x94,
-      0x2d, 0x54, 0x16, 0x58, 0x98, 0x62, 0x78, 0xf2, 0x8f, 0x30, 0x77, 0x93,
-      0x7d, 0x2c, 0x17, 0x29, 0xe5, 0x50, 0x42, 0xed, 0x8d, 0x6c, 0x31, 0x34,
-      0x16, 0x20, 0x4f, 0xcc, 0x50, 0x09, 0xaf, 0x8d, 0x56, 0x56, 0x73, 0xe3,
-      0xb9, 0x5a, 0x15, 0xbf, 0x73, 0x25, 0x91, 0xa0, 0xaf, 0x8f, 0x64, 0x19,
-      0xf4, 0x17, 0x8e, 0x7a, 0x05, 0x76, 0x23,
-  };
-  static const uint8_t kRawPublicKey[] = {
-      0xe2, 0xf5, 0x86, 0x4a, 0xf6, 0xe0, 0x7d, 0x19, 0x94, 0x2d, 0x54,
-      0x16, 0x58, 0x98, 0x62, 0x78, 0xf2, 0x8f, 0x30, 0x77, 0x93, 0x7d,
-      0x2c, 0x17, 0x29, 0xe5, 0x50, 0x42, 0xed, 0x8d, 0x6c, 0x31, 0x34,
-      0x16, 0x20, 0x4f, 0xcc, 0x50, 0x09, 0xaf, 0x8d, 0x56, 0x56, 0x73,
-      0xe3, 0xb9, 0x5a, 0x15, 0xbf, 0x73, 0x25, 0x91, 0xa0, 0xaf, 0x8f,
-      0x64, 0x19, 0xf4, 0x17, 0x8e, 0x7a, 0x05, 0x76, 0x23,
-  };
-
-  std::unique_ptr<crypto::ECPrivateKey> key(
-      crypto::ECPrivateKey::DeriveFromSecret(kSecret));
-  ASSERT_TRUE(key);
-
-  std::vector<uint8_t> privkey;
-  EXPECT_TRUE(key->ExportPrivateKey(&privkey));
-  EXPECT_EQ(std::vector<uint8_t>(std::begin(kPrivateKeyInfo),
-                                 std::end(kPrivateKeyInfo)),
-            privkey);
-
-  std::vector<uint8_t> public_key;
-  ASSERT_TRUE(key->ExportPublicKey(&public_key));
-  EXPECT_EQ(std::vector<uint8_t>(std::begin(kSubjectPublicKeyInfo),
-                                 std::end(kSubjectPublicKeyInfo)),
-            public_key);
-
-  std::string raw_public_key;
-  ASSERT_TRUE(key->ExportRawPublicKey(&raw_public_key));
-  EXPECT_EQ(std::string(reinterpret_cast<const char*>(kRawPublicKey),
-                        sizeof(kRawPublicKey)),
-            raw_public_key);
-}
-
 TEST(ECPrivateKeyUnitTest, RSAPrivateKeyInfo) {
   static const uint8_t kPrivateKeyInfo[] = {
       0x30, 0x82, 0x02, 0x78, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic.cc b/device/bluetooth/bluetooth_remote_gatt_characteristic.cc
index 6abab33..5309450 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic.cc
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic.cc
@@ -125,17 +125,17 @@
     const base::Optional<NotificationType>& notification_type,
     NotifySessionCallback callback,
     ErrorCallback error_callback) {
-  auto repeating_error_callback =
-      base::AdaptCallbackForRepeating(std::move(error_callback));
+  auto split_error_callback =
+      base::SplitOnceCallback(std::move(error_callback));
   NotifySessionCommand* command = new NotifySessionCommand(
       base::BindOnce(
           &BluetoothRemoteGattCharacteristic::ExecuteStartNotifySession,
           GetWeakPtr(), notification_type, std::move(callback),
-          repeating_error_callback),
+          std::move(split_error_callback.first)),
       base::BindOnce(
           &BluetoothRemoteGattCharacteristic::CancelStartNotifySession,
           GetWeakPtr(),
-          base::BindOnce(repeating_error_callback,
+          base::BindOnce(std::move(split_error_callback.second),
                          BluetoothGattService::GATT_ERROR_FAILED)));
 
   pending_notify_commands_.push(base::WrapUnique(command));
@@ -277,15 +277,14 @@
 void BluetoothRemoteGattCharacteristic::StopNotifySession(
     BluetoothGattNotifySession* session,
     base::OnceClosure callback) {
-  auto repeating_callback =
-      base::AdaptCallbackForRepeating(std::move(callback));
+  auto split_callback = base::SplitOnceCallback(std::move(callback));
   NotifySessionCommand* command = new NotifySessionCommand(
       base::BindOnce(
           &BluetoothRemoteGattCharacteristic::ExecuteStopNotifySession,
-          GetWeakPtr(), session, repeating_callback),
+          GetWeakPtr(), session, std::move(split_callback.first)),
       base::BindOnce(
           &BluetoothRemoteGattCharacteristic::CancelStopNotifySession,
-          GetWeakPtr(), repeating_callback));
+          GetWeakPtr(), std::move(split_callback.second)));
 
   pending_notify_commands_.push(std::unique_ptr<NotifySessionCommand>(command));
   if (pending_notify_commands_.size() == 1) {
diff --git a/device/fido/cable/fido_ble_connection.cc b/device/fido/cable/fido_ble_connection.cc
index 58d9bd5d..d5d25ec 100644
--- a/device/fido/cable/fido_ble_connection.cc
+++ b/device/fido/cable/fido_ble_connection.cc
@@ -259,11 +259,13 @@
           : BluetoothRemoteGattCharacteristic::WriteType::kWithResponse;
 
   FIDO_LOG(DEBUG) << "Wrote Control Point.";
-  auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
+  auto split_callback = base::SplitOnceCallback(std::move(callback));
   control_point->WriteRemoteCharacteristic(
       data, write_type,
-      base::BindOnce(OnWriteRemoteCharacteristic, copyable_callback),
-      base::BindOnce(OnWriteRemoteCharacteristicError, copyable_callback));
+      base::BindOnce(OnWriteRemoteCharacteristic,
+                     std::move(split_callback.first)),
+      base::BindOnce(OnWriteRemoteCharacteristicError,
+                     std::move(split_callback.second)));
 }
 
 void FidoBleConnection::OnCreateGattConnection(
@@ -406,14 +408,16 @@
     return;
   }
 
-  auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
+  auto split_callback = base::SplitOnceCallback(std::move(callback));
   DCHECK(service_revision_bitfield_id_);
   fido_service->GetCharacteristic(*service_revision_bitfield_id_)
       ->WriteRemoteCharacteristic(
           {static_cast<uint8_t>(service_revision)},
           BluetoothRemoteGattCharacteristic::WriteType::kWithResponse,
-          base::BindOnce(OnWriteRemoteCharacteristic, copyable_callback),
-          base::BindOnce(OnWriteRemoteCharacteristicError, copyable_callback));
+          base::BindOnce(OnWriteRemoteCharacteristic,
+                         std::move(split_callback.first)),
+          base::BindOnce(OnWriteRemoteCharacteristicError,
+                         std::move(split_callback.second)));
 }
 
 void FidoBleConnection::OnServiceRevisionWritten(bool success) {
diff --git a/device/fido/cable/fido_cable_discovery.cc b/device/fido/cable/fido_cable_discovery.cc
index f29b982..d51277d 100644
--- a/device/fido/cable/fido_cable_discovery.cc
+++ b/device/fido/cable/fido_cable_discovery.cc
@@ -372,12 +372,10 @@
   adapter()->StartDiscoverySessionWithFilter(
       std::make_unique<BluetoothDiscoveryFilter>(
           BluetoothTransport::BLUETOOTH_TRANSPORT_LE),
-      base::AdaptCallbackForRepeating(
-          base::BindOnce(&FidoCableDiscovery::OnStartDiscoverySession,
-                         weak_factory_.GetWeakPtr())),
-      base::AdaptCallbackForRepeating(
-          base::BindOnce(&FidoCableDiscovery::OnStartDiscoverySessionError,
-                         weak_factory_.GetWeakPtr())));
+      base::BindOnce(&FidoCableDiscovery::OnStartDiscoverySession,
+                     weak_factory_.GetWeakPtr()),
+      base::BindOnce(&FidoCableDiscovery::OnStartDiscoverySessionError,
+                     weak_factory_.GetWeakPtr()));
 }
 
 void FidoCableDiscovery::OnStartDiscoverySession(
@@ -419,10 +417,9 @@
     }
     adapter()->RegisterAdvertisement(
         ConstructAdvertisementData(data.v1->client_eid),
-        base::AdaptCallbackForRepeating(
-            base::BindOnce(&FidoCableDiscovery::OnAdvertisementRegistered,
-                           weak_factory_.GetWeakPtr(), data.v1->client_eid)),
-        base::BindRepeating([](BluetoothAdvertisement::ErrorCode error_code) {
+        base::BindOnce(&FidoCableDiscovery::OnAdvertisementRegistered,
+                       weak_factory_.GetWeakPtr(), data.v1->client_eid),
+        base::BindOnce([](BluetoothAdvertisement::ErrorCode error_code) {
           FIDO_LOG(ERROR) << "Failed to register advertisement: " << error_code;
         }));
   }
@@ -497,7 +494,7 @@
   // Speed up GATT service discovery on ChromeOS/BlueZ.
   // SetConnectionLatency() is NOTIMPLEMENTED() on other platforms.
   device->SetConnectionLatency(BluetoothDevice::CONNECTION_LATENCY_LOW,
-                               base::DoNothing(), base::BindRepeating([]() {
+                               base::DoNothing(), base::BindOnce([]() {
                                  FIDO_LOG(ERROR)
                                      << "SetConnectionLatency() failed";
                                }));
diff --git a/device/gamepad/gamepad_device_linux.cc b/device/gamepad/gamepad_device_linux.cc
index a01f3e9..087744d 100644
--- a/device/gamepad/gamepad_device_linux.cc
+++ b/device/gamepad/gamepad_device_linux.cc
@@ -222,11 +222,11 @@
     scoped_refptr<base::SequencedTaskRunner> polling_runner) {
   auto* client = chromeos::PermissionBrokerClient::Get();
   DCHECK(client) << "Could not get permission broker client.";
-  auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
-  auto success_callback =
-      base::BindOnce(&OnOpenPathSuccess, copyable_callback, polling_runner);
-  auto error_callback =
-      base::BindOnce(&OnOpenPathError, copyable_callback, polling_runner);
+  auto split_callback = base::SplitOnceCallback(std::move(callback));
+  auto success_callback = base::BindOnce(
+      &OnOpenPathSuccess, std::move(split_callback.first), polling_runner);
+  auto error_callback = base::BindOnce(
+      &OnOpenPathError, std::move(split_callback.second), polling_runner);
   client->OpenPath(path, std::move(success_callback),
                    std::move(error_callback));
 }
diff --git a/docs/linux/debugging.md b/docs/linux/debugging.md
index 9ecefa5..38e4d96 100644
--- a/docs/linux/debugging.md
+++ b/docs/linux/debugging.md
@@ -83,6 +83,10 @@
 https://www.chromium.org/blink/getting-started-with-blink-debugging for more
 information on how this can be done.
 
+For utilities you can use `--utility-startup-dialog` to have all utilities
+prompt, or `--utility-startup-dialog=data_decoder.mojom.DataDecoderService`
+to debug only a particular service type.
+
 #### Choosing which renderers to debug
 
 If you are starting multiple renderers then the above means that multiple gdb's
diff --git a/docs/mac/debugging.md b/docs/mac/debugging.md
index 8cd36e9..420faef 100644
--- a/docs/mac/debugging.md
+++ b/docs/mac/debugging.md
@@ -173,7 +173,7 @@
 
 * `--renderer-startup-dialog`
 * `--utility-startup-dialog`
-* `--renderer-startup-dialog`
+* `--utility-startup-dialog=data_decoder.mojom.DataDecoderService`
 
 After the process launches, it will print a message like this to standard error:
 
diff --git a/docs/mojo_testing.md b/docs/mojo_testing.md
new file mode 100644
index 0000000..95941a3
--- /dev/null
+++ b/docs/mojo_testing.md
@@ -0,0 +1,206 @@
+# Testing With Mojo
+
+This document outlines some best practices and techniques for testing code which
+internally uses a Mojo service. It assumes familiarity with the
+[Mojo and Services] document.
+
+## Example Code & Context
+
+Suppose we have this Mojo interface:
+
+```mojom
+module example.mojom;
+
+interface IncrementerService {
+  Increment(int32 value) => (int32 new_value);
+}
+```
+
+and this C++ class that uses it:
+
+```c++
+class Incrementer {
+ public:
+  Incrementer();
+
+  void SetServiceForTest(
+      mojo::PendingRemote<mojom::IncrementerService> service);
+
+  // The underlying service is async, so this method is too.
+  void Increment(int32_t value,
+                 IncrementCallback callback);
+
+ private;
+  mojo::Remote<mojom::IncrementerService> service_;
+};
+
+void Incrementer::SetServiceForTesting(
+    mojo::PendingRemote<mojom::IncrementerService> service) {
+  service_.Bind(std::move(service));
+}
+
+void Incrementer::Increment(int32_t value, IncrementCallback callback) {
+  if (!service_)
+    service_ = LaunchIncrementerService();
+  service_->Increment(value, std::move(callback));
+}
+```
+
+and we wish to swap a test fake in for the underlying IncrementerService, so we
+can unit-test Incrementer. Specifically, we're trying to write this (silly) test:
+
+```c++
+// Test that Incrementer correctly handles when the IncrementerService fails to
+// increment the value.
+TEST(IncrementerTest, DetectsFailureToIncrement) {
+  Incrementer incr;
+  FakeIncrementerService service;
+  incr.SetServiceForTest(service);
+
+  // Incrementing is async, so we have to wait...
+  base::RunLoop loop;
+  int returned_value;
+  incr.Increment(0,
+    base::BindLambdaForTesting([&](int value) {
+      returned_value = value;
+      loop.Quit();
+    }));
+  loop.Run();
+
+  EXPECT_EQ(0, returned_value);
+}
+```
+
+## The Fake Service Itself
+
+This part is fairly straightforward. Mojo generated a class called
+mojom::IncrementerService, which is normally subclassed by
+IncrementerServiceImpl (or whatever) in production; we can subclass it
+ourselves:
+
+```c++
+class FakeIncrementerService : public mojom::IncrementerService {
+ public:
+  void Increment(int32_t value, IncrementCallback callback) override {
+    // Does not actually increment, for test purposes!
+    std::move(callback).Run(value);
+  }
+}
+```
+
+## Async Services
+
+If we plug the FakeIncrementerService in in our test:
+
+```c++
+  mojo::Receiver<IncrementerService> receiver{&fake_service};
+  incrementer->SetServiceForTest(receiver);
+```
+
+we can invoke it and wait for the response as we usually would:
+
+```c++
+  base::RunLoop loop;
+  incrementer->Increment(1, base::BindLambdaForTesting(...));
+  loop.Run();
+```
+
+... and all is well. However, we might reasonably want a more flexible
+FakeIncrementerService, which allows for plugging different responses in as the
+test progresses. In that case, we will actually need to wait twice: once for the
+request to arrive at the FakeIncrementerService, and once for the response to be
+delivered back to the Incrementer.
+
+## Waiting For Requests
+
+To do that, we can instead structure our fake service like this:
+
+```c++
+class FakeIncrementerService : public mojom::IncrementerService {
+ public:
+  void Increment(int32_t value, IncrementCallback callback) override {
+    CHECK(!HasPendingRequest());
+    last_value_ = value;
+    last_callback_ = std::move(callback);
+    if (wait_loop_)
+      wait_loop_->Quit();
+  }
+
+  bool HasPendingRequest() const {
+    return bool(last_callback_);
+  }
+
+  void WaitForRequest() {
+    if (HasPendingRequest())
+      return;
+    wait_loop_ = std::make_unique<base::RunLoop>();
+    wait_loop_->Run();
+  }
+
+  void AnswerRequest(int32_t value) {
+    CHECK(HasPendingRequest());
+    std::move(last_callback_).Run(value);
+  }
+};
+```
+
+That having been done, our test can now observe the state of the code under test
+(in this case the Incrementer service) while the mojo request is pending, like
+so:
+
+```c++
+  FakeIncrementerService service;
+  mojo::Receiver<mojom::IncrementerService> receiver{&service};
+
+  Incrementer incrementer;
+  incrementer->SetServiceForTest(receiver);
+  incrementer->Increment(1, base::BindLambdaForTesting(...));
+
+  // This will do the right thing even if the Increment method later becomes
+  // synchronous, and exercises the same async code paths as the production code
+  // will.
+  service.WaitForRequest();
+  service.AnswerRequest(service.last_value() + 2);
+
+  // The lambda passed in above will now asynchronously run somewhere here,
+  // since the response is also delivered asynchronously by mojo.
+```
+
+## Test Ergonomics
+
+The async-ness at both ends can create a good amount of boilerplate in test
+code, which is unpleasant. This section gives some techniques for reducing it.
+
+### Sync Wrappers
+
+One can use the [synchronous runloop] pattern to make the mojo calls appear to
+be synchronous *to the test bodies* while leaving them asynchronous in the
+production code. Mojo actually generates test helpers for this already! We can
+include `incrementer_service.mojom-test-utils.h` and then do:
+
+```c++
+int32_t Increment(Incrementer* incrementer, int32_t value) {
+  int32_t result;
+  mojom::IncrementerAsyncWaiter sync_incrementer(incrementer);
+  sync_incrementer.Increment(value, &result);
+  return result;
+}
+```
+
+Note that this only works if FakeIncrementerService does not need to be told
+when to send a response (via AnswerRequest or similar) - if it does, this
+pattern will deadlock!
+
+To avoid that, the cleanest approach is to have the FakeIncrementerService
+either contain a field with the next expected value, or a callback that produces
+expected values on demand, so that your test code reads like:
+
+```c++
+  service.SetNextValue(2);
+  EXPECT_EQ(Increment(incrementer, 1), 2);
+```
+
+or similar.
+
+[Mojo and Services]: mojo_and_services.md
+[synchronous runloop]: patterns/synchronous-runloop.md
diff --git a/docs/python3_migration.md b/docs/python3_migration.md
new file mode 100644
index 0000000..65aea89
--- /dev/null
+++ b/docs/python3_migration.md
@@ -0,0 +1,144 @@
+# Migrating Chromium to Python3
+
+This page describes the current status and how to migrate code.
+
+[crbug.com/941669](https://crbug.com/941669) tracks the overall migration.
+
+*It is now safe to write new code using Python3 as long as it isn't called
+from other Python2 files. See the
+[Python style guide](../styleguide/python/python.md) for the latest on this.*
+
+## Status
+
+As of the time of writing (2021-05-12), we're in the following state:
+
+* depot_tools is fully Python3-compatible.
+* [gclient hooks](#gclient_hooks) are being migrated to use Python3
+  ([crbug.com/1208028](https://crbug.com/1208028)).
+* GN is fully Python3-compatible, meaning that all the scripts invoked
+  through exec_script() are using Python3.
+* The [build](#gn_ninja-actions) (scripts invoked by Ninja) is using Python3 by default,
+  but some actions are still run using Python2
+  ([crbug.com/1112471](https://crbug.com/1112471)).
+* We are updating the various test harnesses and frameworks to use
+  Python3, but most still use Python2. It is possible to use
+  Python3 for tests if you're ready to do so.
+* [PRESUBMIT checks](#presubmit_checks) are being migrated to use Python3
+  ([crbug.com/1207012](https://crbug.com/1207012)).
+* Python3-compatible pylint checks are available but not yet fully
+  integrated into the presubmit checks
+  ([crbug.com/1157676](https://crbug.com/1157676)).
+
+
+## Migrating Python code from 2 to 3
+
+This document will not attempt to replicate the general information in
+the [Python.org Porting HOWTO](https://docs.python.org/3/howto/pyporting.html)
+or the many, many other guides on the Internet.
+
+However, here are a few notes that may be helpful in a Chromium context:
+
+* Most of our Python code is pretty straightforward and moves easily
+  from Python2 to Python3, so don't stress out about this!
+
+* When migrating code, please make the Right Changes, rather than the
+  minimum needed to get things to work. For example, make sure your code
+  is clear about whether something should be a byte string or a unicode
+  string, rather than trying to handle both "to be compatible".
+  (If you really do need the code to handle both, though, that can be okay.)
+
+* Do not assume you can use [vpython] regardless of context! vpython has
+  performance issues in some situations and so we don't want to use it yet for
+  things invoked by gclient, PRESUBMITs, or Ninja. However, all tests are run
+  under vpython and so you can assume it there.
+
+* Some people find the `2to3` tool to be useful to partially or
+  completely automate the migration of existing files, and the
+  `six` module to shim compatibility across the two. The `six` module
+  is available in vpython and in `//third_party/six/src/six.py`.
+
+* shebang lines mostly don't matter. A "shebang line" is the line at the
+  beginning of many unix scripts, like `#!/usr/bin/env python`. They are
+  not that important for us because most of our python invocations come
+  from tools like Ninja or Swarming and invoke python directly. So, while
+  you should keep them accurate where they are useful, we can't rely
+  on them to tell which code has been migrated and which hasn't.
+
+* The major gotchas for us tend to have to do with processing output
+  from a subprocess (e.g., `subprocess.check_output()`). By default
+  output is returned as a binary string, so get in the habit of calling
+  `.check_output().decode('utf-8')` instead. This is compatible across
+  2 and 3. 'utf-8' is the default in Python3 (ASCII was the default in
+  Python2), but being explicitly is probably a good idea until we have
+  migrated everything.
+
+* Be aware that `filter` and `map` return generators in Python3, which
+  are one-shot objects. If you reference them inside another loop, e.g.,
+
+      foo = [ ... ]
+      bar = filter(some_function, [ ...])
+      for x in foo:
+          for y in bar:
+              do_something(x, y)
+
+  this won't work right, because on the second and subsequent iterations,
+  bar will be an empty list.
+
+  Best practice is to use a list comprehension instead of `map` or `filter`,
+  but you can also explicitly cast the results of map or filter to a list
+  if the list comprehension is too awkward.
+
+* Some modules (like `urllib2`) were renamed and/or moved around in Python 3.
+  A Google search will usually quickly tell you the new location.
+
+* Watch out for places where you reference `basestring` or `unicode` directly.
+  `six` provides some compatibility types to help here.
+
+## Testing your migrations
+
+Generally speaking, test your changes the same way we do everything else:
+make a change locally, and rely on the CQ and CI bots to catch problems.
+
+However, here are some specific guidelines for the different contexts
+where we use Python:
+
+### gclient hooks
+
+To switch a gclient hook from Python2 to Python3, simply change `python`
+to `python3` in the DEPS file, and make sure things still run :).
+
+### GN/Ninja actions
+
+Most targets in the build use Python3 now, and anything declared via an
+`action()` rule in GN will use Python3.
+
+Some targets still require Python2; they are declared as [python2_action]
+targets instead. To migrate them to Python3, change the `python2_action` to
+`action` and make sure things still build.
+
+### Tests
+
+Test targets that run by invoking python scripts (like telemetry_unittests
+or blink_web_tests) should eventually migrate to using the [script_test]
+GN templates. Once you do that, they will use Python3 by default. However,
+some tests may specify `run_under_python2 = true` as a template variable
+to use Python2, so when you're ready to test Python3, just delete that line.
+
+Some tests still need to be migrated to `script_test()`
+([crbug.com/1208648](https://crbug.com/1208648)). The process for
+doing that is not yet well documented, so ask on python@chromium.org (or
+ask dpranke@ directly).
+
+There is no general mechanism for migrating tests that are C++ executables
+that launch python via subprocesses, so you're on your own for dealing with
+that.
+
+### Presubmit checks
+
+Presubmit checks are run using Python 2 by default. To run them using
+Python3, add the line `USE_PYTHON3 = True` to the PRESUBMIT.py file in
+question (effectively creating a global variable).
+
+[python2_action]: https://source.chromium.org/chromium/chromium/src/+/main:build/config/python.gni;l=68?q=python2_action%20file:python.gni&ss=chromium
+[script_test]: https://source.chromium.org/?q=script_test%20file:testing%2Ftest.gni&ss=chromium
+[vpython]: https://chromium.googlesource.com/infra/infra/+/refs/heads/main/doc/users/vpython.md
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 e2b52402..8dc27c2 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
@@ -424,8 +424,8 @@
 
 void MimeHandlerViewGuest::DocumentOnLoadCompletedInMainFrame(
     content::RenderFrameHost* render_frame_host) {
-  // Assume the embedder WebContents is valid here.
-  DCHECK(embedder_web_contents());
+  DCHECK(GetEmbedderFrame());
+  DCHECK_NE(element_instance_id(), guest_view::kInstanceIDNone);
 
   // For plugin elements, the embedder should be notified so that the queued
   // messages (postMessage) are forwarded to the guest page. Otherwise we
diff --git a/extensions/browser/renderer_startup_helper_unittest.cc b/extensions/browser/renderer_startup_helper_unittest.cc
index c9b9499e..de2c220 100644
--- a/extensions/browser/renderer_startup_helper_unittest.cc
+++ b/extensions/browser/renderer_startup_helper_unittest.cc
@@ -101,8 +101,7 @@
                                     bool update_origin_whitelist) override {}
 
   void UpdateUserScripts(base::ReadOnlySharedMemoryRegion shared_memory,
-                         mojom::HostIDPtr host_id,
-                         bool allowlisted_only) override {}
+                         mojom::HostIDPtr host_id) override {}
 
   void ClearTabSpecificPermissions(
       const std::vector<std::string>& extension_ids,
diff --git a/extensions/browser/user_script_loader.cc b/extensions/browser/user_script_loader.cc
index 3ca2655e..ee08854d 100644
--- a/extensions/browser/user_script_loader.cc
+++ b/extensions/browser/user_script_loader.cc
@@ -18,10 +18,13 @@
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_process_host.h"
+#include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extensions_browser_client.h"
+#include "extensions/browser/guest_view/web_view/web_view_renderer_state.h"
 #include "extensions/browser/renderer_startup_helper.h"
 #include "extensions/common/extension_messages.h"
 #include "extensions/common/mojom/run_location.mojom-shared.h"
+#include "extensions/common/permissions/permissions_data.h"
 
 using content::BrowserThread;
 using content::BrowserContext;
@@ -70,6 +73,19 @@
   return true;
 }
 
+bool CanExecuteScriptEverywhere(BrowserContext* browser_context,
+                                const mojom::HostID& host_id) {
+  if (host_id.type == mojom::HostID::HostType::kWebUi)
+    return true;
+
+  const Extension* extension =
+      ExtensionRegistry::Get(browser_context)
+          ->GetExtensionById(host_id.id, ExtensionRegistry::ENABLED);
+
+  return extension && PermissionsData::CanExecuteScriptEverywhere(
+                          extension->id(), extension->location());
+}
+
 }  // namespace
 
 // static
@@ -418,14 +434,6 @@
 void UserScriptLoader::SendUpdate(
     content::RenderProcessHost* process,
     const base::ReadOnlySharedMemoryRegion& shared_memory) {
-  // Don't allow injection of non-allowlisted extensions' content scripts
-  // into <webview>.
-  // TODO(crbug.com/1054624): Some tests will fail if we set extension webview
-  // scripts to be allowlisted only. This will be corrected in a follow up.
-  // Since all scripts sent in the IPC now belong to the same extension, we
-  // should be able to move the logic from the renderer back here and not send
-  // the IPC in some cases.
-  bool allowlisted_only = process->IsForGuestsOnly() && host_id().id.empty();
 
   // Make sure we only send user scripts to processes in our browser_context.
   if (!ExtensionsBrowserClient::Get()->IsSameContext(
@@ -443,12 +451,29 @@
   if (!region_for_process.IsValid())
     return;
 
+  // If the process only hosts guest frames, then those guest frames share the
+  // same embedder/owner. In this case, only scripts from allowlisted hosts or
+  // from the guest frames' owner should be injected.
+  // Concrete example: This prevents a scenario where manifest scripts from
+  // other extensions are injected into webviews.
+  if (process->IsForGuestsOnly() &&
+      !CanExecuteScriptEverywhere(browser_context_, host_id())) {
+    DCHECK(WebViewRendererState::GetInstance()->IsGuest(process->GetID()));
+
+    std::string owner_host;
+    bool found_owner = WebViewRendererState::GetInstance()->GetOwnerInfo(
+        process->GetID(), /*owner_process_id=*/nullptr, &owner_host);
+
+    DCHECK(found_owner);
+    if (owner_host != host_id().id)
+      return;
+  }
+
   mojom::Renderer* renderer =
       RendererStartupHelperFactory::GetForBrowserContext(browser_context())
           ->GetRenderer(process);
   renderer->UpdateUserScripts(std::move(region_for_process),
-                              mojom::HostID::New(host_id().type, host_id().id),
-                              allowlisted_only);
+                              mojom::HostID::New(host_id().type, host_id().id));
 }
 
 }  // namespace extensions
diff --git a/extensions/common/mojom/renderer.mojom b/extensions/common/mojom/renderer.mojom
index 0c9b26d..8f63ed3 100644
--- a/extensions/common/mojom/renderer.mojom
+++ b/extensions/common/mojom/renderer.mojom
@@ -77,12 +77,9 @@
   // Notifies the renderer that the user scripts have been updated. It has one
   // ReadOnlySharedMemoryRegion argument consisting of the pickled script data.
   // This memory region is valid in the context of the renderer.
-  // |owner| must not be empty, and all scripts from |owner| will be updated. If
-  // |allowlisted_only| is true, this process should only run allowlisted
-  // scripts and not all user scripts.
+  // |owner| must not be empty, and all scripts from |owner| will be updated.
   UpdateUserScripts(mojo_base.mojom.ReadOnlySharedMemoryRegion region,
-                    HostID owner,
-                    bool allowlisted_only);
+                    HostID owner);
 
   // Tells the render view to clear tab-specific permissions for some
   // extensions.
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc
index 30628fa..4225637 100644
--- a/extensions/renderer/dispatcher.cc
+++ b/extensions/renderer/dispatcher.cc
@@ -1095,10 +1095,9 @@
 
 void Dispatcher::UpdateUserScripts(
     base::ReadOnlySharedMemoryRegion shared_memory,
-    mojom::HostIDPtr host_id,
-    bool allowlisted_only) {
+    mojom::HostIDPtr host_id) {
   user_script_set_manager_->OnUpdateUserScripts(std::move(shared_memory),
-                                                *host_id, allowlisted_only);
+                                                *host_id);
 }
 
 void Dispatcher::ClearTabSpecificPermissions(
diff --git a/extensions/renderer/dispatcher.h b/extensions/renderer/dispatcher.h
index d34626f..20e1fdd 100644
--- a/extensions/renderer/dispatcher.h
+++ b/extensions/renderer/dispatcher.h
@@ -246,8 +246,7 @@
                                     int tab_id,
                                     bool update_origin_whitelist) override;
   void UpdateUserScripts(base::ReadOnlySharedMemoryRegion shared_memory,
-                         mojom::HostIDPtr host_id,
-                         bool allowlisted_only) override;
+                         mojom::HostIDPtr host_id) override;
   void ClearTabSpecificPermissions(
       const std::vector<std::string>& extension_ids,
       int tab_id,
diff --git a/extensions/renderer/user_script_set.cc b/extensions/renderer/user_script_set.cc
index 9f60c81..1e4d811a 100644
--- a/extensions/renderer/user_script_set.cc
+++ b/extensions/renderer/user_script_set.cc
@@ -18,11 +18,9 @@
 #include "extensions/common/extension.h"
 #include "extensions/common/extensions_client.h"
 #include "extensions/common/mojom/host_id.mojom.h"
-#include "extensions/common/permissions/permissions_data.h"
 #include "extensions/renderer/extension_injection_host.h"
 #include "extensions/renderer/extensions_renderer_client.h"
 #include "extensions/renderer/injection_host.h"
-#include "extensions/renderer/renderer_extension_registry.h"
 #include "extensions/renderer/script_context.h"
 #include "extensions/renderer/script_injection.h"
 #include "extensions/renderer/user_script_injector.h"
@@ -55,17 +53,6 @@
   return data_source_url;
 }
 
-bool CanExecuteScriptEverywhere(const mojom::HostID& host_id) {
-  if (host_id.type == mojom::HostID::HostType::kWebUi)
-    return true;
-
-  const Extension* extension =
-      RendererExtensionRegistry::Get()->GetByID(host_id.id);
-
-  return extension && PermissionsData::CanExecuteScriptEverywhere(
-                          extension->id(), extension->location());
-}
-
 }  // namespace
 
 UserScriptSet::UserScriptSet(mojom::HostID host_id)
@@ -101,20 +88,7 @@
 }
 
 bool UserScriptSet::UpdateUserScripts(
-    base::ReadOnlySharedMemoryRegion shared_memory,
-    bool allowlisted_only) {
-  if (allowlisted_only && !CanExecuteScriptEverywhere(host_id_)) {
-    // Since scripts should not execute here, the memory mapping is no longer
-    // valid and should be reset.
-    // TODO(crbug.com/1054624): Change this to a DCHECK once the browser side
-    // has been updated to not send the IPC if scripts for the given HostID
-    // should not execute in this process.
-    shared_memory_mapping_ = base::ReadOnlySharedMemoryMapping();
-    for (auto& observer : observers_)
-      observer.OnUserScriptsUpdated();
-    return true;
-  }
-
+    base::ReadOnlySharedMemoryRegion shared_memory) {
   bool only_inject_incognito =
       ExtensionsRendererClient::Get()->IsIncognitoProcess();
 
diff --git a/extensions/renderer/user_script_set.h b/extensions/renderer/user_script_set.h
index c81567b..370a3db 100644
--- a/extensions/renderer/user_script_set.h
+++ b/extensions/renderer/user_script_set.h
@@ -70,8 +70,7 @@
 
   // Updates scripts given the shared memory region containing user scripts.
   // Returns true if the scripts were successfully updated.
-  bool UpdateUserScripts(base::ReadOnlySharedMemoryRegion shared_memory,
-                         bool allowlisted_only);
+  bool UpdateUserScripts(base::ReadOnlySharedMemoryRegion shared_memory);
 
   bool HasScripts() const { return !scripts_.empty(); }
 
diff --git a/extensions/renderer/user_script_set_manager.cc b/extensions/renderer/user_script_set_manager.cc
index 7c9224e..39d29a5 100644
--- a/extensions/renderer/user_script_set_manager.cc
+++ b/extensions/renderer/user_script_set_manager.cc
@@ -76,8 +76,7 @@
 
 void UserScriptSetManager::OnUpdateUserScripts(
     base::ReadOnlySharedMemoryRegion shared_memory,
-    const mojom::HostID& host_id,
-    bool allowlisted_only) {
+    const mojom::HostID& host_id) {
   if (!shared_memory.IsValid()) {
     NOTREACHED() << "Bad scripts handle";
     return;
@@ -93,7 +92,7 @@
   if (!scripts)
     scripts = std::make_unique<UserScriptSet>(host_id);
 
-  if (scripts->UpdateUserScripts(std::move(shared_memory), allowlisted_only)) {
+  if (scripts->UpdateUserScripts(std::move(shared_memory))) {
     for (auto& observer : observers_)
       observer.OnUserScriptsUpdated(host_id);
   }
diff --git a/extensions/renderer/user_script_set_manager.h b/extensions/renderer/user_script_set_manager.h
index 76015fb..e780d5b 100644
--- a/extensions/renderer/user_script_set_manager.h
+++ b/extensions/renderer/user_script_set_manager.h
@@ -75,8 +75,7 @@
 
   // Handle the UpdateUserScripts extension message.
   void OnUpdateUserScripts(base::ReadOnlySharedMemoryRegion shared_memory,
-                           const mojom::HostID& host_id,
-                           bool allowlisted_only);
+                           const mojom::HostID& host_id);
 
   // Invalidates script injections for the UserScriptSet in `scripts_`
   // corresponding to `extension_id` and deletes the script set.
diff --git a/infra/config/generated/commit-queue.cfg b/infra/config/generated/commit-queue.cfg
index aa5477f..2853a37e 100644
--- a/infra/config/generated/commit-queue.cfg
+++ b/infra/config/generated/commit-queue.cfg
@@ -1137,13 +1137,6 @@
         includable_only: true
       }
       builders {
-        name: "chromium/try/linux-experimental-next-rel"
-        experiment_percentage: 10
-        location_regexp: ".*"
-        location_regexp_exclude: ".+/[+]/docs/.+"
-        location_regexp_exclude: ".+/[+]/infra/config/.+"
-      }
-      builders {
         name: "chromium/try/linux-extended-tracing-rel"
         includable_only: true
       }
diff --git a/infra/config/generated/cq-builders.md b/infra/config/generated/cq-builders.md
index bd85ecb7..c8173f78 100644
--- a/infra/config/generated/cq-builders.md
+++ b/infra/config/generated/cq-builders.md
@@ -444,9 +444,6 @@
 * [ios-simulator-rts](https://ci.chromium.org/p/chromium/builders/try/ios-simulator-rts) ([definition](https://cs.chromium.org/search?q=package:%5Echromium$+file:/cq.star$+-file:/beta/+-file:/stable/+ios-simulator-rts)) ([matching builders](https://cs.chromium.org/search?q=+file:trybots.py+ios-simulator-rts))
   * Experiment percentage: 1.0
 
-* [linux-experimental-next-rel](https://ci.chromium.org/p/chromium/builders/try/linux-experimental-next-rel) ([definition](https://cs.chromium.org/search?q=package:%5Echromium$+file:/cq.star$+-file:/beta/+-file:/stable/+linux-experimental-next-rel)) ([matching builders](https://cs.chromium.org/search?q=+file:trybots.py+linux-experimental-next-rel))
-  * Experiment percentage: 10.0
-
 * [linux-perfetto-rel](https://ci.chromium.org/p/chromium/builders/try/linux-perfetto-rel) ([definition](https://cs.chromium.org/search?q=package:%5Echromium$+file:/cq.star$+-file:/beta/+-file:/stable/+linux-perfetto-rel)) ([matching builders](https://cs.chromium.org/search?q=+file:trybots.py+linux-perfetto-rel))
   * Experiment percentage: 100.0
 
diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg
index 6fb3167..dadf9579 100644
--- a/infra/config/generated/cr-buildbucket.cfg
+++ b/infra/config/generated/cr-buildbucket.cfg
@@ -47494,70 +47494,6 @@
       }
     }
     builders {
-      name: "linux-experimental-next-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builder:linux-experimental-next-rel"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
-      dimensions: "pool:luci.chromium.try"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/code_coverage\":{\"use_clang_coverage\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"$recipe_engine/isolated\":{\"server\":\"https://isolateserver.appspot.com\"},\"$recipe_engine/resultdb/test_presentation\":{\"column_keys\":[],\"grouping_keys\":[\"status\",\"v.test_suite\"]},\"builder_group\":\"tryserver.chromium.linux\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      grace_period {
-        seconds: 120
-      }
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      experiments {
-        key: "chromium.resultdb.result_sink"
-        value: 100
-      }
-      experiments {
-        key: "chromium.resultdb.result_sink.junit_tests"
-        value: 100
-      }
-      experiments {
-        key: "luci.use_realms"
-        value: 100
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "gpu_try_test_results"
-          test_results {
-            predicate {
-              test_id_regexp: "ninja://(chrome/test:|content/test:fuchsia_)telemetry_gpu_integration_test/.+"
-            }
-          }
-        }
-        history_options {
-          use_invocation_timestamp: true
-        }
-      }
-    }
-    builders {
       name: "linux-extended-tracing-rel"
       swarming_host: "chromium-swarm.appspot.com"
       swarming_tags: "vpython:native-python-wrapper"
diff --git a/infra/config/generated/luci-milo.cfg b/infra/config/generated/luci-milo.cfg
index d6a36e64..ed00f01b 100644
--- a/infra/config/generated/luci-milo.cfg
+++ b/infra/config/generated/luci-milo.cfg
@@ -2048,9 +2048,6 @@
     name: "buildbucket/luci.chromium.try/linux-chromeos-rel"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/linux-experimental-next-rel"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/linux-lacros-rel"
   }
   builders {
@@ -13287,9 +13284,6 @@
     name: "buildbucket/luci.chromium.try/linux-example-builder"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/linux-experimental-next-rel"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/linux-extended-tracing-rel"
   }
   builders {
@@ -14270,9 +14264,6 @@
     name: "buildbucket/luci.chromium.try/linux-example-builder"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/linux-experimental-next-rel"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/linux-extended-tracing-rel"
   }
   builders {
diff --git a/infra/config/subprojects/chromium/try.star b/infra/config/subprojects/chromium/try.star
index 4763e2b..c994e81b9 100644
--- a/infra/config/subprojects/chromium/try.star
+++ b/infra/config/subprojects/chromium/try.star
@@ -1166,19 +1166,6 @@
 )
 
 try_.chromium_linux_builder(
-    name = "linux-experimental-next-rel",
-    branch_selector = branches.STANDARD_MILESTONE,
-    builderless = not settings.is_main,
-    goma_jobs = goma.jobs.J150,
-    os = os.LINUX_BIONIC,
-    main_list_view = "try",
-    tryjob = try_.job(
-        experiment_percentage = 10,
-    ),
-    use_clang_coverage = True,
-)
-
-try_.chromium_linux_builder(
     name = "linux-blink-heap-concurrent-marking-tsan-rel",
 )
 
diff --git a/ios/chrome/browser/ui/infobars/presentation/infobar_banner_presentation_controller.mm b/ios/chrome/browser/ui/infobars/presentation/infobar_banner_presentation_controller.mm
index 62eef948..263b0103 100644
--- a/ios/chrome/browser/ui/infobars/presentation/infobar_banner_presentation_controller.mm
+++ b/ios/chrome/browser/ui/infobars/presentation/infobar_banner_presentation_controller.mm
@@ -21,7 +21,7 @@
 const CGFloat kContainerMaxHeight = 230;
 // Minimum height or width frame change that should warrant a resizing of the
 // container view in response to a relayout.
-const CGFloat kMinimumSizeChange = 0.01;
+const CGFloat kMinimumSizeChange = 0.5;
 }
 
 @interface InfobarBannerPresentationController ()
@@ -122,8 +122,16 @@
   }
 
   UIView* bannerView = self.presentedView;
-  bannerView.frame = [bannerView.superview convertRect:bannerFrame
-                                              fromView:window];
+  CGRect newFrame = [bannerView.superview convertRect:bannerFrame
+                                             fromView:window];
+  if (std::fabs(newFrame.size.height - bannerView.frame.size.height) >
+          kMinimumSizeChange ||
+      std::fabs(newFrame.size.width - bannerView.frame.size.width) >
+          kMinimumSizeChange) {
+    bannerView.frame = newFrame;
+    self.needsLayout = YES;
+  }
+
   [super containerViewWillLayoutSubviews];
 }
 
diff --git a/ios/chrome/browser/ui/overlays/overlay_presentation_controller.h b/ios/chrome/browser/ui/overlays/overlay_presentation_controller.h
index 20cf30db..64de6690 100644
--- a/ios/chrome/browser/ui/overlays/overlay_presentation_controller.h
+++ b/ios/chrome/browser/ui/overlays/overlay_presentation_controller.h
@@ -21,6 +21,12 @@
 // the presenter.  Returns NO by default.
 @property(nonatomic, readonly) BOOL resizesPresentationContainer;
 
+// YES if the presented view was resized and therefore the presenting view
+// controller needs a new layout pass. Defaults to YES to allow for a layout
+// pass the first time through since the presenting view controller needs to
+// resize from CGRectZero to the presented view size or vice versa.
+@property(nonatomic, assign) BOOL needsLayout;
+
 // Subclasses must notify the superclass when their container views lay out
 // their subviews.
 - (void)containerViewWillLayoutSubviews NS_REQUIRES_SUPER;
diff --git a/ios/chrome/browser/ui/overlays/overlay_presentation_controller.mm b/ios/chrome/browser/ui/overlays/overlay_presentation_controller.mm
index c7ca8b8..02c73a7 100644
--- a/ios/chrome/browser/ui/overlays/overlay_presentation_controller.mm
+++ b/ios/chrome/browser/ui/overlays/overlay_presentation_controller.mm
@@ -10,6 +10,18 @@
 
 @implementation OverlayPresentationController
 
+- (instancetype)
+    initWithPresentedViewController:(UIViewController*)presentedViewController
+           presentingViewController:
+               (nullable UIViewController*)presentingViewController {
+  self = [super initWithPresentedViewController:presentedViewController
+                       presentingViewController:presentingViewController];
+  if (self) {
+    _needsLayout = YES;
+  }
+  return self;
+}
+
 #pragma mark - Accessors
 
 - (BOOL)resizesPresentationContainer {
@@ -27,7 +39,10 @@
   // Trigger a layout pass for the presenting view controller.  This allows the
   // presentation context to resize itself to match the presented overlay UI if
   // |resizesPresentationContainer| is YES.
-  [self.presentingViewController.view setNeedsLayout];
+  if (self.needsLayout) {
+    [self.presentingViewController.view setNeedsLayout];
+    self.needsLayout = NO;
+  }
 }
 
 @end
diff --git a/ios/web/navigation/crw_wk_navigation_handler.mm b/ios/web/navigation/crw_wk_navigation_handler.mm
index e9e15e9..5b755c4b 100644
--- a/ios/web/navigation/crw_wk_navigation_handler.mm
+++ b/ios/web/navigation/crw_wk_navigation_handler.mm
@@ -5,7 +5,6 @@
 #import "ios/web/navigation/crw_wk_navigation_handler.h"
 
 #include "base/feature_list.h"
-#include "base/ios/ios_util.h"
 #import "base/ios/ns_error_util.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
@@ -1758,8 +1757,7 @@
         web::RequiresProvisionalNavigationFailureWorkaround()) {
       // It is likely that |navigationContext| is null because
       // didStartProvisionalNavigation: was not called with this WKNavigation
-      // object, which was pretty common on iOS 12 and fixed on iOS 13.
-      // See crbug.com/973653 and crbug.com/1004634 for details.
+      // object.
       return;
     }
   }
@@ -1997,10 +1995,13 @@
     }
 
     if (provisionalLoad) {
-      if (base::ios::IsRunningOnIOS13OrLater() || navigationContext) {
+      if (!navigationContext &&
+          web::RequiresProvisionalNavigationFailureWorkaround()) {
         // It is likely that |navigationContext| is null because
         // didStartProvisionalNavigation: was not called with this WKNavigation
-        // object. See crbug.com/973653 for details.
+        // object. Do not call OnNavigationFinished() to avoid crash on null
+        // pointer dereferencing. See crbug.com/973653 for details.
+      } else {
         self.webStateImpl->OnNavigationFinished(navigationContext.get());
       }
     }
diff --git a/mojo/core/channel_fuchsia.cc b/mojo/core/channel_fuchsia.cc
index 08cdf98c..eb4356c 100644
--- a/mojo/core/channel_fuchsia.cc
+++ b/mojo/core/channel_fuchsia.cc
@@ -12,6 +12,7 @@
 #include <zircon/status.h>
 #include <zircon/syscalls.h>
 #include <algorithm>
+#include <memory>
 
 #include "base/bind.h"
 #include "base/containers/circular_deque.h"
@@ -245,8 +246,9 @@
 
     base::CurrentThread::Get()->AddDestructionObserver(this);
 
-    read_watch_.reset(
-        new base::MessagePumpForIO::ZxHandleWatchController(FROM_HERE));
+    read_watch_ =
+        std::make_unique<base::MessagePumpForIO::ZxHandleWatchController>(
+            FROM_HERE);
     base::CurrentIOThread::Get()->WatchZxHandle(
         handle_.get(), true /* persistent */,
         ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED, read_watch_.get(), this);
diff --git a/pdf/pdf_view_web_plugin_unittest.cc b/pdf/pdf_view_web_plugin_unittest.cc
index 29889cf..9234340 100644
--- a/pdf/pdf_view_web_plugin_unittest.cc
+++ b/pdf/pdf_view_web_plugin_unittest.cc
@@ -5,6 +5,7 @@
 #include "pdf/pdf_view_web_plugin.h"
 
 #include <memory>
+#include <string>
 #include <utility>
 
 #include "cc/paint/paint_canvas.h"
@@ -14,6 +15,7 @@
 #include "pdf/test/test_helpers.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/platform/web_text_input_type.h"
 #include "third_party/blink/public/web/web_associated_url_loader.h"
 #include "third_party/blink/public/web/web_plugin_params.h"
@@ -67,6 +69,10 @@
   return expected_bitmap;
 }
 
+MATCHER_P(EqualsWebString, selected_string, "") {
+  return arg.Utf8() == selected_string;
+}
+
 class FakeContainerWrapper final : public PdfViewWebPlugin::ContainerWrapper {
  public:
   explicit FakeContainerWrapper(PdfViewWebPlugin* web_plugin)
@@ -282,6 +288,31 @@
   }
 }
 
+TEST_F(PdfViewWebPluginTest, ChangeTextSelection) {
+  ASSERT_FALSE(plugin_->HasSelection());
+  ASSERT_TRUE(plugin_->SelectionAsText().IsEmpty());
+  ASSERT_TRUE(plugin_->SelectionAsMarkup().IsEmpty());
+
+  testing::InSequence s;
+  static constexpr char kSelectedText[] = "1234";
+  EXPECT_CALL(*wrapper_ptr_,
+              TextSelectionChanged(EqualsWebString(kSelectedText), 0,
+                                   gfx::Range(0, 4)));
+
+  plugin_->SetSelectedText(kSelectedText);
+  EXPECT_TRUE(plugin_->HasSelection());
+  EXPECT_EQ(kSelectedText, plugin_->SelectionAsText().Utf8());
+  EXPECT_EQ(kSelectedText, plugin_->SelectionAsMarkup().Utf8());
+
+  static constexpr char kEmptyText[] = "";
+  EXPECT_CALL(*wrapper_ptr_, TextSelectionChanged(EqualsWebString(kEmptyText),
+                                                  0, gfx::Range(0, 0)));
+  plugin_->SetSelectedText(kEmptyText);
+  EXPECT_FALSE(plugin_->HasSelection());
+  EXPECT_TRUE(plugin_->SelectionAsText().IsEmpty());
+  EXPECT_TRUE(plugin_->SelectionAsMarkup().IsEmpty());
+}
+
 TEST_F(PdfViewWebPluginTest, FormTextFieldFocusChangeUpdatesTextInputType) {
   ASSERT_EQ(blink::WebTextInputType::kWebTextInputTypeNone,
             wrapper_ptr_->widget_text_input_type());
diff --git a/services/device/fingerprint/fingerprint_chromeos.cc b/services/device/fingerprint/fingerprint_chromeos.cc
index 6b11e1e..e0c6d86 100644
--- a/services/device/fingerprint/fingerprint_chromeos.cc
+++ b/services/device/fingerprint/fingerprint_chromeos.cc
@@ -137,9 +137,8 @@
 void FingerprintChromeOS::RequestRecordLabel(
     const std::string& record_path,
     RequestRecordLabelCallback callback) {
-  GetBiodClient()->RequestRecordLabel(
-      dbus::ObjectPath(record_path),
-      base::AdaptCallbackForRepeating(std::move(callback)));
+  GetBiodClient()->RequestRecordLabel(dbus::ObjectPath(record_path),
+                                      std::move(callback));
 }
 
 void FingerprintChromeOS::SetRecordLabel(const std::string& new_label,
diff --git a/services/device/hid/hid_manager_impl.cc b/services/device/hid/hid_manager_impl.cc
index 0ea50a9c..aaca19b 100644
--- a/services/device/hid/hid_manager_impl.cc
+++ b/services/device/hid/hid_manager_impl.cc
@@ -80,11 +80,11 @@
     mojo::PendingRemote<mojom::HidConnectionWatcher> watcher,
     bool allow_protected_reports,
     ConnectCallback callback) {
-  hid_service_->Connect(device_guid, allow_protected_reports,
-                        base::AdaptCallbackForRepeating(base::BindOnce(
-                            &HidManagerImpl::CreateConnection,
-                            weak_factory_.GetWeakPtr(), std::move(callback),
-                            std::move(connection_client), std::move(watcher))));
+  hid_service_->Connect(
+      device_guid, allow_protected_reports,
+      base::BindOnce(&HidManagerImpl::CreateConnection,
+                     weak_factory_.GetWeakPtr(), std::move(callback),
+                     std::move(connection_client), std::move(watcher)));
 }
 
 void HidManagerImpl::CreateConnection(
diff --git a/services/device/hid/hid_service_linux.cc b/services/device/hid/hid_service_linux.cc
index cf413ec..9a9c71e 100644
--- a/services/device/hid/hid_service_linux.cc
+++ b/services/device/hid/hid_service_linux.cc
@@ -378,17 +378,16 @@
   scoped_refptr<HidDeviceInfo> device_info = map_entry->second;
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  // Adapt |callback| to a repeating callback because the implementation below
-  // requires separate callbacks for success and error. Only one will be called.
-  auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
+  auto split_callback = base::SplitOnceCallback(std::move(callback));
   chromeos::PermissionBrokerClient::Get()->OpenPath(
       device_info->device_node(),
       base::BindOnce(
           &HidServiceLinux::OnPathOpenComplete,
           std::make_unique<ConnectParams>(device_info, allow_protected_reports,
-                                          copyable_callback)),
+                                          std::move(split_callback.first))),
       base::BindOnce(&HidServiceLinux::OnPathOpenError,
-                     device_info->device_node(), copyable_callback));
+                     device_info->device_node(),
+                     std::move(split_callback.second)));
 #else
   auto params = std::make_unique<ConnectParams>(
       device_info, allow_protected_reports, std::move(callback));
diff --git a/services/device/public/cpp/geolocation/geolocation_manager_impl_mac.mm b/services/device/public/cpp/geolocation/geolocation_manager_impl_mac.mm
index ae252c3..4a6caa55 100644
--- a/services/device/public/cpp/geolocation/geolocation_manager_impl_mac.mm
+++ b/services/device/public/cpp/geolocation/geolocation_manager_impl_mac.mm
@@ -16,7 +16,8 @@
   base::WeakPtr<device::GeolocationManagerImpl> _manager;
 }
 
-- (id)initWithManager:(base::WeakPtr<device::GeolocationManagerImpl>)manager;
+- (instancetype)initWithManager:
+    (base::WeakPtr<device::GeolocationManagerImpl>)manager;
 
 // CLLocationManagerDelegate
 - (void)locationManager:(CLLocationManager*)manager
@@ -83,7 +84,8 @@
 
 @implementation GeolocationManagerDelegate
 
-- (id)initWithManager:(base::WeakPtr<device::GeolocationManagerImpl>)manager {
+- (instancetype)initWithManager:
+    (base::WeakPtr<device::GeolocationManagerImpl>)manager {
   if (self = [super init]) {
     _permissionInitialized = NO;
     _hasPermission = NO;
diff --git a/services/device/serial/bluetooth_serial_port_impl.cc b/services/device/serial/bluetooth_serial_port_impl.cc
index 78c415dd..ce01294 100644
--- a/services/device/serial/bluetooth_serial_port_impl.cc
+++ b/services/device/serial/bluetooth_serial_port_impl.cc
@@ -67,14 +67,15 @@
 
   BluetoothDevice::UUIDSet device_uuids = device->GetUUIDs();
   if (base::Contains(device_uuids, GetSerialPortProfileUUID())) {
-    auto copyable_callback =
-        base::AdaptCallbackForRepeating(std::move(callback));
+    auto split_callback = base::SplitOnceCallback(std::move(callback));
     device->ConnectToService(
         GetSerialPortProfileUUID(),
         base::BindOnce(&BluetoothSerialPortImpl::OnSocketConnected,
-                       weak_ptr_factory_.GetWeakPtr(), copyable_callback),
+                       weak_ptr_factory_.GetWeakPtr(),
+                       std::move(split_callback.first)),
         base::BindOnce(&BluetoothSerialPortImpl::OnSocketConnectedError,
-                       weak_ptr_factory_.GetWeakPtr(), copyable_callback));
+                       weak_ptr_factory_.GetWeakPtr(),
+                       std::move(split_callback.second)));
     return;
   }
 
diff --git a/services/device/usb/mojo/device_manager_impl.cc b/services/device/usb/mojo/device_manager_impl.cc
index 528e0dd..3c963cc 100644
--- a/services/device/usb/mojo/device_manager_impl.cc
+++ b/services/device/usb/mojo/device_manager_impl.cc
@@ -141,8 +141,7 @@
     LOG(ERROR) << "Was asked to open non-existent USB device: " << guid;
     std::move(callback).Run(base::File());
   } else {
-    auto copyable_callback =
-        base::AdaptCallbackForRepeating(std::move(callback));
+    auto split_callback = base::SplitOnceCallback(std::move(callback));
     auto devpath =
         static_cast<device::UsbDeviceLinux*>(device.get())->device_path();
 
@@ -151,9 +150,11 @@
     chromeos::PermissionBrokerClient::Get()->ClaimDevicePath(
         devpath, drop_privileges_mask, lifeline_fd.GetFD().get(),
         base::BindOnce(&DeviceManagerImpl::OnOpenFileDescriptor,
-                       weak_factory_.GetWeakPtr(), copyable_callback),
+                       weak_factory_.GetWeakPtr(),
+                       std::move(split_callback.first)),
         base::BindOnce(&DeviceManagerImpl::OnOpenFileDescriptorError,
-                       weak_factory_.GetWeakPtr(), copyable_callback));
+                       weak_factory_.GetWeakPtr(),
+                       std::move(split_callback.second)));
   }
 }
 
diff --git a/services/device/usb/usb_device_linux.cc b/services/device/usb/usb_device_linux.cc
index c02bcf4..de5e39d 100644
--- a/services/device/usb/usb_device_linux.cc
+++ b/services/device/usb/usb_device_linux.cc
@@ -63,13 +63,13 @@
     return;
   }
 
-  auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
+  auto split_callback = base::SplitOnceCallback(std::move(callback));
   chromeos::PermissionBrokerClient::Get()->ClaimDevicePath(
       device_path_, kAllInterfacesMask, read_end.get(),
       base::BindOnce(&UsbDeviceLinux::OnOpenRequestComplete, this,
-                     copyable_callback, std::move(write_end)),
+                     std::move(split_callback.first), std::move(write_end)),
       base::BindOnce(&UsbDeviceLinux::OnOpenRequestError, this,
-                     copyable_callback));
+                     std::move(split_callback.second)));
 #else
   scoped_refptr<base::SequencedTaskRunner> blocking_task_runner =
       UsbService::CreateBlockingTaskRunner();
diff --git a/services/shape_detection/barcode_detection_impl_mac_unittest.mm b/services/shape_detection/barcode_detection_impl_mac_unittest.mm
index 33effd7..62a57d72 100644
--- a/services/shape_detection/barcode_detection_impl_mac_unittest.mm
+++ b/services/shape_detection/barcode_detection_impl_mac_unittest.mm
@@ -16,6 +16,7 @@
 #include "base/mac/scoped_cftyperef.h"
 #include "base/mac/scoped_nsobject.h"
 #include "base/run_loop.h"
+#include "base/strings/sys_string_conversions.h"
 #include "base/test/gmock_callback_support.h"
 #include "base/test/task_environment.h"
 #include "services/shape_detection/barcode_detection_impl_mac_vision.h"
@@ -121,9 +122,8 @@
   impl_ = GetParam().factory.Run(mojom::BarcodeDetectorOptions::New());
 
   // Generate a barcode image as a CIImage by using |qr_code_generator|.
-  NSData* const qr_code_data =
-      [[NSString stringWithUTF8String:kInfoString.c_str()]
-          dataUsingEncoding:NSISOLatin1StringEncoding];
+  NSData* const qr_code_data = [base::SysUTF8ToNSString(kInfoString)
+      dataUsingEncoding:NSISOLatin1StringEncoding];
 
   CIFilter* qr_code_generator =
       [CIFilter filterWithName:GetParam().test_code_generator];
diff --git a/services/shape_detection/barcode_detection_provider_mac_unittest.mm b/services/shape_detection/barcode_detection_provider_mac_unittest.mm
index 924a7a91..b23b69ce 100644
--- a/services/shape_detection/barcode_detection_provider_mac_unittest.mm
+++ b/services/shape_detection/barcode_detection_provider_mac_unittest.mm
@@ -199,7 +199,7 @@
   }
 
   std::unique_ptr<VisionAPIInterface> mock_vision_api =
-      CreateMockVisionAPI([NSArray array]);
+      CreateMockVisionAPI(@[]);
 
   provider_ = CreateBarcodeProviderMac(std::move(mock_vision_api));
   provider_->EnumerateSupportedFormats(base::BindOnce(
diff --git a/services/shape_detection/text_detection_impl_mac_unittest.mm b/services/shape_detection/text_detection_impl_mac_unittest.mm
index f128391..99dadda 100644
--- a/services/shape_detection/text_detection_impl_mac_unittest.mm
+++ b/services/shape_detection/text_detection_impl_mac_unittest.mm
@@ -67,8 +67,7 @@
   // Create a line of Helvetica 16 text, and draw it in the |context|.
   base::scoped_nsobject<NSFont> helvetica([NSFont fontWithName:@"Helvetica"
                                                           size:16]);
-  NSDictionary* attributes = [NSDictionary
-      dictionaryWithObjectsAndKeys:helvetica, kCTFontAttributeName, nil];
+  NSDictionary* attributes = @{(id)kCTFontAttributeName : helvetica};
 
   base::scoped_nsobject<NSAttributedString> info([[NSAttributedString alloc]
       initWithString:@"https://www.chromium.org"
diff --git a/styleguide/python/python.md b/styleguide/python/python.md
index f56902d..42f1307 100644
--- a/styleguide/python/python.md
+++ b/styleguide/python/python.md
@@ -3,6 +3,38 @@
 _For other languages, please see the [Chromium style
 guides](https://chromium.googlesource.com/chromium/src/+/master/styleguide/styleguide.md)._
 
+As of 2021-05-12, Chromium is transitioning from Python 2 to Python 3 (follow
+[crbug.com/941669](https://crbug.com/941669) for updates). See
+[//docs/python3_migration.md](../docs/python3_migration.md) for more on
+how to migrate code.
+
+For new (Python 3) code, you can assume Python 3.8 (and that's what the bots
+will use), but we are increasingly seeing people running 3.9 locally as well.
+
+We (often) use a tool called [vpython] to manage Python packages; vpython
+is a wrapper around virtualenv. However, it is not safe to use vpython
+regardless of context, as it can have performance issues. All tests are
+run under vpython, so it is safe there, but you should not use vpython
+during PRESUBMIT checks, gclient runhooks, or during the build unless
+a [//build/OWNER](../../build/OWNERS) has told you that it is okay to do so.
+
+Also, there is some performance overhead to using vpython, so prefer not
+to use vpython unless you need it (to pick up packages not available in the
+source tree).
+
+"shebang lines" (the first line of many unix scripts, like `#!/bin/sh`)
+aren't as useful as you might think in Chromium, because
+most of our python invocations come from other tools like Ninja or
+the swarming infrastructure, and they also don't work on Windows.
+So, don't expect them to help you.
+
+However, if your script is executable, you should still use one, and for
+Python you should use `#!/usr/bin/env/python3` or `#!/usr/bin/env vpython3`
+in order to pick up the right version of Python from your $PATH rather than
+assuming you want the version in `/usr/bin`; this allows you to pick up the
+versions we endorse from
+`depot_tools`.
+
 Chromium follows [PEP-8](https://www.python.org/dev/peps/pep-0008/).
 
 It is also encouraged to follow advice from
@@ -39,7 +71,7 @@
 ### pylint
 [Depot tools](http://commondatastorage.googleapis.com/chrome-infra-docs/flat/depot_tools/docs/html/depot_tools.html)
 contains a local copy of pylint, appropriately configured.
-* Directories need to opt into pylint presumbit checks via:
+* Directories need to opt into pylint presubmit checks via:
    `input_api.canned_checks.RunPylint()`.
 
 ### YAPF
@@ -74,4 +106,6 @@
 * For Chromium-specific bugs, please discuss on `python@chromium.org`.
 
 #### Editor Integration
-See: https://github.com/google/yapf/tree/master/plugins
+See: https://github.com/google/yapf/tree/main/plugins
+
+[vpython]: https://chromium.googlesource.com/infra/infra/+/refs/heads/main/doc/users/vpython.md
diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json
index 7d4d0da..b3770d6 100644
--- a/testing/buildbot/chromium.clang.json
+++ b/testing/buildbot/chromium.clang.json
@@ -23206,7 +23206,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23224,7 +23224,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23245,7 +23245,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23264,7 +23264,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23282,7 +23282,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23300,7 +23300,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23318,7 +23318,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23336,7 +23336,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23354,7 +23354,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23372,7 +23372,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23391,7 +23391,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23409,7 +23409,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23427,7 +23427,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23445,7 +23445,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -23467,7 +23467,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23485,7 +23485,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23503,7 +23503,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23521,7 +23521,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23539,7 +23539,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23557,7 +23557,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23575,7 +23575,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23593,7 +23593,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23611,7 +23611,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -23630,7 +23630,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23648,7 +23648,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23666,7 +23666,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23684,7 +23684,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23702,7 +23702,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23720,7 +23720,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23738,7 +23738,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23756,7 +23756,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23774,7 +23774,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23792,7 +23792,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23810,7 +23810,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23828,7 +23828,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23846,7 +23846,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23864,7 +23864,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23882,7 +23882,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23900,7 +23900,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23918,7 +23918,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23936,7 +23936,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23954,7 +23954,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23972,7 +23972,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -23990,7 +23990,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -24009,7 +24009,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24027,7 +24027,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24045,7 +24045,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24063,7 +24063,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24081,7 +24081,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24099,7 +24099,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24117,7 +24117,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24135,7 +24135,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24153,7 +24153,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24171,7 +24171,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24189,7 +24189,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24207,7 +24207,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24225,7 +24225,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24243,7 +24243,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24261,7 +24261,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24279,7 +24279,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24297,7 +24297,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24315,7 +24315,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24333,7 +24333,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24351,7 +24351,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24369,7 +24369,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24387,7 +24387,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24405,7 +24405,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24423,7 +24423,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24441,7 +24441,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24459,7 +24459,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24477,7 +24477,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24495,7 +24495,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24513,7 +24513,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24531,7 +24531,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24549,7 +24549,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24567,7 +24567,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24585,7 +24585,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24603,7 +24603,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24621,7 +24621,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24639,7 +24639,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24658,7 +24658,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24676,7 +24676,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24701,7 +24701,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24729,7 +24729,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -24751,7 +24751,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24776,7 +24776,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24795,7 +24795,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24819,7 +24819,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24842,7 +24842,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24865,7 +24865,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24887,7 +24887,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24906,7 +24906,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24928,7 +24928,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24950,7 +24950,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -24972,7 +24972,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "idempotent": false,
@@ -24998,7 +24998,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "idempotent": false,
@@ -25026,7 +25026,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "idempotent": false,
@@ -25052,7 +25052,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25080,7 +25080,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25107,7 +25107,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25128,7 +25128,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25150,7 +25150,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25172,7 +25172,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25193,7 +25193,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25214,7 +25214,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25235,7 +25235,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25256,7 +25256,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25277,7 +25277,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25298,7 +25298,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25320,7 +25320,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25341,7 +25341,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25362,7 +25362,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25383,7 +25383,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -25406,7 +25406,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25427,7 +25427,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25448,7 +25448,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25469,7 +25469,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25490,7 +25490,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25511,7 +25511,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25532,7 +25532,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25553,7 +25553,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25574,7 +25574,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -25596,7 +25596,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25617,7 +25617,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25638,7 +25638,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25659,7 +25659,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25680,7 +25680,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25701,7 +25701,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25722,7 +25722,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25743,7 +25743,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25764,7 +25764,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25785,7 +25785,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25806,7 +25806,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25827,7 +25827,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25848,7 +25848,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25869,7 +25869,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25890,7 +25890,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25911,7 +25911,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25932,7 +25932,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25953,7 +25953,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25974,7 +25974,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -25995,7 +25995,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26016,7 +26016,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -26038,7 +26038,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26059,7 +26059,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26080,7 +26080,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26101,7 +26101,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26122,7 +26122,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26143,7 +26143,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26164,7 +26164,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26185,7 +26185,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26206,7 +26206,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26227,7 +26227,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26248,7 +26248,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26269,7 +26269,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26290,7 +26290,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26311,7 +26311,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26332,7 +26332,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26353,7 +26353,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26374,7 +26374,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26395,7 +26395,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26416,7 +26416,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26437,7 +26437,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26458,7 +26458,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26479,7 +26479,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26500,7 +26500,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26521,7 +26521,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26542,7 +26542,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26563,7 +26563,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26584,7 +26584,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26605,7 +26605,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26626,7 +26626,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26647,7 +26647,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26668,7 +26668,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26689,7 +26689,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26710,7 +26710,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26731,7 +26731,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26752,7 +26752,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26774,7 +26774,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26795,7 +26795,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26820,7 +26820,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26838,7 +26838,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26859,7 +26859,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26878,7 +26878,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26896,7 +26896,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26914,7 +26914,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26932,7 +26932,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26950,7 +26950,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26968,7 +26968,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -26986,7 +26986,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27005,7 +27005,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27023,7 +27023,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27041,7 +27041,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27059,7 +27059,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -27081,7 +27081,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27099,7 +27099,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27117,7 +27117,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27135,7 +27135,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27153,7 +27153,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27171,7 +27171,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27189,7 +27189,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27207,7 +27207,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27225,7 +27225,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -27244,7 +27244,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27262,7 +27262,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27280,7 +27280,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27298,7 +27298,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27316,7 +27316,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27334,7 +27334,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27352,7 +27352,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27370,7 +27370,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27388,7 +27388,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27406,7 +27406,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27424,7 +27424,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27442,7 +27442,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27460,7 +27460,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27478,7 +27478,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27496,7 +27496,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27514,7 +27514,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27532,7 +27532,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27550,7 +27550,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27568,7 +27568,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27586,7 +27586,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27604,7 +27604,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -27623,7 +27623,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27641,7 +27641,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27659,7 +27659,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27677,7 +27677,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27695,7 +27695,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27713,7 +27713,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27731,7 +27731,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27749,7 +27749,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27767,7 +27767,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27785,7 +27785,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27803,7 +27803,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27821,7 +27821,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27839,7 +27839,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27857,7 +27857,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27875,7 +27875,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27893,7 +27893,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27911,7 +27911,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27929,7 +27929,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27947,7 +27947,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27965,7 +27965,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -27983,7 +27983,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28001,7 +28001,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28019,7 +28019,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28037,7 +28037,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28055,7 +28055,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28073,7 +28073,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28091,7 +28091,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28109,7 +28109,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28127,7 +28127,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28145,7 +28145,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28163,7 +28163,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28181,7 +28181,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28199,7 +28199,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28217,7 +28217,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28235,7 +28235,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28253,7 +28253,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28272,7 +28272,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28290,7 +28290,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28315,7 +28315,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28343,7 +28343,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -28365,7 +28365,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28390,7 +28390,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28409,7 +28409,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28433,7 +28433,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28456,7 +28456,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28479,7 +28479,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28501,7 +28501,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28520,7 +28520,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28542,7 +28542,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28564,7 +28564,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -28586,7 +28586,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "idempotent": false,
@@ -28612,7 +28612,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "idempotent": false,
@@ -28640,7 +28640,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "idempotent": false,
@@ -28666,7 +28666,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
diff --git a/testing/buildbot/chromium.dev.json b/testing/buildbot/chromium.dev.json
index 22f46618..db2fb60 100644
--- a/testing/buildbot/chromium.dev.json
+++ b/testing/buildbot/chromium.dev.json
@@ -1244,7 +1244,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester-dev@chops-service-accounts.iam.gserviceaccount.com"
@@ -1262,7 +1262,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester-dev@chops-service-accounts.iam.gserviceaccount.com"
@@ -1280,7 +1280,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester-dev@chops-service-accounts.iam.gserviceaccount.com"
@@ -1298,7 +1298,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester-dev@chops-service-accounts.iam.gserviceaccount.com"
@@ -1316,7 +1316,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester-dev@chops-service-accounts.iam.gserviceaccount.com"
@@ -1334,7 +1334,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester-dev@chops-service-accounts.iam.gserviceaccount.com"
diff --git a/testing/buildbot/chromium.goma.json b/testing/buildbot/chromium.goma.json
index 351e79a..405a94a 100644
--- a/testing/buildbot/chromium.goma.json
+++ b/testing/buildbot/chromium.goma.json
@@ -190,7 +190,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -208,7 +208,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -233,7 +233,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -251,7 +251,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -276,7 +276,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -294,7 +294,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -319,7 +319,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -337,7 +337,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
diff --git a/testing/buildbot/chromium.json b/testing/buildbot/chromium.json
index 115d4b0..78fa9ef 100644
--- a/testing/buildbot/chromium.json
+++ b/testing/buildbot/chromium.json
@@ -57,16 +57,7 @@
     "additional_compile_targets": [
       "all"
     ],
-    "scripts": [
-      {
-        "args": [
-          "mac-release/sizes"
-        ],
-        "name": "checkbins",
-        "script": "checkbins.py",
-        "swarming": {}
-      }
-    ]
+    "scripts": []
   },
   "mac-official": {
     "additional_compile_targets": [
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 345f78e..072844b 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -18083,2018 +18083,6 @@
       }
     ]
   },
-  "linux-experimental-next-rel": {
-    "gtest_tests": [
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "absl_hardening_tests",
-        "test_id_prefix": "ninja://third_party/abseil-cpp:absl_hardening_tests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "accessibility_unittests",
-        "test_id_prefix": "ninja://ui/accessibility:accessibility_unittests/"
-      },
-      {
-        "args": [
-          "angle_unittests"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_unittests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_unittests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "app_shell_unittests",
-        "test_id_prefix": "ninja://extensions/shell:app_shell_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "aura_unittests",
-        "test_id_prefix": "ninja://ui/aura:aura_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "base_unittests",
-        "test_id_prefix": "ninja://base:base_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "base_util_unittests",
-        "test_id_prefix": "ninja://base/util:base_util_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_common_unittests",
-        "test_id_prefix": "ninja://third_party/blink/common:blink_common_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_fuzzer_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform:blink_fuzzer_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_heap_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform/heap:blink_heap_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_platform_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform:blink_platform_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "webkit_unit_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/controller:blink_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "boringssl_crypto_tests",
-        "test_id_prefix": "ninja://third_party/boringssl:boringssl_crypto_tests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "boringssl_ssl_tests",
-        "test_id_prefix": "ninja://third_party/boringssl:boringssl_ssl_tests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 10
-        },
-        "test": "browser_tests",
-        "test_id_prefix": "ninja://chrome/test:browser_tests/"
-      },
-      {
-        "args": [
-          "--gtest_filter=-*UsingRealWebcam*"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "capture_unittests",
-        "test_id_prefix": "ninja://media/capture:capture_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "cast_unittests",
-        "test_id_prefix": "ninja://media/cast:cast_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "cc_unittests",
-        "test_id_prefix": "ninja://cc:cc_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chrome_app_unittests",
-        "test_id_prefix": "ninja://chrome/test:chrome_app_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chromedriver_unittests",
-        "test_id_prefix": "ninja://chrome/test/chromedriver:chromedriver_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "color_unittests",
-        "test_id_prefix": "ninja://ui/color:color_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "components_browsertests",
-        "test_id_prefix": "ninja://components:components_browsertests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "components_unittests",
-        "test_id_prefix": "ninja://components:components_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "compositor_unittests",
-        "test_id_prefix": "ninja://ui/compositor:compositor_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 6
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "content_unittests",
-        "test_id_prefix": "ninja://content/test:content_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "crashpad_tests",
-        "test_id_prefix": "ninja://third_party/crashpad/crashpad:crashpad_tests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "cronet_tests",
-        "test_id_prefix": "ninja://components/cronet:cronet_tests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "cronet_unittests",
-        "test_id_prefix": "ninja://components/cronet:cronet_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "crypto_unittests",
-        "test_id_prefix": "ninja://crypto:crypto_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "dbus_unittests",
-        "test_id_prefix": "ninja://dbus:dbus_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "device_unittests",
-        "test_id_prefix": "ninja://device:device_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "display_unittests",
-        "test_id_prefix": "ninja://ui/display:display_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "events_unittests",
-        "test_id_prefix": "ninja://ui/events:events_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_unittests",
-        "test_id_prefix": "ninja://extensions:extensions_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "filesystem_service_unittests",
-        "test_id_prefix": "ninja://components/services/filesystem:filesystem_service_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gcm_unit_tests",
-        "test_id_prefix": "ninja://google_apis/gcm:gcm_unit_tests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gfx_unittests",
-        "test_id_prefix": "ninja://ui/gfx:gfx_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gin_unittests",
-        "test_id_prefix": "ninja://gin:gin_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "google_apis_unittests",
-        "test_id_prefix": "ninja://google_apis:google_apis_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gpu_unittests",
-        "test_id_prefix": "ninja://gpu:gpu_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gtk_unittests",
-        "test_id_prefix": "ninja://ui/gtk:gtk_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gwp_asan_unittests",
-        "test_id_prefix": "ninja://components/gwp_asan:gwp_asan_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "headless_browsertests",
-        "test_id_prefix": "ninja://headless:headless_browsertests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "headless_unittests",
-        "test_id_prefix": "ninja://headless:headless_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ipc_tests",
-        "test_id_prefix": "ninja://ipc:ipc_tests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "jingle_unittests",
-        "test_id_prefix": "ninja://jingle:jingle_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "latency_unittests",
-        "test_id_prefix": "ninja://ui/latency:latency_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "libjingle_xmpp_unittests",
-        "test_id_prefix": "ninja://third_party/libjingle_xmpp:libjingle_xmpp_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "liburlpattern_unittests",
-        "test_id_prefix": "ninja://third_party/liburlpattern:liburlpattern_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "media_blink_unittests",
-        "test_id_prefix": "ninja://media/blink:media_blink_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "media_unittests",
-        "test_id_prefix": "ninja://media:media_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "message_center_unittests",
-        "test_id_prefix": "ninja://ui/message_center:message_center_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "midi_unittests",
-        "test_id_prefix": "ninja://media/midi:midi_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "mojo_core_unittests",
-        "test_id_prefix": "ninja://mojo/core:mojo_core_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "mojo_unittests",
-        "test_id_prefix": "ninja://mojo:mojo_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "nacl_helper_nonsfi_unittests",
-        "test_id_prefix": "ninja://components/nacl/loader:nacl_helper_nonsfi_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "nacl_loader_unittests",
-        "test_id_prefix": "ninja://components/nacl/loader:nacl_loader_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "native_theme_unittests",
-        "test_id_prefix": "ninja://ui/native_theme:native_theme_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "net_unittests",
-        "test_id_prefix": "ninja://net:net_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "openscreen_unittests",
-        "test_id_prefix": "ninja://chrome/browser/media/router:openscreen_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "pdf_unittests",
-        "test_id_prefix": "ninja://pdf:pdf_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "perfetto_unittests",
-        "test_id_prefix": "ninja://third_party/perfetto:perfetto_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ppapi_unittests",
-        "test_id_prefix": "ninja://ppapi:ppapi_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "printing_unittests",
-        "test_id_prefix": "ninja://printing:printing_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "remoting_unittests",
-        "test_id_prefix": "ninja://remoting:remoting_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "sandbox_linux_unittests",
-        "test_id_prefix": "ninja://sandbox/linux:sandbox_linux_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "service_manager_unittests",
-        "test_id_prefix": "ninja://services/service_manager/tests:service_manager_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "services_unittests",
-        "test_id_prefix": "ninja://services:services_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "shell_dialogs_unittests",
-        "test_id_prefix": "ninja://ui/shell_dialogs:shell_dialogs_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "skia_unittests",
-        "test_id_prefix": "ninja://skia:skia_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "snapshot_unittests",
-        "test_id_prefix": "ninja://ui/snapshot:snapshot_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "sql_unittests",
-        "test_id_prefix": "ninja://sql:sql_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "storage_unittests",
-        "test_id_prefix": "ninja://storage:storage_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "sync_integration_tests",
-        "test_id_prefix": "ninja://chrome/test:sync_integration_tests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "traffic_annotation_auditor_unittests",
-        "test_id_prefix": "ninja://tools/traffic_annotation/auditor:traffic_annotation_auditor_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ui_base_unittests",
-        "test_id_prefix": "ninja://ui/base:ui_base_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ui_touch_selection_unittests",
-        "test_id_prefix": "ninja://ui/touch_selection:ui_touch_selection_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "unit_tests",
-        "test_id_prefix": "ninja://chrome/test:unit_tests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "url_unittests",
-        "test_id_prefix": "ninja://url:url_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "views_unittests",
-        "test_id_prefix": "ninja://ui/views:views_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "viz_unittests",
-        "test_id_prefix": "ninja://components/viz:viz_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "vr_common_unittests",
-        "test_id_prefix": "ninja://chrome/browser/vr:vr_common_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "vr_pixeltests",
-        "test_id_prefix": "ninja://chrome/browser/vr:vr_pixeltests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "weblayer_browsertests",
-        "test_id_prefix": "ninja://weblayer/test:weblayer_browsertests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "weblayer_unittests",
-        "test_id_prefix": "ninja://weblayer/test:weblayer_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "wm_unittests",
-        "test_id_prefix": "ninja://ui/wm:wm_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "wtf_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform/wtf:wtf_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "x11_unittests",
-        "test_id_prefix": "ninja://ui/platform_window/x11:x11_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "xr_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "xr_browser_tests",
-        "test_id_prefix": "ninja://chrome/test:xr_browser_tests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "zlib_unittests",
-        "test_id_prefix": "ninja://third_party/zlib:zlib_unittests/"
-      }
-    ],
-    "isolated_scripts": [
-      {
-        "isolate_name": "blink_python_tests",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "blink_python_tests",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://:blink_python_tests/"
-      },
-      {
-        "args": [
-          "--num-retries=3"
-        ],
-        "isolate_name": "blink_web_tests",
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "blink_web_tests",
-        "resultdb": {
-          "enable": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 12
-        },
-        "test_id_prefix": "ninja://:blink_web_tests/"
-      },
-      {
-        "args": [
-          "--test-type=integration"
-        ],
-        "isolate_name": "chromedriver_py_tests",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "chromedriver_py_tests",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test/chromedriver:chromedriver_py_tests/"
-      },
-      {
-        "isolate_name": "chromedriver_replay_unittests",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "chromedriver_replay_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test/chromedriver:chromedriver_replay_unittests/"
-      },
-      {
-        "isolate_name": "content_shell_crash_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "content_shell_crash_test",
-        "resultdb": {
-          "enable": true,
-          "result_format": "single"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://content/shell:content_shell_crash_test/"
-      },
-      {
-        "isolate_name": "flatbuffers_unittests",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "flatbuffers_unittests",
-        "resultdb": {
-          "enable": true,
-          "result_format": "single"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://third_party/flatbuffers:flatbuffers_unittests/"
-      },
-      {
-        "isolate_name": "grit_python_unittests",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "grit_python_unittests",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://tools/grit:grit_python_unittests/"
-      },
-      {
-        "isolate_name": "metrics_python_tests",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "metrics_python_tests",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://tools/metrics:metrics_python_tests/"
-      },
-      {
-        "isolate_name": "mojo_python_unittests",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "mojo_python_unittests",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://mojo/public/tools:mojo_python_unittests/"
-      },
-      {
-        "args": [
-          "--additional-driver-flag",
-          "--disable-site-isolation-trials",
-          "--additional-expectations=../../third_party/blink/web_tests/FlagExpectations/disable-site-isolation-trials",
-          "--num-retries=3"
-        ],
-        "isolate_name": "blink_web_tests",
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "not_site_per_process_blink_web_tests",
-        "resultdb": {
-          "enable": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 10
-        },
-        "test_id_prefix": "ninja://:blink_web_tests/"
-      },
-      {
-        "isolate_name": "telemetry_gpu_unittests",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "telemetry_gpu_unittests",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_unittests/"
-      },
-      {
-        "args": [
-          "--extra-browser-args=--enable-crashpad"
-        ],
-        "isolate_name": "telemetry_perf_unittests",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "telemetry_perf_unittests",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 12
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_perf_unittests/"
-      },
-      {
-        "args": [
-          "--jobs=1",
-          "--extra-browser-args=--disable-gpu"
-        ],
-        "isolate_name": "telemetry_unittests",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "telemetry_unittests",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 8
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_unittests/"
-      },
-      {
-        "args": [
-          "--gtest-benchmark-name=views_perftests"
-        ],
-        "isolate_name": "views_perftests",
-        "merge": {
-          "args": [
-            "--smoke-test-mode"
-          ],
-          "script": "//tools/perf/process_perf_results.py"
-        },
-        "name": "views_perftests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://ui/views:views_perftests/"
-      },
-      {
-        "args": [
-          "--num-retries=3",
-          "--additional-driver-flag=--enable-gpu-rasterization",
-          "--additional-driver-flag=--enable-features=UseSkiaRenderer,Vulkan",
-          "--additional-driver-flag=--enable-oop-rasterization",
-          "--additional-driver-flag=--use-vulkan=swiftshader",
-          "--additional-driver-flag=--disable-vulkan-fallback-to-gl-for-testing",
-          "--fuzzy-diff",
-          "--skipped=always",
-          "--test-list=../../testing/buildbot/filters/gpu.skiarenderer_vulkan_blink_web_tests.filter",
-          "--additional-expectations=../../third_party/blink/web_tests/FlagExpectations/enable-features=UseSkiaRenderer",
-          "--additional-expectations=../../third_party/blink/web_tests/FlagExpectations/enable-gpu-rasterization",
-          "--additional-expectations=../../third_party/blink/web_tests/FlagExpectations/use-vulkan=swiftshader"
-        ],
-        "isolate_name": "blink_web_tests",
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "vulkan_swiftshader_blink_web_tests",
-        "resultdb": {
-          "enable": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://:blink_web_tests/"
-      },
-      {
-        "isolate_name": "webdriver_wpt_tests",
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "webdriver_tests_suite",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 4
-        },
-        "test_id_prefix": "ninja://:webdriver_wpt_tests/"
-      }
-    ],
-    "scripts": [
-      {
-        "name": "check_static_initializers",
-        "script": "check_static_initializers.py",
-        "swarming": {}
-      },
-      {
-        "name": "checkdeps",
-        "script": "checkdeps.py",
-        "swarming": {}
-      },
-      {
-        "name": "checkperms",
-        "script": "checkperms.py",
-        "swarming": {}
-      },
-      {
-        "name": "headless_python_unittests",
-        "script": "headless_python_unittests.py",
-        "swarming": {}
-      },
-      {
-        "name": "webkit_lint",
-        "script": "blink_lint_expectations.py",
-        "swarming": {}
-      }
-    ]
-  },
   "linux-extended-tracing-rel": {
     "additional_compile_targets": [
       "all"
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 14c136ad..62da1872 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -13259,7 +13259,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13280,7 +13280,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13302,7 +13302,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13324,7 +13324,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13345,7 +13345,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13366,7 +13366,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13387,7 +13387,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13408,7 +13408,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13429,7 +13429,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13450,7 +13450,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13472,7 +13472,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13493,7 +13493,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13514,7 +13514,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13536,7 +13536,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -13559,7 +13559,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13580,7 +13580,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13601,7 +13601,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13622,7 +13622,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13643,7 +13643,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13664,7 +13664,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13685,7 +13685,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13706,7 +13706,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13727,7 +13727,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -13749,7 +13749,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13770,7 +13770,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13791,7 +13791,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13812,7 +13812,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13833,7 +13833,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13854,7 +13854,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13875,7 +13875,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13896,7 +13896,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13917,7 +13917,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13938,7 +13938,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13959,7 +13959,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -13980,7 +13980,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14001,7 +14001,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14022,7 +14022,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14043,7 +14043,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14064,7 +14064,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14085,7 +14085,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14106,7 +14106,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14127,7 +14127,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14148,7 +14148,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14169,7 +14169,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -14191,7 +14191,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14212,7 +14212,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14233,7 +14233,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14254,7 +14254,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14275,7 +14275,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14296,7 +14296,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14317,7 +14317,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14338,7 +14338,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14359,7 +14359,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14380,7 +14380,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14401,7 +14401,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14422,7 +14422,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14443,7 +14443,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14464,7 +14464,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14485,7 +14485,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14506,7 +14506,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14527,7 +14527,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14548,7 +14548,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14569,7 +14569,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14590,7 +14590,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14611,7 +14611,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14632,7 +14632,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14653,7 +14653,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14674,7 +14674,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14695,7 +14695,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14716,7 +14716,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14737,7 +14737,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14758,7 +14758,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14779,7 +14779,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14800,7 +14800,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14821,7 +14821,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14842,7 +14842,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14863,7 +14863,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14884,7 +14884,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14905,7 +14905,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14927,7 +14927,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -14948,7 +14948,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
diff --git a/testing/buildbot/chromium.webrtc.json b/testing/buildbot/chromium.webrtc.json
index 2d21ea8d..bdb980d 100644
--- a/testing/buildbot/chromium.webrtc.json
+++ b/testing/buildbot/chromium.webrtc.json
@@ -369,7 +369,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -393,7 +393,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -433,7 +433,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -458,7 +458,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -484,7 +484,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -506,7 +506,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -525,7 +525,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -547,7 +547,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Mac"
+              "os": "Mac-10.15"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
diff --git a/testing/buildbot/filters/gpu.skiarenderer_vulkan_content_browsertests.filter b/testing/buildbot/filters/gpu.skiarenderer_vulkan_content_browsertests.filter
index 6cee29a6..2f26d5cd 100644
--- a/testing/buildbot/filters/gpu.skiarenderer_vulkan_content_browsertests.filter
+++ b/testing/buildbot/filters/gpu.skiarenderer_vulkan_content_browsertests.filter
@@ -10,4 +10,9 @@
 # Consistent failures.  https://crbug.com/1164594
 -SRC_ExternalClearKey/EncryptedMediaTest.Playback_VideoOnly_WebM_AV1_10bit/0
 -MSE_ExternalClearKey/EncryptedMediaTest.Playback_VideoOnly_WebM_AV1_10bit/0
--MSE_ExternalClearKey/EncryptedMediaTest.Playback_VideoOnly_MP4_AV1_10bit/0
\ No newline at end of file
+-MSE_ExternalClearKey/EncryptedMediaTest.Playback_VideoOnly_MP4_AV1_10bit/0
+
+# Consistent failures. https://crbug.com/1208515
+-FormControlsBrowserTest.Textarea
+-FormControlsBrowserTest.Select
+-FormControlsBrowserTest.Input
diff --git a/testing/buildbot/mixins.pyl b/testing/buildbot/mixins.pyl
index 0644f70..33955f1 100644
--- a/testing/buildbot/mixins.pyl
+++ b/testing/buildbot/mixins.pyl
@@ -788,11 +788,13 @@
       ],
     },
   },
+  # mac_x64 is used as a prefered OS dimension for mac platform instead of any
+  # mac OS version. It selects the most representative dimension on Swarming.
   'mac_x64': {
     'swarming': {
       'dimension_sets': [
          {
-           'os': 'Mac',
+           'os': 'Mac-10.15',
            'cpu': 'x86-64',
          },
       ],
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 07c84da..d234d756 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -829,6 +829,8 @@
       'linux-archive-rel',
       'mac-archive-dbg',
       'mac-archive-rel',
+      'mac-arm64-archive-dbg',
+      'mac-arm64-archive-rel',
     ],
   },
   'chrome_all_tast_tests': {
diff --git a/testing/buildbot/trybot_analyze_config.json b/testing/buildbot/trybot_analyze_config.json
index 5de2f821..75655d3 100644
--- a/testing/buildbot/trybot_analyze_config.json
+++ b/testing/buildbot/trybot_analyze_config.json
@@ -34,6 +34,7 @@
   },
   "chromium": {
     "exclusions": [
+      "buildtools/checkdeps/.*",
       "chrome/android/profiles/newest.txt",
       "chrome/browser/resources/.*(css|html|js)",
       "chrome/browser/ui/webui/.*browsertest.*js",
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 7939edd..46e51d2 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -4933,16 +4933,6 @@
           'scripts': 'chromium_linux_scripts',
         },
       },
-      'linux-experimental-next-rel': {
-        'mixins': [
-          'linux-bionic',
-        ],
-        'test_suites': {
-          'gtest_tests': 'chromium_linux_gtests',
-          'isolated_scripts': 'chromium_linux_rel_isolated_scripts',
-          'scripts': 'chromium_linux_scripts',
-        },
-      },
       'linux-extended-tracing-rel': {
         'additional_compile_targets': [
           'all',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 19e76d0..1dc5d26 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -6786,7 +6786,7 @@
             ]
         }
     ],
-    "SafeBrowsingVisualCsdModel": [
+    "SafeBrowsingVisualCsdModelVariation9": [
         {
             "platforms": [
                 "chromeos",
@@ -6797,9 +6797,9 @@
             ],
             "experiments": [
                 {
-                    "name": "Enabled_20210208",
+                    "name": "Enabled",
                     "params": {
-                        "ModelNum": "8"
+                        "ModelNum": "9"
                     },
                     "enable_features": [
                         "ClientSideDetectionModel"
diff --git a/third_party/.gitignore b/third_party/.gitignore
index ab96e1517..dfedc29 100644
--- a/third_party/.gitignore
+++ b/third_party/.gitignore
@@ -5,6 +5,7 @@
 /accessibility_test_framework/lib/
 /adobe/flash/binaries
 /adobe/flash/symbols
+/aemu-linux-arm64
 /aemu-linux-x64
 /amd/
 /android_build_tools/aapt2/aapt2
diff --git a/third_party/blink/common/custom_handlers/protocol_handler_utils.cc b/third_party/blink/common/custom_handlers/protocol_handler_utils.cc
index 84c3e27..bc23413 100644
--- a/third_party/blink/common/custom_handlers/protocol_handler_utils.cc
+++ b/third_party/blink/common/custom_handlers/protocol_handler_utils.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/public/common/custom_handlers/protocol_handler_utils.h"
 
+#include "base/containers/contains.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 4584f84e..9d91c69 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -37,7 +37,7 @@
 // TODO (crbug.com/1166910): Remove once the HandwritingRecognition API is more
 // widely available (likely M92).
 const base::Feature kHandwritingRecognitionWebPlatformApi{
-    "HandwritingRecognitionWebPlatformApi", base::FEATURE_DISABLED_BY_DEFAULT};
+    "HandwritingRecognitionWebPlatformApi", base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Whether the HandwritingRecognition API can be enabled. Disabling this feature
 // disables both the origin trial and the mojo interface. Defaults to enabled
@@ -447,6 +447,20 @@
 const base::FeatureParam<int> kForceDarkBackgroundLightnessThresholdParam{
     &kForceWebContentsDarkMode, "background_lightness_threshold", -1};
 
+const base::FeatureParam<ForceDarkIncreaseTextContrast>::Option
+    forcedark_increase_text_contrast_options[] = {
+        {ForceDarkIncreaseTextContrast::kUseBlinkSettings,
+         "use_blink_settings_for_method"},
+        {ForceDarkIncreaseTextContrast::kFalse, "false"},
+        {ForceDarkIncreaseTextContrast::kTrue, "true"}};
+
+// Should text contrast be increased.
+const base::FeatureParam<ForceDarkIncreaseTextContrast>
+    kForceDarkIncreaseTextContrastParam{
+        &kForceWebContentsDarkMode, "increase_text_contrast",
+        ForceDarkIncreaseTextContrast::kUseBlinkSettings,
+        &forcedark_increase_text_contrast_options};
+
 // Instructs WebRTC to honor the Min/Max Video Encode Accelerator dimensions.
 const base::Feature kWebRtcUseMinMaxVEADimensions {
   "WebRtcUseMinMaxVEADimensions",
@@ -811,6 +825,15 @@
 const base::Feature kWebAppEnableProtocolHandlers{
     "WebAppEnableProtocolHandlers", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Whether web apps are able to be treated as note-taking apps. Controls parsing
+// of "note_taking" dictionary field and "new_note_url" entry in web app
+// manifests. Also controls whether the parsed field is used in browser. See
+// incubation spec:
+// https://wicg.github.io/manifest-incubations/#note_taking-member
+// TODO(crbug.com/1185678): Enable by default after M92 branches.
+const base::Feature kWebAppNoteTaking{"WebAppNoteTaking",
+                                      base::FEATURE_DISABLED_BY_DEFAULT};
+
 // When enabled NV12 frames on a GPU will be forwarded to libvpx encoders
 // without conversion to I420.
 const base::Feature kWebRtcLibvpxEncodeNV12{"WebRtcLibvpxEncodeNV12",
diff --git a/third_party/blink/common/loader/throttling_url_loader.cc b/third_party/blink/common/loader/throttling_url_loader.cc
index ceeae87d..174fae0 100644
--- a/third_party/blink/common/loader/throttling_url_loader.cc
+++ b/third_party/blink/common/loader/throttling_url_loader.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/public/common/loader/throttling_url_loader.h"
 
 #include "base/bind.h"
+#include "base/containers/contains.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/strcat.h"
diff --git a/third_party/blink/common/manifest/manifest.cc b/third_party/blink/common/manifest/manifest.cc
index 7c5984a..9f56bfb 100644
--- a/third_party/blink/common/manifest/manifest.cc
+++ b/third_party/blink/common/manifest/manifest.cc
@@ -48,7 +48,7 @@
          related_applications.empty() && file_handlers.empty() &&
          !prefer_related_applications && !theme_color && !background_color &&
          !gcm_sender_id && scope.is_empty() && protocol_handlers.empty() &&
-         url_handlers.empty();
+         url_handlers.empty() && !note_taking.has_value();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/common/manifest/manifest_mojom_traits.cc b/third_party/blink/common/manifest/manifest_mojom_traits.cc
index ebcb3ca1b..7d4b0dd2 100644
--- a/third_party/blink/common/manifest/manifest_mojom_traits.cc
+++ b/third_party/blink/common/manifest/manifest_mojom_traits.cc
@@ -114,6 +114,9 @@
   if (!data.ReadUrlHandlers(&out->url_handlers))
     return false;
 
+  if (!data.ReadNoteTaking(&out->note_taking))
+    return false;
+
   if (!data.ReadRelatedApplications(&out->related_applications))
     return false;
 
@@ -317,4 +320,14 @@
   return true;
 }
 
+bool StructTraits<blink::mojom::ManifestNoteTakingDataView,
+                  ::blink::Manifest::NoteTaking>::
+    Read(blink::mojom::ManifestNoteTakingDataView data,
+         ::blink::Manifest::NoteTaking* out) {
+  if (!data.ReadNewNoteUrl(&out->new_note_url))
+    return false;
+
+  return true;
+}
+
 }  // namespace mojo
diff --git a/third_party/blink/common/page/content_to_visible_time_reporter_unittest.cc b/third_party/blink/common/page/content_to_visible_time_reporter_unittest.cc
index b10a7ee3..e25e4a89 100644
--- a/third_party/blink/common/page/content_to_visible_time_reporter_unittest.cc
+++ b/third_party/blink/common/page/content_to_visible_time_reporter_unittest.cc
@@ -5,6 +5,7 @@
 #include <strstream>
 #include <utility>
 
+#include "base/containers/contains.h"
 #include "base/rand_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/metrics/histogram_tester.h"
diff --git a/third_party/blink/common/use_counter/use_counter_feature.cc b/third_party/blink/common/use_counter/use_counter_feature.cc
index 185775d..45f9f37 100644
--- a/third_party/blink/common/use_counter/use_counter_feature.cc
+++ b/third_party/blink/common/use_counter/use_counter_feature.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/public/common/use_counter/use_counter_feature.h"
 
+#include "third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom-shared.h"
 #include "third_party/blink/public/mojom/use_counter/css_property_id.mojom-shared.h"
 #include "third_party/blink/public/mojom/web_feature/web_feature.mojom-shared.h"
 
@@ -32,6 +33,10 @@
       return value_ < static_cast<UseCounterFeature::EnumValue>(
                           mojom::CSSSampleId::kMaxValue) +
                           1;
+    case mojom::UseCounterFeatureType::kPermissionsPolicyViolationEnforce:
+      return value_ < static_cast<UseCounterFeature::EnumValue>(
+                          mojom::PermissionsPolicyFeature::kMaxValue) +
+                          1;
   }
 }
 
diff --git a/third_party/blink/common/use_counter/use_counter_feature_mojom_traits.cc b/third_party/blink/common/use_counter/use_counter_feature_mojom_traits.cc
index 7c352353..755ee3a 100644
--- a/third_party/blink/common/use_counter/use_counter_feature_mojom_traits.cc
+++ b/third_party/blink/common/use_counter/use_counter_feature_mojom_traits.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/common/use_counter/use_counter_feature_mojom_traits.h"
 
+#include "third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom-shared.h"
 #include "third_party/blink/public/mojom/use_counter/css_property_id.mojom-shared.h"
 #include "third_party/blink/public/mojom/web_feature/web_feature.mojom-shared.h"
 
@@ -22,6 +23,11 @@
       return feature.value() ==
              static_cast<blink::UseCounterFeature::EnumValue>(
                  blink::mojom::CSSSampleId::kTotalPagesMeasured);
+    case blink::mojom::UseCounterFeatureType::
+        kPermissionsPolicyViolationEnforce:
+      return feature.value() ==
+             static_cast<blink::UseCounterFeature::EnumValue>(
+                 blink::mojom::PermissionsPolicyFeature::kNotFound);
   }
 }
 }  // namespace
diff --git a/third_party/blink/common/use_counter/use_counter_feature_tracker.cc b/third_party/blink/common/use_counter/use_counter_feature_tracker.cc
index 1fa88db..e6ce5c7 100644
--- a/third_party/blink/common/use_counter/use_counter_feature_tracker.cc
+++ b/third_party/blink/common/use_counter/use_counter_feature_tracker.cc
@@ -16,6 +16,8 @@
       return css_properties_.test(feature.value());
     case FeatureType::kAnimatedCssProperty:
       return animated_css_properties_.test(feature.value());
+    case FeatureType::kPermissionsPolicyViolationEnforce:
+      return violated_permissions_policy_features_.test(feature.value());
   }
 }
 
@@ -63,6 +65,9 @@
     case FeatureType::kAnimatedCssProperty:
       animated_css_properties_[feature.value()] = value;
       break;
+    case FeatureType::kPermissionsPolicyViolationEnforce:
+      violated_permissions_policy_features_[feature.value()] = value;
+      break;
   }
 }
 
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index e0c853b..e9fa9d8 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -126,6 +126,9 @@
     kForceDarkTextLightnessThresholdParam;
 BLINK_COMMON_EXPORT extern const base::FeatureParam<int>
     kForceDarkBackgroundLightnessThresholdParam;
+BLINK_COMMON_EXPORT extern const base::FeatureParam<
+    ForceDarkIncreaseTextContrast>
+    kForceDarkIncreaseTextContrastParam;
 
 // Returns true when PlzDedicatedWorker is enabled.
 BLINK_COMMON_EXPORT bool IsPlzDedicatedWorkerEnabled();
@@ -325,6 +328,8 @@
 
 BLINK_COMMON_EXPORT extern const base::Feature kWebAppEnableProtocolHandlers;
 
+BLINK_COMMON_EXPORT extern const base::Feature kWebAppNoteTaking;
+
 BLINK_COMMON_EXPORT extern const base::Feature kWebRtcLibvpxEncodeNV12;
 
 BLINK_COMMON_EXPORT extern const base::Feature kLoadingTasksUnfreezable;
diff --git a/third_party/blink/public/common/forcedark/forcedark_switches.h b/third_party/blink/public/common/forcedark/forcedark_switches.h
index f2fda3a..6fe9768 100644
--- a/third_party/blink/public/common/forcedark/forcedark_switches.h
+++ b/third_party/blink/public/common/forcedark/forcedark_switches.h
@@ -39,6 +39,14 @@
   kInvertSelectively
 };
 
+// Specifies algorithm for increasing text contrast.
+enum class ForceDarkIncreaseTextContrast {
+  // Same as ForceDarkInversionMethod::kUseBlinkSettings above.
+  kUseBlinkSettings,
+  kFalse,
+  kTrue
+};
+
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_FORCEDARK_FORCEDARK_SWITCHES_H_
diff --git a/third_party/blink/public/common/manifest/manifest.h b/third_party/blink/public/common/manifest/manifest.h
index b8b4d6e..9555cd6 100644
--- a/third_party/blink/public/common/manifest/manifest.h
+++ b/third_party/blink/public/common/manifest/manifest.h
@@ -121,6 +121,12 @@
     bool has_origin_wildcard;
   };
 
+  struct BLINK_COMMON_EXPORT NoteTaking {
+    // A URL for taking a new note in the web application. If valid, this web
+    // application is a note-taking application.
+    GURL new_note_url;
+  };
+
   // Structure representing a related application.
   struct BLINK_COMMON_EXPORT RelatedApplication {
     RelatedApplication();
@@ -209,6 +215,12 @@
   // entries inside the array were invalid.
   std::vector<UrlHandler> url_handlers;
 
+  // TODO(crbug.com/1185678): This field is non-standard and part of a manifest
+  // incubation. See:
+  // https://wicg.github.io/manifest-incubations/index.html#dfn-note_taking
+  // Null if parsing failed or the field was not present.
+  base::Optional<NoteTaking> note_taking;
+
   // Empty if the parsing failed, the field was not present, empty or all the
   // applications inside the array were invalid. The order of the array
   // indicates the priority of the application to use.
diff --git a/third_party/blink/public/common/manifest/manifest_mojom_traits.h b/third_party/blink/public/common/manifest/manifest_mojom_traits.h
index 15301e1..afd6be1 100644
--- a/third_party/blink/public/common/manifest/manifest_mojom_traits.h
+++ b/third_party/blink/public/common/manifest/manifest_mojom_traits.h
@@ -138,6 +138,11 @@
     return manifest.url_handlers;
   }
 
+  static const base::Optional<::blink::Manifest::NoteTaking>& note_taking(
+      const ::blink::Manifest& manifest) {
+    return manifest.note_taking;
+  }
+
   static const std::vector<::blink::Manifest::RelatedApplication>&
   related_applications(const ::blink::Manifest& manifest) {
     return manifest.related_applications;
@@ -363,6 +368,19 @@
                    ::blink::Manifest::ProtocolHandler* out);
 };
 
+template <>
+struct BLINK_COMMON_EXPORT
+    StructTraits<blink::mojom::ManifestNoteTakingDataView,
+                 ::blink::Manifest::NoteTaking> {
+  static const GURL new_note_url(
+      const ::blink::Manifest::NoteTaking& note_taking) {
+    return note_taking.new_note_url;
+  }
+
+  static bool Read(blink::mojom::ManifestNoteTakingDataView data,
+                   ::blink::Manifest::NoteTaking* out);
+};
+
 }  // namespace mojo
 
 #endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_MANIFEST_MANIFEST_MOJOM_TRAITS_H_
diff --git a/third_party/blink/public/common/use_counter/use_counter_feature_tracker.h b/third_party/blink/public/common/use_counter/use_counter_feature_tracker.h
index 4860ed2..6b14221 100644
--- a/third_party/blink/public/common/use_counter/use_counter_feature_tracker.h
+++ b/third_party/blink/public/common/use_counter/use_counter_feature_tracker.h
@@ -10,6 +10,7 @@
 #include <vector>
 #include "third_party/blink/public/common/common_export.h"
 #include "third_party/blink/public/common/use_counter/use_counter_feature.h"
+#include "third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom-shared.h"
 #include "third_party/blink/public/mojom/use_counter/css_property_id.mojom-shared.h"
 #include "third_party/blink/public/mojom/web_feature/web_feature.mojom-shared.h"
 
@@ -33,6 +34,9 @@
       css_properties_;
   std::bitset<static_cast<size_t>(mojom::CSSSampleId::kMaxValue) + 1>
       animated_css_properties_;
+  std::bitset<static_cast<size_t>(mojom::PermissionsPolicyFeature::kMaxValue) +
+              1>
+      violated_permissions_policy_features_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/public/mojom/manifest/manifest.mojom b/third_party/blink/public/mojom/manifest/manifest.mojom
index 6c9257c1..a7b00cd2 100644
--- a/third_party/blink/public/mojom/manifest/manifest.mojom
+++ b/third_party/blink/public/mojom/manifest/manifest.mojom
@@ -54,6 +54,11 @@
 
   array<ManifestUrlHandler> url_handlers;
 
+  // TODO(crbug.com/1185678): This field is non-standard and part of a manifest
+  // incubation. See:
+  // https://wicg.github.io/manifest-incubations/index.html#dfn-note_taking
+  ManifestNoteTaking? note_taking;
+
   array<ManifestRelatedApplication> related_applications;
 
   // A boolean that is used as a hint for the user agent to say that related
@@ -146,6 +151,13 @@
   bool has_origin_wildcard;
 };
 
+// Structure representing note-taking application capabilities.
+struct ManifestNoteTaking {
+  // A URL for taking a new note in the web application. If valid, this web
+  // application is a note-taking application.
+  url.mojom.Url new_note_url;
+};
+
 // Structure representing a related application.
 struct ManifestRelatedApplication {
   // The platform on which the application can be found. This can be any
diff --git a/third_party/blink/public/mojom/use_counter/use_counter_feature.mojom b/third_party/blink/public/mojom/use_counter/use_counter_feature.mojom
index 944dfd4a..2f54503 100644
--- a/third_party/blink/public/mojom/use_counter/use_counter_feature.mojom
+++ b/third_party/blink/public/mojom/use_counter/use_counter_feature.mojom
@@ -7,9 +7,14 @@
 // This enum defines feature types that can be counted by UseCounter
 // infrastructure.
 enum UseCounterFeatureType {
+  // Blink.UseCounter.Features
   kWebFeature,
+  // Blink.UseCounter.CSSProperties
   kCssProperty,
+  // Blink.UseCounter.AnimatedCSSProperties
   kAnimatedCssProperty,
+  // Blink.UseCounter.PermissionsPolicy.Violation.Enforce
+  kPermissionsPolicyViolationEnforce,
 };
 
 // This struct corresponds to `blink::UseCounterFeature`.
diff --git a/third_party/blink/public/platform/DEPS b/third_party/blink/public/platform/DEPS
index 24e4479..4302493 100644
--- a/third_party/blink/public/platform/DEPS
+++ b/third_party/blink/public/platform/DEPS
@@ -28,6 +28,7 @@
     "+cc",
     "+components/viz/common",
     "+media/base/audio_capturer_source.h",
+    "+media/base/audio_latency.h",
     "+media/base/audio_renderer_sink.h",
     "+media/base/eme_constants.h",
     "+media/base/media_content_type.h",
diff --git a/third_party/blink/public/platform/platform.h b/third_party/blink/public/platform/platform.h
index 00a41fe3..e5b61777 100644
--- a/third_party/blink/public/platform/platform.h
+++ b/third_party/blink/public/platform/platform.h
@@ -36,35 +36,26 @@
 
 #include "base/callback.h"
 #include "base/memory/scoped_refptr.h"
-#include "base/metrics/user_metrics_action.h"
-#include "base/strings/string_piece.h"
-#include "base/threading/thread.h"
+#include "base/optional.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "components/viz/common/surfaces/frame_sink_id.h"
 #include "media/base/audio_capturer_source.h"
+#include "media/base/audio_latency.h"
 #include "media/base/audio_renderer_sink.h"
 #include "media/base/media_log.h"
-#include "mojo/public/cpp/base/big_buffer.h"
-#include "mojo/public/cpp/bindings/generic_pending_receiver.h"
-#include "mojo/public/cpp/system/message_pipe.h"
-#include "services/network/public/mojom/url_loader_factory.mojom-shared.h"
-#include "third_party/blink/public/common/permissions_policy/permissions_policy.h"
 #include "third_party/blink/public/common/security/protocol_handler_security_level.h"
 #include "third_party/blink/public/common/user_agent/user_agent_metadata.h"
 #include "third_party/blink/public/mojom/loader/code_cache.mojom-forward.h"
 #include "third_party/blink/public/platform/audio/web_audio_device_source_type.h"
 #include "third_party/blink/public/platform/blame_context.h"
 #include "third_party/blink/public/platform/cross_variant_mojo_util.h"
-#include "third_party/blink/public/platform/user_metrics_action.h"
 #include "third_party/blink/public/platform/web_audio_device.h"
 #include "third_party/blink/public/platform/web_code_cache_loader.h"
 #include "third_party/blink/public/platform/web_common.h"
 #include "third_party/blink/public/platform/web_data.h"
 #include "third_party/blink/public/platform/web_dedicated_worker_host_factory_client.h"
 #include "third_party/blink/public/platform/web_string.h"
-#include "third_party/blink/public/platform/web_url_error.h"
-#include "third_party/blink/public/platform/web_url_loader.h"
 #include "third_party/blink/public/platform/web_url_loader_factory.h"
 #include "third_party/blink/public/platform/web_v8_value_converter.h"
 #include "third_party/webrtc/api/video/video_codec_type.h"
@@ -99,10 +90,21 @@
 class GpuVideoAcceleratorFactories;
 }  // namespace media
 
+namespace mojo_base {
+class BigBuffer;
+}
+
 namespace network {
+namespace mojom {
+class URLLoaderFactoryInterfaceBase;
+}
 class SharedURLLoaderFactory;
 }
 
+namespace url {
+class Origin;
+}
+
 namespace v8 {
 class Context;
 template <class T>
@@ -121,6 +123,7 @@
 class Thread;
 struct ThreadCreationParams;
 class URLLoaderThrottle;
+class UserMetricsAction;
 class WebAudioBus;
 class WebAudioLatencyHint;
 class WebCrypto;
@@ -777,7 +780,7 @@
 
   virtual void SetRenderingColorSpace(const gfx::ColorSpace& color_space) {}
 
-  virtual gfx::ColorSpace GetRenderingColorSpace() const { return {}; }
+  virtual gfx::ColorSpace GetRenderingColorSpace() const;
 
   // Renderer Memory Metrics ----------------------------------------------
 
diff --git a/third_party/blink/renderer/bindings/core/v8/serialization/serialization_tag.h b/third_party/blink/renderer/bindings/core/v8/serialization/serialization_tag.h
index 02004666..7285fc00 100644
--- a/third_party/blink/renderer/bindings/core/v8/serialization/serialization_tag.h
+++ b/third_party/blink/renderer/bindings/core/v8/serialization/serialization_tag.h
@@ -104,7 +104,7 @@
   kRTCEncodedAudioFrameTag = 'A',  // uint32_t -> transferred audio frame ID
   kRTCEncodedVideoFrameTag = 'V',  // uint32_t -> transferred video frame ID
 
-  kAudioFrameTag = 'a',  // uint32_t -> transferred audio frame data
+  kAudioDataTag = 'a',   // uint32_t -> transferred audio data
   kVideoFrameTag = 'v',  // uint32_t -> transferred video frame ID
 
   // The following tags were used by the Shape Detection API implementation
diff --git a/third_party/blink/renderer/bindings/generated_in_modules.gni b/third_party/blink/renderer/bindings/generated_in_modules.gni
index 5626a82..6aca374 100644
--- a/third_party/blink/renderer/bindings/generated_in_modules.gni
+++ b/third_party/blink/renderer/bindings/generated_in_modules.gni
@@ -11,8 +11,8 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_animate_callback.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_animator_constructor.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_animator_constructor.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_frame_output_callback.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_frame_output_callback.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_data_output_callback.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_data_output_callback.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_blink_audio_worklet_process_callback.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_blink_audio_worklet_process_callback.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_blink_audio_worklet_processor_constructor.cc",
@@ -119,6 +119,8 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_configuration.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_context_options.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_context_options.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_data_init.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_data_init.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_config.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_config.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_init.cc",
@@ -129,8 +131,6 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_encoder_config.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_encoder_init.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_encoder_init.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_frame_init.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_frame_init.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_node_options.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_node_options.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_param_descriptor.cc",
@@ -1325,14 +1325,14 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_buffer_source_node.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_context.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_context.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_data.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_data.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_destination_node.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_destination_node.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_encoder.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_encoder.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_frame.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_frame.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_listener.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_listener.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_audio_node.cc",
diff --git a/third_party/blink/renderer/bindings/idl_in_modules.gni b/third_party/blink/renderer/bindings/idl_in_modules.gni
index 3be138f..ecae35dd 100644
--- a/third_party/blink/renderer/bindings/idl_in_modules.gni
+++ b/third_party/blink/renderer/bindings/idl_in_modules.gni
@@ -782,6 +782,9 @@
           "//third_party/blink/renderer/modules/webaudio/stereo_panner_options.idl",
           "//third_party/blink/renderer/modules/webaudio/wave_shaper_node.idl",
           "//third_party/blink/renderer/modules/webaudio/wave_shaper_options.idl",
+          "//third_party/blink/renderer/modules/webcodecs/audio_data.idl",
+          "//third_party/blink/renderer/modules/webcodecs/audio_data_init.idl",
+          "//third_party/blink/renderer/modules/webcodecs/audio_data_output_callback.idl",
           "//third_party/blink/renderer/modules/webcodecs/audio_decoder.idl",
           "//third_party/blink/renderer/modules/webcodecs/audio_decoder_config.idl",
           "//third_party/blink/renderer/modules/webcodecs/audio_decoder_init.idl",
@@ -790,9 +793,6 @@
           "//third_party/blink/renderer/modules/webcodecs/audio_encoder_config.idl",
           "//third_party/blink/renderer/modules/webcodecs/audio_encoder_init.idl",
           "//third_party/blink/renderer/modules/webcodecs/audio_encoder_support.idl",
-          "//third_party/blink/renderer/modules/webcodecs/audio_frame.idl",
-          "//third_party/blink/renderer/modules/webcodecs/audio_frame_init.idl",
-          "//third_party/blink/renderer/modules/webcodecs/audio_frame_output_callback.idl",
           "//third_party/blink/renderer/modules/webcodecs/avc_encoder_config.idl",
           "//third_party/blink/renderer/modules/webcodecs/codec_state.idl",
           "//third_party/blink/renderer/modules/webcodecs/color_space_matrix_id.idl",
diff --git a/third_party/blink/renderer/bindings/modules/v8/generated.gni b/third_party/blink/renderer/bindings/modules/v8/generated.gni
index ca02c0c..baf661b 100644
--- a/third_party/blink/renderer/bindings/modules/v8/generated.gni
+++ b/third_party/blink/renderer/bindings/modules/v8/generated.gni
@@ -142,8 +142,8 @@
   "$bindings_modules_v8_output_dir/v8_animate_callback.h",
   "$bindings_modules_v8_output_dir/v8_animator_constructor.cc",
   "$bindings_modules_v8_output_dir/v8_animator_constructor.h",
-  "$bindings_modules_v8_output_dir/v8_audio_frame_output_callback.cc",
-  "$bindings_modules_v8_output_dir/v8_audio_frame_output_callback.h",
+  "$bindings_modules_v8_output_dir/v8_audio_data_output_callback.cc",
+  "$bindings_modules_v8_output_dir/v8_audio_data_output_callback.h",
   "$bindings_modules_v8_output_dir/v8_blink_audio_worklet_process_callback.cc",
   "$bindings_modules_v8_output_dir/v8_blink_audio_worklet_process_callback.h",
   "$bindings_modules_v8_output_dir/v8_blink_audio_worklet_processor_constructor.cc",
diff --git a/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_deserializer_for_modules.cc b/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_deserializer_for_modules.cc
index cb4bc77..4f60151 100644
--- a/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_deserializer_for_modules.cc
+++ b/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_deserializer_for_modules.cc
@@ -22,8 +22,8 @@
 #include "third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_frame_delegate.h"
 #include "third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_frame.h"
 #include "third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_frame_delegate.h"
-#include "third_party/blink/renderer/modules/webcodecs/audio_frame.h"
-#include "third_party/blink/renderer/modules/webcodecs/audio_frame_attachment.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_data.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_data_attachment.h"
 #include "third_party/blink/renderer/modules/webcodecs/video_frame.h"
 #include "third_party/blink/renderer/modules/webcodecs/video_frame_attachment.h"
 
@@ -77,8 +77,8 @@
       return ReadRTCEncodedAudioFrame();
     case kRTCEncodedVideoFrameTag:
       return ReadRTCEncodedVideoFrame();
-    case kAudioFrameTag:
-      return ReadAudioFrame();
+    case kAudioDataTag:
+      return ReadAudioData();
     case kVideoFrameTag:
       return ReadVideoFrame();
     default:
@@ -422,7 +422,7 @@
   return MakeGarbageCollected<RTCEncodedVideoFrame>(frames[index]);
 }
 
-AudioFrame* V8ScriptValueDeserializerForModules::ReadAudioFrame() {
+AudioData* V8ScriptValueDeserializerForModules::ReadAudioData() {
   if (!RuntimeEnabledFeatures::WebCodecsEnabled(
           ExecutionContext::From(GetScriptState()))) {
     return nullptr;
@@ -433,7 +433,7 @@
     return nullptr;
 
   const auto* attachment =
-      GetSerializedScriptValue()->GetAttachmentIfExists<AudioFrameAttachment>();
+      GetSerializedScriptValue()->GetAttachmentIfExists<AudioDataAttachment>();
   if (!attachment)
     return nullptr;
 
@@ -441,7 +441,7 @@
   if (index >= attachment->size())
     return nullptr;
 
-  return MakeGarbageCollected<AudioFrame>(audio_buffers[index]);
+  return MakeGarbageCollected<AudioData>(audio_buffers[index]);
 }
 
 VideoFrame* V8ScriptValueDeserializerForModules::ReadVideoFrame() {
diff --git a/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_deserializer_for_modules.h b/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_deserializer_for_modules.h
index 9a01275..bcab8457 100644
--- a/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_deserializer_for_modules.h
+++ b/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_deserializer_for_modules.h
@@ -10,7 +10,7 @@
 
 namespace blink {
 
-class AudioFrame;
+class AudioData;
 class CryptoKey;
 class FileSystemHandle;
 class RTCEncodedAudioFrame;
@@ -50,7 +50,7 @@
   FileSystemHandle* ReadFileSystemHandle(SerializationTag tag);
   RTCEncodedAudioFrame* ReadRTCEncodedAudioFrame();
   RTCEncodedVideoFrame* ReadRTCEncodedVideoFrame();
-  AudioFrame* ReadAudioFrame();
+  AudioData* ReadAudioData();
   VideoFrame* ReadVideoFrame();
 };
 
diff --git a/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules.cc b/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules.cc
index f51c839..5eb90a3f 100644
--- a/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules.cc
+++ b/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules.cc
@@ -11,7 +11,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_dom_rect_read_only.h"
 #include "third_party/blink/renderer/bindings/modules/v8/serialization/web_crypto_sub_tags.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_frame.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_data.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_crypto_key.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_dom_file_system.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_file_system_directory_handle.h"
@@ -26,8 +26,8 @@
 #include "third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_frame_delegate.h"
 #include "third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_frame.h"
 #include "third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_frame_delegate.h"
-#include "third_party/blink/renderer/modules/webcodecs/audio_frame.h"
-#include "third_party/blink/renderer/modules/webcodecs/audio_frame_attachment.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_data.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_data_attachment.h"
 #include "third_party/blink/renderer/modules/webcodecs/video_frame.h"
 #include "third_party/blink/renderer/modules/webcodecs/video_frame_attachment.h"
 #include "third_party/blink/renderer/modules/webcodecs/video_frame_transfer_list.h"
@@ -156,21 +156,20 @@
     }
     return WriteVideoFrameHandle(std::move(handle));
   }
-  if (wrapper_type_info == V8AudioFrame::GetWrapperTypeInfo() &&
+  if (wrapper_type_info == V8AudioData::GetWrapperTypeInfo() &&
       RuntimeEnabledFeatures::WebCodecsEnabled(
           ExecutionContext::From(GetScriptState()))) {
     if (IsForStorage()) {
-      exception_state.ThrowDOMException(
-          DOMExceptionCode::kDataCloneError,
-          "An AudioFrame cannot be serialized for "
-          "storage.");
+      exception_state.ThrowDOMException(DOMExceptionCode::kDataCloneError,
+                                        "AudioData cannot be serialized for "
+                                        "storage.");
       return false;
     }
     scoped_refptr<media::AudioBuffer> data =
-        wrappable->ToImpl<AudioFrame>()->data();
+        wrappable->ToImpl<AudioData>()->data();
     if (!data) {
       exception_state.ThrowDOMException(DOMExceptionCode::kDataCloneError,
-                                        "An AudioFrame could not be cloned "
+                                        "AudioData could not be cloned "
                                         "because it was closed.");
       return false;
     }
@@ -419,12 +418,12 @@
 bool V8ScriptValueSerializerForModules::WriteMediaAudioBuffer(
     scoped_refptr<media::AudioBuffer> audio_data) {
   auto* attachment =
-      GetSerializedScriptValue()->GetOrCreateAttachment<AudioFrameAttachment>();
+      GetSerializedScriptValue()->GetOrCreateAttachment<AudioDataAttachment>();
   auto& audio_buffers = attachment->AudioBuffers();
   audio_buffers.push_back(std::move(audio_data));
   const uint32_t index = static_cast<uint32_t>(audio_buffers.size() - 1);
 
-  WriteTag(kAudioFrameTag);
+  WriteTag(kAudioDataTag);
   WriteUint32(index);
 
   return true;
diff --git a/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc b/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc
index 931558ab..d0692e1 100644
--- a/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc
+++ b/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc
@@ -19,7 +19,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/v8_dom_exception.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_dom_rect_read_only.h"
 #include "third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_deserializer_for_modules.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_frame.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_data.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_crypto_key.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_dom_file_system.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_certificate.h"
@@ -29,7 +29,7 @@
 #include "third_party/blink/renderer/modules/filesystem/dom_file_system.h"
 #include "third_party/blink/renderer/modules/peerconnection/rtc_certificate.h"
 #include "third_party/blink/renderer/modules/peerconnection/rtc_certificate_generator.h"
-#include "third_party/blink/renderer/modules/webcodecs/audio_frame.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_data.h"
 #include "third_party/blink/renderer/modules/webcodecs/video_frame.h"
 #include "third_party/blink/renderer/modules/webcodecs/video_frame_transfer_list.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -1076,7 +1076,7 @@
       "DataCloneError", scope.GetScriptState(), exception_state));
 }
 
-TEST(V8ScriptValueSerializerForModulesTest, RoundTripAudioFrame) {
+TEST(V8ScriptValueSerializerForModulesTest, RoundTripAudioData) {
   V8TestingScope scope;
 
   const unsigned kChannels = 2;
@@ -1101,39 +1101,39 @@
   auto audio_buffer =
       media::AudioBuffer::CopyFrom(kSampleRate, kTimestamp, audio_bus.get());
 
-  auto* audio_frame = MakeGarbageCollected<AudioFrame>(std::move(audio_buffer));
+  auto* audio_data = MakeGarbageCollected<AudioData>(std::move(audio_buffer));
 
   // Round trip the frame and make sure the size is the same.
-  v8::Local<v8::Value> wrapper = ToV8(audio_frame, scope.GetScriptState());
+  v8::Local<v8::Value> wrapper = ToV8(audio_data, scope.GetScriptState());
   v8::Local<v8::Value> result = RoundTripForModules(wrapper, scope);
 
   // The data should have been copied, not transferred.
-  EXPECT_TRUE(audio_frame->buffer());
+  EXPECT_TRUE(audio_data->buffer());
 
-  ASSERT_TRUE(V8AudioFrame::HasInstance(result, scope.GetIsolate()));
+  ASSERT_TRUE(V8AudioData::HasInstance(result, scope.GetIsolate()));
 
-  AudioFrame* new_frame = V8AudioFrame::ToImpl(result.As<v8::Object>());
-  EXPECT_EQ(base::TimeDelta::FromMicroseconds(new_frame->timestamp()),
+  AudioData* new_data = V8AudioData::ToImpl(result.As<v8::Object>());
+  EXPECT_EQ(base::TimeDelta::FromMicroseconds(new_data->timestamp()),
             kTimestamp);
-  EXPECT_EQ(new_frame->buffer()->numberOfChannels(), kChannels);
-  EXPECT_EQ(new_frame->buffer()->sampleRate(), kSampleRate);
-  EXPECT_EQ(new_frame->buffer()->length(), kFrames);
+  EXPECT_EQ(new_data->buffer()->numberOfChannels(), kChannels);
+  EXPECT_EQ(new_data->buffer()->sampleRate(), kSampleRate);
+  EXPECT_EQ(new_data->buffer()->length(), kFrames);
 
   // Make sure the data wasn't changed during the transfer.
   for (unsigned ch = 0; ch < kChannels; ++ch) {
-    float* src_data = audio_frame->buffer()->getChannelData(ch)->Data();
-    float* dst_data = new_frame->buffer()->getChannelData(ch)->Data();
+    float* src_data = audio_data->buffer()->getChannelData(ch)->Data();
+    float* dst_data = new_data->buffer()->getChannelData(ch)->Data();
     for (unsigned i = 0; i < kFrames; ++i) {
       EXPECT_EQ(src_data[i], dst_data[i]);
     }
   }
 
-  // Closing the original |audio_frame| should not affect |new_frame|.
-  audio_frame->close();
-  EXPECT_TRUE(new_frame->buffer());
+  // Closing the original |audio_data| should not affect |new_data|.
+  audio_data->close();
+  EXPECT_TRUE(new_data->buffer());
 }
 
-TEST(V8ScriptValueSerializerForModulesTest, ClosedAudioFrameThrows) {
+TEST(V8ScriptValueSerializerForModulesTest, ClosedAudioDataThrows) {
   V8TestingScope scope;
   ExceptionState exception_state(scope.GetIsolate(),
                                  ExceptionState::kExecutionContext, "Window",
@@ -1146,11 +1146,11 @@
       /*frame_count=*/500, base::TimeDelta::FromMilliseconds(314));
 
   // Create and close the frame.
-  auto* audio_frame = MakeGarbageCollected<AudioFrame>(std::move(audio_buffer));
-  audio_frame->close();
+  auto* audio_data = MakeGarbageCollected<AudioData>(std::move(audio_buffer));
+  audio_data->close();
 
   // Serializing the closed frame should throw an error.
-  v8::Local<v8::Value> wrapper = ToV8(audio_frame, scope.GetScriptState());
+  v8::Local<v8::Value> wrapper = ToV8(audio_data, scope.GetScriptState());
   EXPECT_FALSE(V8ScriptValueSerializer(scope.GetScriptState())
                    .Serialize(wrapper, exception_state));
   EXPECT_TRUE(HadDOMExceptionInModulesTest(
diff --git a/third_party/blink/renderer/core/animation/property_handle.h b/third_party/blink/renderer/core/animation/property_handle.h
index 2bace91..d540ad6 100644
--- a/third_party/blink/renderer/core/animation/property_handle.h
+++ b/third_party/blink/renderer/core/animation/property_handle.h
@@ -140,7 +140,7 @@
     : SimpleClassHashTraits<blink::PropertyHandle> {
   static const bool kNeedsDestruction = true;
   static void ConstructDeletedValue(blink::PropertyHandle& slot, bool) {
-    new (NotNull, &slot) blink::PropertyHandle(
+    new (NotNullTag::kNotNull, &slot) blink::PropertyHandle(
         blink::PropertyHandle::DeletedValueForHashTraits());
   }
   static bool IsDeletedValue(const blink::PropertyHandle& value) {
diff --git a/third_party/blink/renderer/core/app_history/app_history.cc b/third_party/blink/renderer/core/app_history/app_history.cc
index 9abf2ac0..7d81b1a 100644
--- a/third_party/blink/renderer/core/app_history/app_history.cc
+++ b/third_party/blink/renderer/core/app_history/app_history.cc
@@ -364,6 +364,13 @@
   ongoing_navigate_event_ = nullptr;
 }
 
+int AppHistory::GetIndexFor(AppHistoryEntry* entry) {
+  const auto& it = keys_to_indices_.find(entry->key());
+  if (it == keys_to_indices_.end() || entry != entries_[it->value])
+    return -1;
+  return it->value;
+}
+
 const AtomicString& AppHistory::InterfaceName() const {
   return event_target_names::kAppHistory;
 }
diff --git a/third_party/blink/renderer/core/app_history/app_history.h b/third_party/blink/renderer/core/app_history/app_history.h
index c13683c..0114a43 100644
--- a/third_party/blink/renderer/core/app_history/app_history.h
+++ b/third_party/blink/renderer/core/app_history/app_history.h
@@ -73,6 +73,8 @@
                              SerializedScriptValue* = nullptr);
   void CancelOngoingNavigateEvent();
 
+  int GetIndexFor(AppHistoryEntry*);
+
   // EventTargetWithInlineData overrides:
   const AtomicString& InterfaceName() const final;
   ExecutionContext* GetExecutionContext() const final {
diff --git a/third_party/blink/renderer/core/app_history/app_history_entry.cc b/third_party/blink/renderer/core/app_history/app_history_entry.cc
index 24867d57..b9125ef 100644
--- a/third_party/blink/renderer/core/app_history/app_history_entry.cc
+++ b/third_party/blink/renderer/core/app_history/app_history_entry.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/app_history/app_history_entry.h"
 
+#include "third_party/blink/renderer/core/app_history/app_history.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/loader/document_loader.h"
 
@@ -20,6 +21,11 @@
   return DomWindow() ? item_->GetAppHistoryId() : String();
 }
 
+int64_t AppHistoryEntry::index() {
+  return DomWindow() ? AppHistory::appHistory(*DomWindow())->GetIndexFor(this)
+                     : -1;
+}
+
 KURL AppHistoryEntry::url() {
   return DomWindow() ? item_->Url() : NullURL();
 }
diff --git a/third_party/blink/renderer/core/app_history/app_history_entry.h b/third_party/blink/renderer/core/app_history/app_history_entry.h
index 038db80..b544c63 100644
--- a/third_party/blink/renderer/core/app_history/app_history_entry.h
+++ b/third_party/blink/renderer/core/app_history/app_history_entry.h
@@ -28,6 +28,7 @@
   String key() const;
   String id() const;
   KURL url();
+  int64_t index();
   bool sameDocument() const;
 
   ScriptValue getState() const;
diff --git a/third_party/blink/renderer/core/app_history/app_history_entry.idl b/third_party/blink/renderer/core/app_history/app_history_entry.idl
index 2f57a339..c63ef912 100644
--- a/third_party/blink/renderer/core/app_history/app_history_entry.idl
+++ b/third_party/blink/renderer/core/app_history/app_history_entry.idl
@@ -10,8 +10,7 @@
   readonly attribute DOMString key;
   readonly attribute DOMString id;
   readonly attribute USVString url;
-  // readonly attribute long long index;
-  // readonly attribute boolean finished;
+  readonly attribute long long index;
   readonly attribute boolean sameDocument;
 
   any getState();
diff --git a/third_party/blink/renderer/core/css/css_property_name.h b/third_party/blink/renderer/core/css/css_property_name.h
index d902dc6..2e0153b4 100644
--- a/third_party/blink/renderer/core/css/css_property_name.h
+++ b/third_party/blink/renderer/core/css/css_property_name.h
@@ -108,7 +108,8 @@
   static const bool kEmptyValueIsZero = false;
   static const bool kNeedsDestruction = true;
   static void ConstructDeletedValue(CSSPropertyName& slot, bool) {
-    new (NotNull, &slot) CSSPropertyName(CSSPropertyName::kDeletedValue);
+    new (NotNullTag::kNotNull, &slot)
+        CSSPropertyName(CSSPropertyName::kDeletedValue);
   }
   static bool IsDeletedValue(CSSPropertyName value) {
     return value.IsDeletedValue();
diff --git a/third_party/blink/renderer/core/css/style_change_reason.cc b/third_party/blink/renderer/core/css/style_change_reason.cc
index ca40b551..b178df1 100644
--- a/third_party/blink/renderer/core/css/style_change_reason.cc
+++ b/third_party/blink/renderer/core/css/style_change_reason.cc
@@ -63,15 +63,17 @@
 void Init() {
   DCHECK(IsMainThread());
 
-  new (NotNull, (void*)&g_active) AtomicString(":active");
-  new (NotNull, (void*)&g_disabled) AtomicString(":disabled");
-  new (NotNull, (void*)&g_drag) AtomicString(":-webkit-drag");
-  new (NotNull, (void*)&g_focus) AtomicString(":focus");
-  new (NotNull, (void*)&g_focus_visible) AtomicString(":focus-visible");
-  new (NotNull, (void*)&g_focus_within) AtomicString(":focus-within");
-  new (NotNull, (void*)&g_hover) AtomicString(":hover");
-  new (NotNull, (void*)&g_past) AtomicString(":past");
-  new (NotNull, (void*)&g_unresolved) AtomicString(":unresolved");
+  new (NotNullTag::kNotNull, (void*)&g_active) AtomicString(":active");
+  new (NotNullTag::kNotNull, (void*)&g_disabled) AtomicString(":disabled");
+  new (NotNullTag::kNotNull, (void*)&g_drag) AtomicString(":-webkit-drag");
+  new (NotNullTag::kNotNull, (void*)&g_focus) AtomicString(":focus");
+  new (NotNullTag::kNotNull, (void*)&g_focus_visible)
+      AtomicString(":focus-visible");
+  new (NotNullTag::kNotNull, (void*)&g_focus_within)
+      AtomicString(":focus-within");
+  new (NotNullTag::kNotNull, (void*)&g_hover) AtomicString(":hover");
+  new (NotNullTag::kNotNull, (void*)&g_past) AtomicString(":past");
+  new (NotNullTag::kNotNull, (void*)&g_unresolved) AtomicString(":unresolved");
 }
 
 }  // namespace style_change_extra_data
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc b/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc
index b34eaed..e23ce229 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc
@@ -313,6 +313,28 @@
   return nullptr;
 }
 
+Element* DisplayLockUtilities::NearestLockedInclusiveAncestorWithinTreeScope(
+    const Node& node) {
+  if (!node.isConnected() || node.GetDocument()
+                                     .GetDisplayLockDocumentState()
+                                     .LockedDisplayLockCount() == 0) {
+    return nullptr;
+  }
+
+  for (Node& ancestor : NodeTraversal::InclusiveAncestorsOf(node)) {
+    DCHECK(ancestor.GetTreeScope() == node.GetTreeScope());
+    Element* ancestor_element = DynamicTo<Element>(ancestor);
+    if (!ancestor_element)
+      continue;
+    if (DisplayLockContext* context =
+            ancestor_element->GetDisplayLockContext()) {
+      if (context->IsLocked())
+        return ancestor_element;
+    }
+  }
+  return nullptr;
+}
+
 Element* DisplayLockUtilities::HighestLockedInclusiveAncestor(
     const Node& node) {
   if (!RuntimeEnabledFeatures::CSSContentVisibilityEnabled() ||
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_utilities.h b/third_party/blink/renderer/core/display_lock/display_lock_utilities.h
index a2ceca8..45aeb57 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_utilities.h
+++ b/third_party/blink/renderer/core/display_lock/display_lock_utilities.h
@@ -128,6 +128,12 @@
   static Element* NearestLockedInclusiveAncestor(const LayoutObject& object);
   static Element* NearestLockedExclusiveAncestor(const LayoutObject& object);
 
+  // Returns the nearest inclusive ancestor of |node| that is display locked
+  // within the same TreeScope as |node|, meaning that no flat tree traversals
+  // are made.
+  static Element* NearestLockedInclusiveAncestorWithinTreeScope(
+      const Node& node);
+
   // Returns the nearest ancestor element which has a lock that prevents
   // prepaint. Note that this is different from a nearest locked ancestor since
   // the prepaint update can be forced.
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index ac55e4b8..cc6d433 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -39,6 +39,7 @@
 #include <utility>
 
 #include "base/auto_reset.h"
+#include "base/containers/contains.h"
 #include "base/debug/dump_without_crashing.h"
 #include "base/macros.h"
 #include "base/metrics/histogram_functions.h"
diff --git a/third_party/blink/renderer/core/dom/slot_assignment.cc b/third_party/blink/renderer/core/dom/slot_assignment.cc
index 5ac4a53d..e214bd5e 100644
--- a/third_party/blink/renderer/core/dom/slot_assignment.cc
+++ b/third_party/blink/renderer/core/dom/slot_assignment.cc
@@ -258,16 +258,6 @@
     SlotAssignmentRecalcForbiddenScope forbid_slot_recalc(
         owner_->GetDocument());
 
-    // Before forbidding flat tree traversal, figure out which slots' subtrees
-    // are in display locked state. Note that it could be the slot itself is
-    // locked or it could be that some flat tree ancestor of the slot is locked.
-    HeapHashMap<Member<HTMLSlotElement>, bool> display_lock_map;
-    for (Member<HTMLSlotElement> slot : Slots()) {
-      display_lock_map.Set(
-          slot, DisplayLockUtilities::IsInLockedSubtreeCrossingFrames(
-                    *slot, kIncludeSelf));
-    }
-
     FlatTreeTraversalForbiddenScope forbid_flat_tree_traversal(
         owner_->GetDocument());
 
@@ -349,8 +339,14 @@
           .RemoveShadowRootNeedingRecalc(*owner_);
     }
 
-    for (auto& slot : Slots())
-      slot->DidRecalcAssignedNodes(display_lock_map.at(slot));
+    for (auto& slot : Slots()) {
+      // TODO(crbug.com/1208573): Consider if we really need to be using
+      // IsInLockedSubtreeCrossingFrames, or if
+      // NearestLockedInclusiveAncestorWithinTreeScope is good enough as-is.
+      slot->DidRecalcAssignedNodes(
+          DisplayLockUtilities::NearestLockedInclusiveAncestorWithinTreeScope(
+              *slot));
+    }
   }
 
   // Update an dir=auto flag from a host of slots to its all descendants.
diff --git a/third_party/blink/renderer/core/frame/ad_tracker_test.cc b/third_party/blink/renderer/core/frame/ad_tracker_test.cc
index a5d8f1de..fa6c51724 100644
--- a/third_party/blink/renderer/core/frame/ad_tracker_test.cc
+++ b/third_party/blink/renderer/core/frame/ad_tracker_test.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "base/containers/contains.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc
index fae1149..6831470 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.cc
+++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -29,6 +29,7 @@
 #include <memory>
 #include <utility>
 
+#include "base/containers/contains.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/trace_event/typed_macros.h"
 #include "build/build_config.h"
@@ -462,6 +463,8 @@
     GetFrame()->Console().AddMessage(MakeGarbageCollected<ConsoleMessage>(
         mojom::blink::ConsoleMessageSource::kViolation,
         mojom::blink::ConsoleMessageLevel::kError, body->message()));
+
+    CountPermissionsPolicyViolation(feature);
   }
 }
 
@@ -595,6 +598,16 @@
     loader->CountUse(feature);
 }
 
+void LocalDOMWindow::CountPermissionsPolicyViolation(
+    mojom::blink::PermissionsPolicyFeature feature) const {
+  if (!GetFrame())
+    return;
+  if (auto* loader = GetFrame()->Loader().GetDocumentLoader()) {
+    loader->GetUseCounter().CountPermissionsPolicyViolation(feature,
+                                                            *GetFrame());
+  }
+}
+
 void LocalDOMWindow::CountUseOnlyInCrossOriginIframe(
     mojom::blink::WebFeature feature) {
   if (GetFrame() && GetFrame()->IsCrossOriginToMainFrame())
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.h b/third_party/blink/renderer/core/frame/local_dom_window.h
index 5804da0..32a0a05 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.h
+++ b/third_party/blink/renderer/core/frame/local_dom_window.h
@@ -458,6 +458,12 @@
   // Return the viewport size including scrollbars.
   IntSize GetViewportSize() const;
 
+  // Count feature disabled by Permissions Policy through use counter.
+  // The method is marked const as its caller |ReportPermissionsPolicyViolation|
+  // is marked const.
+  void CountPermissionsPolicyViolation(
+      mojom::blink::PermissionsPolicyFeature feature) const;
+
   Member<ScriptController> script_controller_;
 
   Member<Document> document_;
diff --git a/third_party/blink/renderer/core/frame/use_counter_impl.cc b/third_party/blink/renderer/core/frame/use_counter_impl.cc
index 598be05..3dacfcc 100644
--- a/third_party/blink/renderer/core/frame/use_counter_impl.cc
+++ b/third_party/blink/renderer/core/frame/use_counter_impl.cc
@@ -26,6 +26,7 @@
 #include "third_party/blink/renderer/core/frame/use_counter_impl.h"
 
 #include "base/metrics/histogram_macros.h"
+#include "third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom-blink.h"
 #include "third_party/blink/public/mojom/use_counter/use_counter_feature.mojom-blink.h"
 #include "third_party/blink/renderer/core/css/css_style_sheet.h"
 #include "third_party/blink/renderer/core/css/style_sheet_contents.h"
@@ -191,6 +192,16 @@
         source_frame);
 }
 
+void UseCounterImpl::CountPermissionsPolicyViolation(
+    mojom::blink::PermissionsPolicyFeature feature,
+    const LocalFrame& source_frame) {
+  DCHECK_NE(mojom::blink::PermissionsPolicyFeature::kNotFound, feature);
+  Count(
+      {mojom::blink::UseCounterFeatureType::kPermissionsPolicyViolationEnforce,
+       static_cast<uint32_t>(feature)},
+      &source_frame);
+}
+
 void UseCounterImpl::NotifyFeatureCounted(WebFeature feature) {
   DCHECK(!mute_count_);
   DCHECK_NE(kDisabledContext, context_);
@@ -248,6 +259,9 @@
       if (context_ == kExtensionContext)
         return false;
       break;
+    case mojom::blink::UseCounterFeatureType::
+        kPermissionsPolicyViolationEnforce:
+      break;
   }
 
   client->DidObserveNewFeatureUsage(feature);
@@ -268,7 +282,13 @@
     case mojom::blink::UseCounterFeatureType::kCssProperty:
       trace_name = "CSSFirstUsed";
       break;
+    case mojom::blink::UseCounterFeatureType::
+        kPermissionsPolicyViolationEnforce:
+      // TODO(crbug.com/1206004): Add trace event for permissions policy metrics
+      // gathering.
+      return;
   }
+  DCHECK(trace_name);
   TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.feature_usage"), trace_name,
                "feature", feature.value());
 }
diff --git a/third_party/blink/renderer/core/frame/use_counter_impl.h b/third_party/blink/renderer/core/frame/use_counter_impl.h
index b9a8d7d..d7ea7dcb 100644
--- a/third_party/blink/renderer/core/frame/use_counter_impl.h
+++ b/third_party/blink/renderer/core/frame/use_counter_impl.h
@@ -29,6 +29,7 @@
 #include <bitset>
 #include "base/macros.h"
 #include "third_party/blink/public/common/use_counter/use_counter_feature_tracker.h"
+#include "third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom-blink-forward.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/css/css_property_names.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser_mode.h"
@@ -105,6 +106,8 @@
   // Repeated calls are ignored.
   void Count(CSSPropertyID, CSSPropertyType, const LocalFrame*);
   void Count(WebFeature, const LocalFrame*);
+  void CountPermissionsPolicyViolation(mojom::blink::PermissionsPolicyFeature,
+                                       const LocalFrame&);
 
   // Return whether the feature has been seen since the last page load
   // (except when muted).  Does include features seen in documents which have
diff --git a/third_party/blink/renderer/core/html/forms/form_controller.cc b/third_party/blink/renderer/core/html/forms/form_controller.cc
index 8ad94f8e..d5bb69c 100644
--- a/third_party/blink/renderer/core/html/forms/form_controller.cc
+++ b/third_party/blink/renderer/core/html/forms/form_controller.cc
@@ -195,7 +195,7 @@
 
 struct ControlKeyHashTraits : WTF::GenericHashTraits<ControlKey> {
   static void ConstructDeletedValue(ControlKey& slot, bool) {
-    new (NotNull, &slot) ControlKey(WTF::kHashTableDeletedValue);
+    new (NotNullTag::kNotNull, &slot) ControlKey(WTF::kHashTableDeletedValue);
   }
   static bool IsDeletedValue(const ControlKey& value) {
     return value.IsHashTableDeletedValue();
diff --git a/third_party/blink/renderer/core/html/media/html_video_element.cc b/third_party/blink/renderer/core/html/media/html_video_element.cc
index 25641f9..58c6c87 100644
--- a/third_party/blink/renderer/core/html/media/html_video_element.cc
+++ b/third_party/blink/renderer/core/html/media/html_video_element.cc
@@ -555,6 +555,12 @@
                                          video_renderer, dest_rect);
   if (image)
     image->SetOriginClean(!WouldTaintOrigin());
+
+  // TODO(crbug.com/1204867): The returned |image| is somehow coupled with the
+  // CanvasResourceProvider in ways that make passing |image| across threads
+  // problematic so long as the provider is still alive.
+  resource_provider_.reset();
+
   return image;
 }
 
diff --git a/third_party/blink/renderer/core/html/parser/html_tokenizer.cc b/third_party/blink/renderer/core/html/parser/html_tokenizer.cc
index 3bd2080..09c34841 100644
--- a/third_party/blink/renderer/core/html/parser/html_tokenizer.cc
+++ b/third_party/blink/renderer/core/html/parser/html_tokenizer.cc
@@ -38,11 +38,67 @@
 
 namespace blink {
 
+// clang-format off
+#define INT_0_TO_127_LIST(V)                                                    \
+V(0),   V(1),   V(2),   V(3),   V(4),   V(5),   V(6),   V(7),   V(8),   V(9),   \
+V(10),  V(11),  V(12),  V(13),  V(14),  V(15),  V(16),  V(17),  V(18),  V(19),  \
+V(20),  V(21),  V(22),  V(23),  V(24),  V(25),  V(26),  V(27),  V(28),  V(29),  \
+V(30),  V(31),  V(32),  V(33),  V(34),  V(35),  V(36),  V(37),  V(38),  V(39),  \
+V(40),  V(41),  V(42),  V(43),  V(44),  V(45),  V(46),  V(47),  V(48),  V(49),  \
+V(50),  V(51),  V(52),  V(53),  V(54),  V(55),  V(56),  V(57),  V(58),  V(59),  \
+V(60),  V(61),  V(62),  V(63),  V(64),  V(65),  V(66),  V(67),  V(68),  V(69),  \
+V(70),  V(71),  V(72),  V(73),  V(74),  V(75),  V(76),  V(77),  V(78),  V(79),  \
+V(80),  V(81),  V(82),  V(83),  V(84),  V(85),  V(86),  V(87),  V(88),  V(89),  \
+V(90),  V(91),  V(92),  V(93),  V(94),  V(95),  V(96),  V(97),  V(98),  V(99),  \
+V(100), V(101), V(102), V(103), V(104), V(105), V(106), V(107), V(108), V(109), \
+V(110), V(111), V(112), V(113), V(114), V(115), V(116), V(117), V(118), V(119), \
+V(120), V(121), V(122), V(123), V(124), V(125), V(126), V(127),
+// clang-format on
+
+// Character flags for fast paths.
+enum class ScanFlags : uint8_t {
+  // Base flags
+  kNullCharacter = 1 << 0,
+  kNewlineOrCarriageReturn = 1 << 1,
+  kWhitespaceNotNewline = 1 << 2,
+  kAmpersandAndOpenTag = 1 << 3,
+  // Compound flags
+  kWhitespace = kWhitespaceNotNewline | kNewlineOrCarriageReturn,
+  kCharacterTokenSpecial =
+      kNullCharacter | kNewlineOrCarriageReturn | kAmpersandAndOpenTag,
+  kNullOrNewline = kNullCharacter | kNewlineOrCarriageReturn,
+};
+
+static constexpr uint8_t CreateScanFlags(UChar cc) {
+#define SCAN_FLAG(flag) static_cast<uint8_t>(ScanFlags::flag)
+  DCHECK(!(cc & ~0x7F));  // IsASCII
+  uint8_t scan_flag = 0;
+  if (cc == '\0')
+    scan_flag = SCAN_FLAG(kNullCharacter);
+  else if (cc == '\n' || cc == '\r')
+    scan_flag = SCAN_FLAG(kNewlineOrCarriageReturn);
+  else if (cc == ' ' || cc == '\x09' || cc == '\x0C')
+    scan_flag = SCAN_FLAG(kWhitespaceNotNewline);
+  else if (cc == '&' || cc == '<')
+    scan_flag = SCAN_FLAG(kAmpersandAndOpenTag);
+  return scan_flag;
+#undef SCAN_FLAG
+}
+
+// Table of precomputed scan flags for the first 128 ASCII characters.
+static constexpr const uint8_t character_scan_flags_[128] = {
+    INT_0_TO_127_LIST(CreateScanFlags)};
+
 static inline UChar ToLowerCase(UChar cc) {
   DCHECK(IsASCIIAlpha(cc));
   return cc | 0x20;
 }
 
+static inline bool CheckScanFlag(UChar cc, ScanFlags flag) {
+  return IsASCII(cc) &&
+         (character_scan_flags_[cc] & static_cast<uint8_t>(flag));
+}
+
 static inline UChar ToLowerCaseIfAlpha(UChar cc) {
   return cc | (IsASCIIUpper(cc) ? 0x20 : 0);
 }
@@ -59,6 +115,8 @@
 }
 
 #define HTML_BEGIN_STATE(stateName) BEGIN_STATE(HTMLTokenizer, stateName)
+#define HTML_BEGIN_STATE_NOLABEL(stateName) \
+  BEGIN_STATE_NOLABEL(HTMLTokenizer, stateName)
 #define HTML_RECONSUME_IN(stateName) RECONSUME_IN(HTMLTokenizer, stateName)
 #define HTML_ADVANCE_TO(stateName) ADVANCE_TO(HTMLTokenizer, stateName)
 #define HTML_ADVANCE_PAST_NON_NEWLINE_TO(stateName) \
@@ -169,8 +227,7 @@
       } else if (cc == kEndOfFileMarker)
         return EmitEndOfFile(source);
       else {
-        BufferCharacter(cc);
-        HTML_CONSUME(kDataState);
+        return EmitData(source, cc);
       }
     }
     END_STATE()
@@ -227,11 +284,10 @@
     }
     END_STATE()
 
-    HTML_BEGIN_STATE(kPLAINTEXTState) {
+    HTML_BEGIN_STATE_NOLABEL(kPLAINTEXTState) {
       if (cc == kEndOfFileMarker)
         return EmitEndOfFile(source);
-      BufferCharacter(cc);
-      HTML_CONSUME(kPLAINTEXTState);
+      return EmitPLAINTEXT(source, cc);
     }
     END_STATE()
 
@@ -701,9 +757,9 @@
     END_STATE()
 
     HTML_BEGIN_STATE(kBeforeAttributeNameState) {
-      if (IsTokenizerWhitespace(cc)) {
-        HTML_CONSUME(kBeforeAttributeNameState);
-      } else if (cc == '/') {
+      if (!SkipWhitespaces(source, cc))
+        return HaveBufferedCharacterToken();
+      if (cc == '/') {
         HTML_ADVANCE_PAST_NON_NEWLINE_TO(kSelfClosingStartTagState);
       } else if (cc == '>') {
         return EmitAndResumeIn(source, HTMLTokenizer::kDataState);
@@ -748,9 +804,9 @@
     END_STATE()
 
     HTML_BEGIN_STATE(kAfterAttributeNameState) {
-      if (IsTokenizerWhitespace(cc)) {
-        HTML_CONSUME(kAfterAttributeNameState);
-      } else if (cc == '/') {
+      if (!SkipWhitespaces(source, cc))
+        return HaveBufferedCharacterToken();
+      if (cc == '/') {
         HTML_ADVANCE_PAST_NON_NEWLINE_TO(kSelfClosingStartTagState);
       } else if (cc == '=') {
         HTML_ADVANCE_PAST_NON_NEWLINE_TO(kBeforeAttributeValueState);
@@ -1092,9 +1148,9 @@
     END_STATE()
 
     HTML_BEGIN_STATE(kBeforeDOCTYPENameState) {
-      if (IsTokenizerWhitespace(cc)) {
-        HTML_CONSUME(kBeforeDOCTYPENameState);
-      } else if (cc == '>') {
+      if (!SkipWhitespaces(source, cc))
+        return HaveBufferedCharacterToken();
+      if (cc == '>') {
         ParseError();
         token_->BeginDOCTYPE();
         token_->SetForceQuirks();
@@ -1128,8 +1184,8 @@
     END_STATE()
 
     HTML_BEGIN_STATE(kAfterDOCTYPENameState) {
-      if (IsTokenizerWhitespace(cc))
-        HTML_CONSUME(kAfterDOCTYPENameState);
+      if (!SkipWhitespaces(source, cc))
+        return HaveBufferedCharacterToken();
       if (cc == '>')
         return EmitAndResumeIn(source, HTMLTokenizer::kDataState);
       else if (cc == kEndOfFileMarker) {
@@ -1191,9 +1247,9 @@
     END_STATE()
 
     HTML_BEGIN_STATE(kBeforeDOCTYPEPublicIdentifierState) {
-      if (IsTokenizerWhitespace(cc))
-        HTML_CONSUME(kBeforeDOCTYPEPublicIdentifierState);
-      else if (cc == '"') {
+      if (!SkipWhitespaces(source, cc))
+        return HaveBufferedCharacterToken();
+      if (cc == '"') {
         token_->SetPublicIdentifierToEmptyString();
         HTML_ADVANCE_PAST_NON_NEWLINE_TO(
             kDOCTYPEPublicIdentifierDoubleQuotedState);
@@ -1281,9 +1337,9 @@
     END_STATE()
 
     HTML_BEGIN_STATE(kBetweenDOCTYPEPublicAndSystemIdentifiersState) {
-      if (IsTokenizerWhitespace(cc))
-        HTML_CONSUME(kBetweenDOCTYPEPublicAndSystemIdentifiersState);
-      else if (cc == '>')
+      if (!SkipWhitespaces(source, cc))
+        return HaveBufferedCharacterToken();
+      if (cc == '>')
         return EmitAndResumeIn(source, HTMLTokenizer::kDataState);
       else if (cc == '"') {
         token_->SetSystemIdentifierToEmptyString();
@@ -1335,8 +1391,8 @@
     END_STATE()
 
     HTML_BEGIN_STATE(kBeforeDOCTYPESystemIdentifierState) {
-      if (IsTokenizerWhitespace(cc))
-        HTML_CONSUME(kBeforeDOCTYPESystemIdentifierState);
+      if (!SkipWhitespaces(source, cc))
+        return HaveBufferedCharacterToken();
       if (cc == '"') {
         token_->SetSystemIdentifierToEmptyString();
         HTML_ADVANCE_PAST_NON_NEWLINE_TO(
@@ -1398,9 +1454,9 @@
     END_STATE()
 
     HTML_BEGIN_STATE(kAfterDOCTYPESystemIdentifierState) {
-      if (IsTokenizerWhitespace(cc))
-        HTML_CONSUME(kAfterDOCTYPESystemIdentifierState);
-      else if (cc == '>')
+      if (!SkipWhitespaces(source, cc))
+        return HaveBufferedCharacterToken();
+      if (cc == '>')
         return EmitAndResumeIn(source, HTMLTokenizer::kDataState);
       else if (cc == kEndOfFileMarker) {
         ParseError();
@@ -1462,6 +1518,109 @@
   return false;
 }
 
+bool HTMLTokenizer::SkipWhitespaces(SegmentedString& source, UChar& cc) {
+  if (cc == '\n')  // We could be pointing to '\r'.
+    cc = source.CurrentChar();
+  while (true) {
+    while (CheckScanFlag(cc, ScanFlags::kWhitespaceNotNewline)) {
+      cc = source.AdvancePastNonNewline();
+    }
+    switch (cc) {
+      case '\n':
+        cc = source.AdvancePastNewlineAndUpdateLineNumber();
+        break;
+      case '\r':
+        if (!input_stream_preprocessor_.AdvancePastCarriageReturn(source, cc))
+          return false;
+        break;
+      case '\0':
+        if (!input_stream_preprocessor_.ProcessNullCharacter(source, cc))
+          return false;
+        if (cc == kEndOfFileMarker)
+          return true;
+        break;
+      default:
+        return true;
+    }
+  }
+}
+
+bool HTMLTokenizer::EmitData(SegmentedString& source, UChar cc) {
+  token_->EnsureIsCharacterToken();
+  if (cc == '\n')  // We could be pointing to '\r'.
+    cc = source.CurrentChar();
+  while (true) {
+    while (!CheckScanFlag(cc, ScanFlags::kCharacterTokenSpecial)) {
+      token_->AppendToCharacter(cc);
+      cc = source.AdvancePastNonNewline();
+    }
+    switch (cc) {
+      case '&':
+        state_ = kCharacterReferenceInDataState;
+        source.AdvanceAndASSERT('&');
+        if (!ProcessEntity(source))
+          return true;
+        state_ = kDataState;
+        if (source.IsEmpty())
+          return true;
+        cc = source.CurrentChar();
+        break;
+      case '\n':
+        token_->AppendToCharacter(cc);
+        cc = source.AdvancePastNewlineAndUpdateLineNumber();
+        break;
+      case '\r':
+        token_->AppendToCharacter('\n');  // Canonize newline.
+        if (!input_stream_preprocessor_.AdvancePastCarriageReturn(source, cc))
+          return true;
+        break;
+      case '<':
+        return true;
+      case '\0':
+        if (!input_stream_preprocessor_.ProcessNullCharacter(source, cc))
+          return true;
+        if (cc == kEndOfFileMarker)
+          return EmitEndOfFile(source);
+        break;
+      default:
+        NOTREACHED();
+        break;
+    }
+  }
+}
+
+bool HTMLTokenizer::EmitPLAINTEXT(SegmentedString& source, UChar cc) {
+  token_->EnsureIsCharacterToken();
+  if (cc == '\n')  // We could be pointing to '\r'.
+    cc = source.CurrentChar();
+  while (true) {
+    while (!CheckScanFlag(cc, ScanFlags::kNullOrNewline)) {
+      token_->AppendToCharacter(cc);
+      cc = source.AdvancePastNonNewline();
+    }
+    switch (cc) {
+      case '\n':
+        token_->AppendToCharacter(cc);
+        cc = source.AdvancePastNewlineAndUpdateLineNumber();
+        break;
+      case '\r':
+        token_->AppendToCharacter('\n');  // Canonize newline.
+        if (!input_stream_preprocessor_.AdvancePastCarriageReturn(source, cc))
+          return true;
+        break;
+      case '\0':
+        if (!input_stream_preprocessor_.ProcessNullCharacter(source, cc))
+          return true;
+        if (cc == kEndOfFileMarker)
+          return EmitEndOfFile(source);
+        break;
+      default:
+        NOTREACHED();
+        break;
+    }
+  }
+}
+
 String HTMLTokenizer::BufferedCharacters() const {
   // FIXME: Add a DCHECK about state_.
   StringBuilder characters;
diff --git a/third_party/blink/renderer/core/html/parser/html_tokenizer.h b/third_party/blink/renderer/core/html/parser/html_tokenizer.h
index 7ff835a2..242c964 100644
--- a/third_party/blink/renderer/core/html/parser/html_tokenizer.h
+++ b/third_party/blink/renderer/core/html/parser/html_tokenizer.h
@@ -195,6 +195,10 @@
  private:
   inline bool ProcessEntity(SegmentedString&);
 
+  // Returns true if it has skipped all the whitespaces and we still have
+  // characters in the source.
+  ALWAYS_INLINE bool SkipWhitespaces(SegmentedString& source, UChar& cc);
+
   inline void ParseError();
 
   inline void BufferCharacter(UChar character) {
@@ -216,6 +220,10 @@
     return true;
   }
 
+  ALWAYS_INLINE bool EmitData(SegmentedString& source, UChar cc);
+
+  ALWAYS_INLINE bool EmitPLAINTEXT(SegmentedString& source, UChar cc);
+
   inline bool EmitEndOfFile(SegmentedString& source) {
     if (HaveBufferedCharacterToken())
       return true;
diff --git a/third_party/blink/renderer/core/html/parser/input_stream_preprocessor.h b/third_party/blink/renderer/core/html/parser/input_stream_preprocessor.h
index a82e36b0..c4e65fe3 100644
--- a/third_party/blink/renderer/core/html/parser/input_stream_preprocessor.h
+++ b/third_party/blink/renderer/core/html/parser/input_stream_preprocessor.h
@@ -36,6 +36,9 @@
 
 const LChar kEndOfFileMarker = 0;
 
+// https://html.spec.whatwg.org/#parse-error-unexpected-null-character
+const UChar kReplacementCharacter = 0xFFFD;
+
 // http://www.whatwg.org/specs/web-apps/current-work/#preprocessing-the-input-stream
 template <typename Tokenizer>
 class InputStreamPreprocessor {
@@ -65,10 +68,44 @@
     return ProcessNextInputCharacter(source, cc);
   }
 
-  bool SkipNextNewLine() const { return skip_next_new_line_; }
+  // WARNING: This does not process null characters.
+  ALWAYS_INLINE bool AdvancePastCarriageReturn(SegmentedString& source,
+                                               UChar& cc) {
+    DCHECK_EQ(cc, '\r');
+    cc = source.AdvancePastNonNewline();
+    if (source.IsEmpty()) {
+      skip_next_new_line_ = true;
+      return false;
+    }
+    // We skip if '\r\n'
+    if (cc == '\n') {
+      cc = source.AdvancePastNewlineAndUpdateLineNumber();
+      if (source.IsEmpty())
+        return false;
+    }
+    return true;
+  }
 
-  void Reset(bool skip_next_new_line = false) {
-    skip_next_new_line_ = skip_next_new_line;
+  // WARNING: This does not canonize newlines.
+  ALWAYS_INLINE bool ProcessNullCharacter(SegmentedString& source, UChar& cc) {
+    DCHECK_EQ(cc, '\0');
+    if (source.IsEmpty())
+      return false;
+    if (ShouldTreatNullAsEndOfFileMarker(source))
+      return true;
+    if (!tokenizer_->ShouldSkipNullCharacters()) {
+      cc = kReplacementCharacter;
+      return true;
+    }
+    cc = source.AdvancePastNonNewline();
+    while (cc == '\0') {
+      if (source.IsEmpty())
+        return false;
+      if (ShouldTreatNullAsEndOfFileMarker(source))
+        return true;
+      cc = source.AdvancePastNonNewline();
+    }
+    return true;
   }
 
  private:
@@ -117,7 +154,7 @@
             return false;
           goto ProcessAgain;
         }
-        cc = 0xFFFD;
+        cc = kReplacementCharacter;
       }
     }
     return true;
diff --git a/third_party/blink/renderer/core/html/parser/markup_tokenizer_inlines.h b/third_party/blink/renderer/core/html/parser/markup_tokenizer_inlines.h
index e752dde..c4122dc 100644
--- a/third_party/blink/renderer/core/html/parser/markup_tokenizer_inlines.h
+++ b/third_party/blink/renderer/core/html/parser/markup_tokenizer_inlines.h
@@ -59,6 +59,7 @@
 #define BEGIN_STATE(prefix, stateName) \
   case prefix::stateName:              \
   stateName:
+#define BEGIN_STATE_NOLABEL(prefix, stateName) case prefix::stateName:
 #define END_STATE() \
   NOTREACHED();     \
   break;
diff --git a/third_party/blink/renderer/core/inspector/legacy_dom_snapshot_agent.cc b/third_party/blink/renderer/core/inspector/legacy_dom_snapshot_agent.cc
index f595d22..e99d87f51 100644
--- a/third_party/blink/renderer/core/inspector/legacy_dom_snapshot_agent.cc
+++ b/third_party/blink/renderer/core/inspector/legacy_dom_snapshot_agent.cc
@@ -79,7 +79,8 @@
   }
 
   static void ConstructDeletedValue(Vector<String>& vec, bool) {
-    new (NotNull, &vec) Vector<String>(WTF::kHashTableDeletedValue);
+    new (NotNullTag::kNotNull, &vec)
+        Vector<String>(WTF::kHashTableDeletedValue);
   }
 
   static bool IsDeletedValue(const Vector<String>& vec) {
diff --git a/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc
index e8b149f4..729662e 100644
--- a/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc
@@ -1331,7 +1331,9 @@
     builder.SetPercentageResolutionBlockSize(child_percentage_size_.block_size);
     builder.SetReplacedPercentageResolutionBlockSize(
         child_percentage_size_.block_size);
-    if (WillChildCrossSizeBeContainerCrossSize(child) && !is_column_)
+    if (is_column_)
+      builder.SetIsFixedBlockSizeIndefinite(true);
+    else if (WillChildCrossSizeBeContainerCrossSize(child))
       builder.SetStretchBlockSizeIfAuto(true);
     const auto space = builder.ToConstraintSpace();
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
index c3766f39..705ca5e 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
@@ -537,6 +537,10 @@
     delegate_.SetStretchBlockSizeIfAuto(b);
   }
 
+  void SetIsFixedBlockSizeIndefinite(bool b) {
+    delegate_.SetIsFixedBlockSizeIndefinite(b);
+  }
+
   const NGConstraintSpace ToConstraintSpace() {
     return delegate_.ToConstraintSpace();
   }
diff --git a/third_party/blink/renderer/core/loader/mixed_content_checker.cc b/third_party/blink/renderer/core/loader/mixed_content_checker.cc
index 0920183..27658f5c 100644
--- a/third_party/blink/renderer/core/loader/mixed_content_checker.cc
+++ b/third_party/blink/renderer/core/loader/mixed_content_checker.cc
@@ -28,6 +28,7 @@
 
 #include "third_party/blink/renderer/core/loader/mixed_content_checker.h"
 
+#include "base/containers/contains.h"
 #include "base/feature_list.h"
 #include "base/metrics/field_trial_params.h"
 #include "base/optional.h"
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
index ec6b1c2..6ac8d96 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -1040,18 +1040,32 @@
   }
 
   bool needs_end_layer = false;
-  if (!box_decoration_data.IsPaintingScrollingBackground() &&
-      BleedAvoidanceIsClipping(
-          box_decoration_data.GetBackgroundBleedAvoidance())) {
-    state_saver.Save();
-    FloatRoundedRect border = RoundedBorderGeometry::PixelSnappedRoundedBorder(
-        style, paint_rect, box_fragment_.SidesToInclude());
-    paint_info.context.ClipRoundedRect(border);
+  if (!box_decoration_data.IsPaintingScrollingBackground()) {
+    if (box_fragment_.HasSelfPaintingLayer() && layout_box.IsTableCell() &&
+        ToInterface<LayoutNGTableCellInterface>(layout_box)
+            .TableInterface()
+            ->ShouldCollapseBorders()) {
+      // TODO(crbug.com/1081425) This branch is only used by Legacy
+      // tables. Remove when Legacy tables are removed.
+      // We have to clip here because the background would paint on top of the
+      // collapsed table borders otherwise, since this is a self-painting layer.
+      PhysicalRect clip_rect = paint_rect;
+      clip_rect.Expand(layout_box.BorderInsets());
+      state_saver.Save();
+      paint_info.context.Clip(PixelSnappedIntRect(clip_rect));
+    } else if (BleedAvoidanceIsClipping(
+                   box_decoration_data.GetBackgroundBleedAvoidance())) {
+      state_saver.Save();
+      FloatRoundedRect border =
+          RoundedBorderGeometry::PixelSnappedRoundedBorder(
+              style, paint_rect, box_fragment_.SidesToInclude());
+      paint_info.context.ClipRoundedRect(border);
 
-    if (box_decoration_data.GetBackgroundBleedAvoidance() ==
-        kBackgroundBleedClipLayer) {
-      paint_info.context.BeginLayer();
-      needs_end_layer = true;
+      if (box_decoration_data.GetBackgroundBleedAvoidance() ==
+          kBackgroundBleedClipLayer) {
+        paint_info.context.BeginLayer();
+        needs_end_layer = true;
+      }
     }
   }
 
diff --git a/third_party/blink/renderer/core/testing/mock_clipboard_host.cc b/third_party/blink/renderer/core/testing/mock_clipboard_host.cc
index eb2d0b553..adf990e8 100644
--- a/third_party/blink/renderer/core/testing/mock_clipboard_host.cc
+++ b/third_party/blink/renderer/core/testing/mock_clipboard_host.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/testing/mock_clipboard_host.h"
 
+#include "base/containers/contains.h"
 #include "build/build_config.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/timing/performance.cc b/third_party/blink/renderer/core/timing/performance.cc
index 8620a1e..735e988 100644
--- a/third_party/blink/renderer/core/timing/performance.cc
+++ b/third_party/blink/renderer/core/timing/performance.cc
@@ -33,6 +33,7 @@
 
 #include <algorithm>
 
+#include "base/containers/contains.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/time/default_clock.h"
 #include "base/time/default_tick_clock.h"
diff --git a/third_party/blink/renderer/core/timing/performance_navigation_timing.cc b/third_party/blink/renderer/core/timing/performance_navigation_timing.cc
index 2e0ed206..322cd00 100644
--- a/third_party/blink/renderer/core/timing/performance_navigation_timing.cc
+++ b/third_party/blink/renderer/core/timing/performance_navigation_timing.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/timing/performance_navigation_timing.h"
 
+#include "base/containers/contains.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_object_builder.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/document_timing.h"
diff --git a/third_party/blink/renderer/core/timing/profiler_group.cc b/third_party/blink/renderer/core/timing/profiler_group.cc
index 49c3d2e..d404c85 100644
--- a/third_party/blink/renderer/core/timing/profiler_group.cc
+++ b/third_party/blink/renderer/core/timing/profiler_group.cc
@@ -127,7 +127,7 @@
 
 void DiscardedSamplesDelegate::Notify() {
   if (profiler_group_) {
-    profiler_group_->DispatchSampleBufferFullEvent();
+    profiler_group_->DispatchSampleBufferFullEvent(profiler_id_);
   }
 }
 
@@ -144,10 +144,13 @@
   }
 }
 
-void ProfilerGroup::DispatchSampleBufferFullEvent() {
+void ProfilerGroup::DispatchSampleBufferFullEvent(String profiler_id) {
   for (const auto& profiler : profilers_) {
-    profiler->DispatchEvent(
-        *Event::Create(event_type_names::kSamplebufferfull));
+    if (profiler->ProfilerId() == profiler_id) {
+      profiler->DispatchEvent(
+          *Event::Create(event_type_names::kSamplebufferfull));
+      break;
+    }
   }
 }
 
@@ -186,7 +189,7 @@
 
   v8::CpuProfilingStatus status = cpu_profiler_->StartProfiling(
       V8String(isolate_, profiler_id), options,
-      std::make_unique<DiscardedSamplesDelegate>(this));
+      std::make_unique<DiscardedSamplesDelegate>(this, profiler_id));
 
   switch (status) {
     case v8::CpuProfilingStatus::kErrorTooManyProfilers: {
@@ -223,7 +226,6 @@
       auto* profiler = MakeGarbageCollected<Profiler>(
           this, script_state, profiler_id, effective_sample_interval_ms,
           source_origin, time_origin);
-
       profilers_.insert(profiler);
       num_active_profilers_++;
       return profiler;
diff --git a/third_party/blink/renderer/core/timing/profiler_group.h b/third_party/blink/renderer/core/timing/profiler_group.h
index 40fa83b..5b91224 100644
--- a/third_party/blink/renderer/core/timing/profiler_group.h
+++ b/third_party/blink/renderer/core/timing/profiler_group.h
@@ -58,7 +58,7 @@
   // profiler is ready during its lifetime.
   void OnProfilingContextAdded(ExecutionContext* context);
 
-  void DispatchSampleBufferFullEvent();
+  void DispatchSampleBufferFullEvent(String profiler_id);
   void WillBeDestroyed() override;
   void Trace(Visitor*) const override;
 
@@ -99,14 +99,16 @@
 
 class DiscardedSamplesDelegate : public v8::DiscardedSamplesDelegate {
  public:
-  explicit DiscardedSamplesDelegate(ProfilerGroup* profiler_group)
-      : profiler_group_(profiler_group) {}
+  explicit DiscardedSamplesDelegate(ProfilerGroup* profiler_group,
+                                    String profiler_id)
+      : profiler_group_(profiler_group), profiler_id_(profiler_id) {}
   void Notify() override;
 
  private:
   // It is important to keep a weak reference to the profiler group
   // because Notify may be invoked after profiling stops and ProfilerGroup dies.
   WeakPersistent<ProfilerGroup> profiler_group_;
+  const String profiler_id_;
 };
 }  // namespace blink
 
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
index 6aa5a583..c2a25114 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
@@ -2048,7 +2048,10 @@
     if (new_object) {
       // Any owned objects need to reset their parent_ to point to the
       // new object.
-      relation_cache_->UpdateAriaOwnsWithCleanLayout(new_object, true);
+      if (AXObject::HasARIAOwns(DynamicTo<Element>(node)) &&
+          AXRelationCache::IsValidOwner(new_object)) {
+        relation_cache_->UpdateAriaOwnsWithCleanLayout(new_object, true);
+      }
     } else {
       // Failed to create, so remove object completely.
       RemoveAXID(current);
@@ -2116,7 +2119,12 @@
       if (new_object &&
           new_object->ShouldUseLayoutObjectTraversalForChildren() !=
               did_use_layout_object_traversal) {
-        // TODO(accessibility) Need test for this.
+        // TODO(accessibility) Add test or remove code.
+        SANITIZER_CHECK(false)
+            << "This should no longer be possible, an object only uses layout "
+               "object traversal if it is the descendant of a pseudo element, "
+               "and that never changes: "
+            << new_object->ToString(true, true);
         DCHECK(!HashTraits<AXID>::IsDeletedValue(ax_id));
         pending_children_changed_ids.insert(ax_id);
       }
diff --git a/third_party/blink/renderer/modules/breakout_box/frame_queue_transferring_optimizer.h b/third_party/blink/renderer/modules/breakout_box/frame_queue_transferring_optimizer.h
index 6dc626d..dca99cb7 100644
--- a/third_party/blink/renderer/modules/breakout_box/frame_queue_transferring_optimizer.h
+++ b/third_party/blink/renderer/modules/breakout_box/frame_queue_transferring_optimizer.h
@@ -51,7 +51,7 @@
 
 using VideoFrameQueueTransferOptimizer =
     FrameQueueTransferringOptimizer<scoped_refptr<media::VideoFrame>>;
-using AudioFrameQueueTransferOptimizer =
+using AudioDataQueueTransferOptimizer =
     FrameQueueTransferringOptimizer<scoped_refptr<media::AudioBuffer>>;
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/breakout_box/frame_queue_underlying_source.cc b/third_party/blink/renderer/modules/breakout_box/frame_queue_underlying_source.cc
index 37a5f92..b484bca 100644
--- a/third_party/blink/renderer/modules/breakout_box/frame_queue_underlying_source.cc
+++ b/third_party/blink/renderer/modules/breakout_box/frame_queue_underlying_source.cc
@@ -9,7 +9,7 @@
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/streams/readable_stream_default_controller_with_script_scope.h"
-#include "third_party/blink/renderer/modules/webcodecs/audio_frame.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_data.h"
 #include "third_party/blink/renderer/modules/webcodecs/video_frame.h"
 #include "third_party/blink/renderer/platform/bindings/exception_code.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -297,7 +297,7 @@
 FrameQueueUnderlyingSource<scoped_refptr<media::AudioBuffer>>::MakeBlinkFrame(
     scoped_refptr<media::AudioBuffer> media_frame) {
   DCHECK(realm_task_runner_->RunsTasksInCurrentSequence());
-  return MakeGarbageCollected<AudioFrame>(std::move(media_frame));
+  return MakeGarbageCollected<AudioData>(std::move(media_frame));
 }
 
 template class MODULES_TEMPLATE_EXPORT
diff --git a/third_party/blink/renderer/modules/breakout_box/frame_queue_underlying_source.h b/third_party/blink/renderer/modules/breakout_box/frame_queue_underlying_source.h
index bf7502f..a50a0a82 100644
--- a/third_party/blink/renderer/modules/breakout_box/frame_queue_underlying_source.h
+++ b/third_party/blink/renderer/modules/breakout_box/frame_queue_underlying_source.h
@@ -140,7 +140,7 @@
 
 using VideoFrameQueueUnderlyingSource =
     FrameQueueUnderlyingSource<scoped_refptr<media::VideoFrame>>;
-using AudioFrameQueueUnderlyingSource =
+using AudioDataQueueUnderlyingSource =
     FrameQueueUnderlyingSource<scoped_refptr<media::AudioBuffer>>;
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_sink.cc b/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_sink.cc
index ccaf7f0..6f64374 100644
--- a/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_sink.cc
+++ b/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_sink.cc
@@ -5,9 +5,9 @@
 #include "third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_sink.h"
 
 #include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_frame.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_data.h"
 #include "third_party/blink/renderer/modules/breakout_box/pushable_media_stream_audio_source.h"
-#include "third_party/blink/renderer/modules/webcodecs/audio_frame.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_data.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
@@ -31,15 +31,15 @@
     ScriptValue chunk,
     WritableStreamDefaultController* controller,
     ExceptionState& exception_state) {
-  AudioFrame* audio_frame = V8AudioFrame::ToImplWithTypeCheck(
+  AudioData* audio_data = V8AudioData::ToImplWithTypeCheck(
       script_state->GetIsolate(), chunk.V8Value());
-  if (!audio_frame) {
-    exception_state.ThrowTypeError("Null audio frame.");
+  if (!audio_data) {
+    exception_state.ThrowTypeError("Null audio data.");
     return ScriptPromise();
   }
 
-  if (!audio_frame->data()) {
-    exception_state.ThrowTypeError("Empty or closed audio frame.");
+  if (!audio_data->data()) {
+    exception_state.ThrowTypeError("Empty or closed audio data.");
     return ScriptPromise();
   }
 
@@ -51,8 +51,8 @@
     return ScriptPromise();
   }
 
-  pushable_source->PushAudioData(audio_frame->data());
-  audio_frame->close();
+  pushable_source->PushAudioData(audio_data->data());
+  audio_data->close();
 
   return ScriptPromise::CastUndefined(script_state);
 }
diff --git a/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_sink.h b/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_sink.h
index 6ee7f22..7ed1faf 100644
--- a/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_sink.h
+++ b/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_sink.h
@@ -7,7 +7,7 @@
 
 #include "third_party/blink/renderer/core/streams/underlying_sink_base.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/modules/webcodecs/audio_frame.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_data.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_sink_test.cc b/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_sink_test.cc
index e3f017b..37cb8bbf 100644
--- a/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_sink_test.cc
+++ b/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_sink_test.cc
@@ -13,7 +13,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_tester.h"
 #include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_frame.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_data.h"
 #include "third_party/blink/renderer/core/streams/writable_stream.h"
 #include "third_party/blink/renderer/core/streams/writable_stream_default_writer.h"
 #include "third_party/blink/renderer/modules/breakout_box/pushable_media_stream_audio_source.h"
@@ -60,20 +60,20 @@
     pushable_audio_source_->ConnectToTrack(media_stream_component_);
   }
 
-  ScriptValue CreateAudioFrame(ScriptState* script_state,
-                               AudioFrame** audio_frame_out = nullptr) {
+  ScriptValue CreateAudioData(ScriptState* script_state,
+                              AudioData** audio_data_out = nullptr) {
     const scoped_refptr<media::AudioBuffer> media_buffer =
         media::AudioBuffer::CreateEmptyBuffer(
             media::ChannelLayout::CHANNEL_LAYOUT_STEREO,
             /*channel_count=*/2,
             /*sample_rate=*/44100,
             /*frame_count=*/500, base::TimeDelta());
-    AudioFrame* audio_frame =
-        MakeGarbageCollected<AudioFrame>(std::move(media_buffer));
-    if (audio_frame_out)
-      *audio_frame_out = audio_frame;
+    AudioData* audio_data =
+        MakeGarbageCollected<AudioData>(std::move(media_buffer));
+    if (audio_data_out)
+      *audio_data_out = audio_data;
     return ScriptValue(script_state->GetIsolate(),
-                       ToV8(audio_frame, script_state->GetContext()->Global(),
+                       ToV8(audio_data, script_state->GetContext()->Global(),
                             script_state->GetIsolate()));
   }
 
@@ -107,16 +107,16 @@
   NonThrowableExceptionState exception_state;
   auto* writer = writable_stream->getWriter(script_state, exception_state);
 
-  AudioFrame* audio_frame = nullptr;
-  auto audio_frame_chunk = CreateAudioFrame(script_state, &audio_frame);
-  EXPECT_NE(audio_frame, nullptr);
-  EXPECT_NE(audio_frame->buffer(), nullptr);
+  AudioData* audio_data = nullptr;
+  auto audio_data_chunk = CreateAudioData(script_state, &audio_data);
+  EXPECT_NE(audio_data, nullptr);
+  EXPECT_NE(audio_data->buffer(), nullptr);
   ScriptPromiseTester write_tester(
       script_state,
-      writer->write(script_state, audio_frame_chunk, exception_state));
-  // |audio_frame| should be invalidated after sending it to the sink.
+      writer->write(script_state, audio_data_chunk, exception_state));
+  // |audio_data| should be invalidated after sending it to the sink.
   write_tester.WaitUntilSettled();
-  EXPECT_EQ(audio_frame->buffer(), nullptr);
+  EXPECT_EQ(audio_data->buffer(), nullptr);
   write_loop.Run();
 
   writer->releaseLock(script_state);
@@ -126,7 +126,7 @@
 
   // Writing to the sink after the stream closes should fail.
   DummyExceptionStateForTesting dummy_exception_state;
-  underlying_sink->write(script_state, CreateAudioFrame(script_state), nullptr,
+  underlying_sink->write(script_state, CreateAudioData(script_state), nullptr,
                          dummy_exception_state);
   EXPECT_TRUE(dummy_exception_state.HadException());
   EXPECT_EQ(dummy_exception_state.Code(),
@@ -142,7 +142,7 @@
   auto* sink = CreateUnderlyingSink(script_state);
   ScriptValue v8_integer = ScriptValue::From(script_state, 0);
 
-  // Writing something that is not an AudioFrame to the sink should fail.
+  // Writing something that is not an AudioData to the sink should fail.
   DummyExceptionStateForTesting dummy_exception_state;
   sink->write(script_state, v8_integer, nullptr, dummy_exception_state);
   EXPECT_TRUE(dummy_exception_state.HadException());
@@ -154,11 +154,11 @@
               nullptr, dummy_exception_state);
   EXPECT_TRUE(dummy_exception_state.HadException());
 
-  // Writing a closed AudioFrame to the sink should fail.
+  // Writing a closed AudioData to the sink should fail.
   dummy_exception_state.ClearException();
-  AudioFrame* audio_frame = nullptr;
-  auto chunk = CreateAudioFrame(script_state, &audio_frame);
-  audio_frame->close();
+  AudioData* audio_data = nullptr;
+  auto chunk = CreateAudioData(script_state, &audio_data);
+  audio_data->close();
   EXPECT_FALSE(dummy_exception_state.HadException());
   sink->write(script_state, chunk, nullptr, dummy_exception_state);
   EXPECT_TRUE(dummy_exception_state.HadException());
@@ -178,7 +178,7 @@
 
   // Writing to the sink after the stream closes should fail.
   DummyExceptionStateForTesting dummy_exception_state;
-  underlying_sink->write(script_state, CreateAudioFrame(script_state), nullptr,
+  underlying_sink->write(script_state, CreateAudioData(script_state), nullptr,
                          dummy_exception_state);
   EXPECT_TRUE(dummy_exception_state.HadException());
   EXPECT_EQ(dummy_exception_state.Code(),
diff --git a/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.cc b/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.cc
index 8d2ebb5..5b3ac3c 100644
--- a/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.cc
+++ b/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.cc
@@ -15,7 +15,7 @@
     MediaStreamComponent* track,
     ScriptWrappable* media_stream_track_processor,
     wtf_size_t max_queue_size)
-    : AudioFrameQueueUnderlyingSource(script_state, max_queue_size),
+    : AudioDataQueueUnderlyingSource(script_state, max_queue_size),
       media_stream_track_processor_(media_stream_track_processor),
       track_(track) {
   DCHECK(track_);
@@ -43,14 +43,14 @@
 }
 
 void MediaStreamAudioTrackUnderlyingSource::ContextDestroyed() {
-  AudioFrameQueueUnderlyingSource::ContextDestroyed();
+  AudioDataQueueUnderlyingSource::ContextDestroyed();
   DisconnectFromTrack();
 }
 
 void MediaStreamAudioTrackUnderlyingSource::Trace(Visitor* visitor) const {
   visitor->Trace(media_stream_track_processor_);
   visitor->Trace(track_);
-  AudioFrameQueueUnderlyingSource::Trace(visitor);
+  AudioDataQueueUnderlyingSource::Trace(visitor);
 }
 
 void MediaStreamAudioTrackUnderlyingSource::OnData(
diff --git a/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.h b/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.h
index 29072fc..283b8bc4 100644
--- a/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.h
+++ b/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.h
@@ -16,7 +16,7 @@
 class MediaStreamComponent;
 
 class MODULES_EXPORT MediaStreamAudioTrackUnderlyingSource
-    : public AudioFrameQueueUnderlyingSource,
+    : public AudioDataQueueUnderlyingSource,
       public WebMediaStreamAudioSink {
   USING_PRE_FINALIZER(MediaStreamAudioTrackUnderlyingSource,
                       DisconnectFromTrack);
diff --git a/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source_test.cc b/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source_test.cc
index 4633f1f..7279ce5 100644
--- a/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source_test.cc
+++ b/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source_test.cc
@@ -71,9 +71,9 @@
   static const int kSampleRate = 8000;
   static const int kNumFrames = 10;
 
-  // Pushes a frame into |track|. |timestamp| is the reference time at the
+  // Pushes data into |track|. |timestamp| is the reference time at the
   // beginning of the audio data to be pushed into |track|.
-  void PushFrame(
+  void PushData(
       MediaStreamTrack* track,
       const base::Optional<base::TimeDelta>& timestamp = base::nullopt) {
     auto data = media::AudioBuffer::CreateEmptyBuffer(
@@ -91,7 +91,7 @@
 };
 
 TEST_F(MediaStreamAudioTrackUnderlyingSourceTest,
-       AudioFrameFlowsThroughStreamAndCloses) {
+       AudioDataFlowsThroughStreamAndCloses) {
   V8TestingScope v8_scope;
   ScriptState* script_state = v8_scope.GetScriptState();
   auto* track = CreateTrack(v8_scope.GetExecutionContext());
@@ -106,7 +106,7 @@
   ScriptPromiseTester read_tester(script_state,
                                   reader->read(script_state, exception_state));
   EXPECT_FALSE(read_tester.IsFulfilled());
-  PushFrame(track);
+  PushData(track);
   read_tester.WaitUntilSettled();
   EXPECT_TRUE(read_tester.IsFulfilled());
 
@@ -156,7 +156,7 @@
     base::RunLoop sink_loop;
     EXPECT_CALL(mock_sink, OnData(_, _))
         .WillOnce(base::test::RunOnceClosure(sink_loop.QuitClosure()));
-    PushFrame(track, timestamp);
+    PushData(track, timestamp);
     sink_loop.Run();
   };
 
@@ -215,7 +215,7 @@
     base::RunLoop sink_loop;
     EXPECT_CALL(mock_sink, OnData(_, _))
         .WillOnce(base::test::RunOnceClosure(sink_loop.QuitClosure()));
-    PushFrame(track);
+    PushData(track);
     sink_loop.Run();
   };
 
diff --git a/third_party/blink/renderer/modules/breakout_box/media_stream_track_generator.idl b/third_party/blink/renderer/modules/breakout_box/media_stream_track_generator.idl
index b2cd175..7cdd15d9 100644
--- a/third_party/blink/renderer/modules/breakout_box/media_stream_track_generator.idl
+++ b/third_party/blink/renderer/modules/breakout_box/media_stream_track_generator.idl
@@ -14,7 +14,7 @@
   [CallWith=ScriptState, RaisesException, MeasureAs=MediaStreamTrackGenerator]
   constructor(MediaStreamTrackGeneratorInit init);
 
-  // This streams takes VideoFrame or AudioFrame objects.
+  // This streams takes VideoFrame or AudioData objects.
   [CallWith=ScriptState] readonly attribute WritableStream writable;
 
   // This stream returns MediaStreamTrackSignal objects.
diff --git a/third_party/blink/renderer/modules/breakout_box/media_stream_track_generator_test.cc b/third_party/blink/renderer/modules/breakout_box/media_stream_track_generator_test.cc
index d80813a..8a1f05e0 100644
--- a/third_party/blink/renderer/modules/breakout_box/media_stream_track_generator_test.cc
+++ b/third_party/blink/renderer/modules/breakout_box/media_stream_track_generator_test.cc
@@ -25,7 +25,7 @@
 #include "third_party/blink/renderer/modules/mediastream/mock_media_stream_audio_sink.h"
 #include "third_party/blink/renderer/modules/mediastream/mock_media_stream_video_sink.h"
 #include "third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.h"
-#include "third_party/blink/renderer/modules/webcodecs/audio_frame.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_data.h"
 #include "third_party/blink/renderer/modules/webcodecs/video_frame.h"
 #include "third_party/blink/renderer/platform/bindings/exception_code.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -47,15 +47,15 @@
                           script_state->GetIsolate()));
 }
 
-ScriptValue CreateAudioFrameChunk(ScriptState* script_state) {
-  AudioFrame* audio_frame =
-      MakeGarbageCollected<AudioFrame>(media::AudioBuffer::CreateEmptyBuffer(
+ScriptValue CreateAudioDataChunk(ScriptState* script_state) {
+  AudioData* audio_data =
+      MakeGarbageCollected<AudioData>(media::AudioBuffer::CreateEmptyBuffer(
           media::ChannelLayout::CHANNEL_LAYOUT_STEREO,
           /*channel_count=*/2,
           /*sample_rate=*/44100,
           /*frame_count=*/500, base::TimeDelta()));
   return ScriptValue(script_state->GetIsolate(),
-                     ToV8(audio_frame, script_state->GetContext()->Global(),
+                     ToV8(audio_data, script_state->GetContext()->Global(),
                           script_state->GetIsolate()));
 }
 
@@ -112,7 +112,7 @@
   EXPECT_TRUE(generator->Ended());
 }
 
-TEST_F(MediaStreamTrackGeneratorTest, AudioFramesAreWritten) {
+TEST_F(MediaStreamTrackGeneratorTest, AudioDataAreWritten) {
   V8TestingScope v8_scope;
   ScriptState* script_state = v8_scope.GetScriptState();
   MediaStreamTrackGenerator* generator = MediaStreamTrackGenerator::Create(
@@ -133,7 +133,7 @@
                      ->getWriter(script_state, exception_state);
   ScriptPromiseTester write_tester(
       script_state,
-      writer->write(script_state, CreateAudioFrameChunk(script_state),
+      writer->write(script_state, CreateAudioDataChunk(script_state),
                     exception_state));
   EXPECT_FALSE(write_tester.IsFulfilled());
   write_tester.WaitUntilSettled();
diff --git a/third_party/blink/renderer/modules/breakout_box/media_stream_track_processor_test.cc b/third_party/blink/renderer/modules/breakout_box/media_stream_track_processor_test.cc
index 73ab78c..1628772 100644
--- a/third_party/blink/renderer/modules/breakout_box/media_stream_track_processor_test.cc
+++ b/third_party/blink/renderer/modules/breakout_box/media_stream_track_processor_test.cc
@@ -165,7 +165,7 @@
   EXPECT_EQ(mock_video_sink.last_frame(), frame);
 }
 
-TEST_F(MediaStreamTrackProcessorTest, AudioFramesAreExposed) {
+TEST_F(MediaStreamTrackProcessorTest, AudioDataAreExposed) {
   V8TestingScope v8_scope;
   ScriptState* script_state = v8_scope.GetScriptState();
   ExceptionState& exception_state = v8_scope.GetExceptionState();
@@ -191,7 +191,7 @@
           ->GetDefaultReaderForTesting(script_state, exception_state);
   EXPECT_FALSE(exception_state.HadException());
 
-  // Deliver a frame.
+  // Deliver data.
   base::RunLoop sink_loop;
   EXPECT_CALL(mock_audio_sink, OnData(_, _))
       .WillOnce(base::test::RunOnceClosure(sink_loop.QuitClosure()));
diff --git a/third_party/blink/renderer/modules/breakout_box/transferred_frame_queue_underlying_source.h b/third_party/blink/renderer/modules/breakout_box/transferred_frame_queue_underlying_source.h
index e9105c2..26e785f 100644
--- a/third_party/blink/renderer/modules/breakout_box/transferred_frame_queue_underlying_source.h
+++ b/third_party/blink/renderer/modules/breakout_box/transferred_frame_queue_underlying_source.h
@@ -51,7 +51,7 @@
 
 using TransferredVideoFrameQueueUnderlyingSource =
     TransferredFrameQueueUnderlyingSource<scoped_refptr<media::VideoFrame>>;
-using TransferredAudioFrameQueueUnderlyingSource =
+using TransferredAudioDataQueueUnderlyingSource =
     TransferredFrameQueueUnderlyingSource<scoped_refptr<media::AudioBuffer>>;
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/cookie_store/cookie_store.cc b/third_party/blink/renderer/modules/cookie_store/cookie_store.cc
index 5639449..adf4de2 100644
--- a/third_party/blink/renderer/modules/cookie_store/cookie_store.cc
+++ b/third_party/blink/renderer/modules/cookie_store/cookie_store.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "base/containers/contains.h"
 #include "base/optional.h"
 #include "net/cookies/canonical_cookie.h"
 #include "services/network/public/cpp/is_potentially_trustworthy.h"
diff --git a/third_party/blink/renderer/modules/manifest/manifest_parser.cc b/third_party/blink/renderer/modules/manifest/manifest_parser.cc
index e64c347..3148efb 100644
--- a/third_party/blink/renderer/modules/manifest/manifest_parser.cc
+++ b/third_party/blink/renderer/modules/manifest/manifest_parser.cc
@@ -138,6 +138,7 @@
   manifest_->file_handlers = ParseFileHandlers(root_object.get());
   manifest_->protocol_handlers = ParseProtocolHandlers(root_object.get());
   manifest_->url_handlers = ParseUrlHandlers(root_object.get());
+  manifest_->note_taking = ParseNoteTaking(root_object.get());
   manifest_->related_applications = ParseRelatedApplications(root_object.get());
   manifest_->prefer_related_applications =
       ParsePreferRelatedApplications(root_object.get());
@@ -1199,6 +1200,40 @@
   return std::move(url_handler);
 }
 
+KURL ManifestParser::ParseNoteTakingNewNoteUrl(const JSONObject* note_taking) {
+  if (!note_taking->Get("new_note_url")) {
+    return KURL();
+  }
+  KURL new_note_url = ParseURL(note_taking, "new_note_url", manifest_url_,
+                               ParseURLRestrictions::kWithinScope);
+  if (!new_note_url.IsValid()) {
+    // Error already reported by ParseURL.
+    return KURL();
+  }
+
+  return new_note_url;
+}
+
+mojom::blink::ManifestNoteTakingPtr ManifestParser::ParseNoteTaking(
+    const JSONObject* manifest) {
+  if (!base::FeatureList::IsEnabled(blink::features::kWebAppNoteTaking)) {
+    return nullptr;
+  }
+  if (!manifest->Get("note_taking")) {
+    return nullptr;
+  }
+
+  const JSONObject* note_taking_object = manifest->GetJSONObject("note_taking");
+  if (!note_taking_object) {
+    AddErrorInfo("property 'note_taking' ignored, type object expected.");
+    return nullptr;
+  }
+  auto note_taking = mojom::blink::ManifestNoteTaking::New();
+  note_taking->new_note_url = ParseNoteTakingNewNoteUrl(note_taking_object);
+
+  return note_taking;
+}
+
 String ManifestParser::ParseRelatedApplicationPlatform(
     const JSONObject* application) {
   base::Optional<String> platform = ParseString(application, "platform", Trim);
diff --git a/third_party/blink/renderer/modules/manifest/manifest_parser.h b/third_party/blink/renderer/modules/manifest/manifest_parser.h
index e088ea7e..93d4bff4 100644
--- a/third_party/blink/renderer/modules/manifest/manifest_parser.h
+++ b/third_party/blink/renderer/modules/manifest/manifest_parser.h
@@ -337,6 +337,19 @@
   base::Optional<mojom::blink::ManifestProtocolHandlerPtr> ParseProtocolHandler(
       const JSONObject* protocol_dictionary);
 
+  // Parses the 'new_note_url' field of the 'note_taking' field of a Manifest,
+  // as defined in:
+  // https://wicg.github.io/manifest-incubations/#dfn-new_note_url
+  // Returns the parsed KURL if any, or an empty KURL if parsing failed.
+  KURL ParseNoteTakingNewNoteUrl(const JSONObject* note_taking);
+
+  // Parses the 'note_taking' field of a Manifest, as defined in:
+  // https://wicg.github.io/manifest-incubations/index.html#dfn-note_taking
+  // Returns a parsed ManifestNoteTakingPtr, or nullptr if not present or
+  // parsing failed.
+  mojom::blink::ManifestNoteTakingPtr ParseNoteTaking(
+      const JSONObject* manifest);
+
   // Parses the 'platform' field of a related application, as defined in:
   // https://w3c.github.io/manifest/#dfn-steps-for-processing-the-platform-member-of-an-application
   // Returns the parsed string if any, a null string if the parsing failed.
diff --git a/third_party/blink/renderer/modules/manifest/manifest_parser_unittest.cc b/third_party/blink/renderer/modules/manifest/manifest_parser_unittest.cc
index 9979b40..192393d 100644
--- a/third_party/blink/renderer/modules/manifest/manifest_parser_unittest.cc
+++ b/third_party/blink/renderer/modules/manifest/manifest_parser_unittest.cc
@@ -13,9 +13,9 @@
 #include "base/test/scoped_feature_list.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/features.h"
-#include "third_party/blink/public/platform/web_security_origin.h"
 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 
 namespace blink {
 
@@ -2783,6 +2783,121 @@
   }
 }
 
+TEST_F(ManifestParserTest, NoteTakingParseRulesWithFeatureDisabled) {
+  // With feature disabled, note taking field should never be parsed.
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndDisableFeature(blink::features::kWebAppNoteTaking);
+
+  KURL manifest_url = KURL("https://foo.com/manifest.json");
+  KURL document_url = KURL("https://foo.com/index.html");
+
+  {
+    // Manifest does not contain a 'note_taking' field.
+    auto& manifest = ParseManifest("{ }");
+    ASSERT_EQ(0u, GetErrorCount());
+    EXPECT_TRUE(manifest->note_taking.is_null());
+  }
+
+  {
+    // A valid note_taking entry.
+    auto& manifest = ParseManifestWithURLs(
+        R"({
+          "note_taking": {
+            "new_note_url": "https://foo.com"
+          }
+        })",
+        manifest_url, document_url);
+    ASSERT_EQ(0u, GetErrorCount());
+    EXPECT_TRUE(manifest->note_taking.is_null());
+  }
+}
+
+TEST_F(ManifestParserTest, NoteTakingParseRules) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(blink::features::kWebAppNoteTaking);
+
+  KURL manifest_url = KURL("https://foo.com/manifest.json");
+  KURL document_url = KURL("https://foo.com/index.html");
+
+  {
+    // Manifest does not contain a 'note_taking' field.
+    auto& manifest = ParseManifest("{ }");
+    ASSERT_EQ(0u, GetErrorCount());
+    EXPECT_TRUE(manifest->note_taking.is_null());
+  }
+
+  {
+    // 'note_taking' is not an object.
+    auto& manifest = ParseManifest(R"( { "note_taking": [ ] } )");
+    EXPECT_EQ(1u, GetErrorCount());
+    EXPECT_EQ("property 'note_taking' ignored, type object expected.",
+              errors()[0]);
+    EXPECT_TRUE(manifest->note_taking.is_null());
+  }
+
+  {
+    // Contains 'note_taking' field but no new_note_url entry.
+    auto& manifest = ParseManifest(R"( { "note_taking": { } } )");
+    ASSERT_EQ(0u, GetErrorCount());
+    ASSERT_FALSE(manifest->note_taking.is_null());
+    EXPECT_TRUE(manifest->note_taking->new_note_url.IsEmpty());
+  }
+
+  {
+    // 'new_note_url' entries must be valid URLs.
+    auto& manifest =
+        ParseManifest(R"({ "note_taking": { "new_note_url": {} } } )");
+    ASSERT_EQ(1u, GetErrorCount());
+    EXPECT_EQ("property 'new_note_url' ignored, type string expected.",
+              errors()[0]);
+    ASSERT_FALSE(manifest->note_taking.is_null());
+    EXPECT_TRUE(manifest->note_taking->new_note_url.IsEmpty());
+  }
+
+  {
+    // 'new_note_url' entries must be within scope.
+    auto& manifest = ParseManifest(
+        R"({ "note_taking": { "new_note_url": "https://bar.com" } } )");
+    ASSERT_EQ(1u, GetErrorCount());
+    EXPECT_EQ(
+        "property 'new_note_url' ignored, should be within scope of the "
+        "manifest.",
+        errors()[0]);
+    ASSERT_FALSE(manifest->note_taking.is_null());
+    EXPECT_TRUE(manifest->note_taking->new_note_url.IsEmpty());
+  }
+
+  {
+    // A valid note_taking new_note_url entry.
+    auto& manifest = ParseManifestWithURLs(
+        R"({
+          "note_taking": {
+            "new_note_url": "https://foo.com"
+          }
+        })",
+        manifest_url, document_url);
+    ASSERT_EQ(0u, GetErrorCount());
+    ASSERT_FALSE(manifest->note_taking.is_null());
+    EXPECT_EQ("https://foo.com/",
+              manifest->note_taking->new_note_url.GetString());
+  }
+
+  {
+    // A valid note_taking new_note_url entry, parsed relative to manifest URL.
+    auto& manifest = ParseManifestWithURLs(
+        R"({
+          "note_taking": {
+            "new_note_url": "new_note"
+          }
+        })",
+        manifest_url, document_url);
+    ASSERT_EQ(0u, GetErrorCount());
+    ASSERT_FALSE(manifest->note_taking.is_null());
+    EXPECT_EQ("https://foo.com/new_note",
+              manifest->note_taking->new_note_url.GetString());
+  }
+}
+
 TEST_F(ManifestParserTest, ShareTargetParseRules) {
   // Contains share_target field but no keys.
   {
diff --git a/third_party/blink/renderer/modules/manifest/manifest_type_converters.cc b/third_party/blink/renderer/modules/manifest/manifest_type_converters.cc
index 02fcc7e..5cfd693 100644
--- a/third_party/blink/renderer/modules/manifest/manifest_type_converters.cc
+++ b/third_party/blink/renderer/modules/manifest/manifest_type_converters.cc
@@ -59,6 +59,8 @@
         url_handler.To<blink::Manifest::UrlHandler>());
   }
 
+  output.note_taking = input->note_taking.To<blink::Manifest::NoteTaking>();
+
   for (auto& related_application : input->related_applications) {
     output.related_applications.push_back(
         related_application.To<blink::Manifest::RelatedApplication>());
@@ -236,6 +238,20 @@
   return output;
 }
 
+blink::Manifest::NoteTaking
+TypeConverter<blink::Manifest::NoteTaking,
+              blink::mojom::blink::ManifestNoteTakingPtr>::
+    Convert(const blink::mojom::blink::ManifestNoteTakingPtr& input) {
+  blink::Manifest::NoteTaking output;
+  if (input.is_null())
+    return output;
+
+  if (!input->new_note_url.IsEmpty())
+    output.new_note_url = input->new_note_url;
+
+  return output;
+}
+
 blink::Manifest::RelatedApplication
 TypeConverter<blink::Manifest::RelatedApplication,
               blink::mojom::blink::ManifestRelatedApplicationPtr>::
diff --git a/third_party/blink/renderer/modules/manifest/manifest_type_converters.h b/third_party/blink/renderer/modules/manifest/manifest_type_converters.h
index d06df38..4cb7cb0 100644
--- a/third_party/blink/renderer/modules/manifest/manifest_type_converters.h
+++ b/third_party/blink/renderer/modules/manifest/manifest_type_converters.h
@@ -81,6 +81,13 @@
 };
 
 template <>
+struct TypeConverter<blink::Manifest::NoteTaking,
+                     blink::mojom::blink::ManifestNoteTakingPtr> {
+  static blink::Manifest::NoteTaking Convert(
+      const blink::mojom::blink::ManifestNoteTakingPtr& input);
+};
+
+template <>
 struct TypeConverter<blink::Manifest::RelatedApplication,
                      blink::mojom::blink::ManifestRelatedApplicationPtr> {
   static blink::Manifest::RelatedApplication Convert(
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.cc
index ba63708..65fbda26 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.cc
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.h"
 
 #include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/platform/user_metrics_action.h"
 #include "third_party/blink/public/strings/grit/blink_strings.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_download_button_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_download_button_element.cc
index 229cc6c..055b623 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_download_button_element.cc
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_download_button_element.cc
@@ -6,6 +6,7 @@
 
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
 #include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/platform/user_metrics_action.h"
 #include "third_party/blink/public/strings/grit/blink_strings.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_fullscreen_button_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_fullscreen_button_element.cc
index efcd592..6d05ccd7 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_fullscreen_button_element.cc
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_fullscreen_button_element.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/modules/media_controls/elements/media_control_fullscreen_button_element.h"
 
 #include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/platform/user_metrics_action.h"
 #include "third_party/blink/public/strings/grit/blink_strings.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_mute_button_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_mute_button_element.cc
index 2ed62bc..131cb6d 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_mute_button_element.cc
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_mute_button_element.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/modules/media_controls/elements/media_control_mute_button_element.h"
 
 #include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/platform/user_metrics_action.h"
 #include "third_party/blink/public/strings/grit/blink_strings.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
 #include "third_party/blink/renderer/core/html/media/html_media_element.h"
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_button_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_button_element.cc
index 3fce3d9..58deb81 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_button_element.cc
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_button_element.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_button_element.h"
 
 #include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/platform/user_metrics_action.h"
 #include "third_party/blink/public/strings/grit/blink_strings.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
 #include "third_party/blink/renderer/core/input_type_names.h"
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element.cc
index 41b3263..02040125 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element.cc
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element.h"
 
 #include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/platform/user_metrics_action.h"
 #include "third_party/blink/public/strings/grit/blink_strings.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
 #include "third_party/blink/renderer/core/dom/shadow_root.h"
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_play_button_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_play_button_element.cc
index 526d64f..4515280b 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_play_button_element.cc
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_play_button_element.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/modules/media_controls/elements/media_control_play_button_element.h"
 
 #include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/platform/user_metrics_action.h"
 #include "third_party/blink/public/strings/grit/blink_strings.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
 #include "third_party/blink/renderer/core/html/media/html_media_element.h"
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.cc
index b67f051..e7302ee 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.cc
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.cc
@@ -6,6 +6,7 @@
 
 #include "third_party/blink/public/common/widget/screen_info.h"
 #include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/platform/user_metrics_action.h"
 #include "third_party/blink/public/strings/grit/blink_strings.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
 #include "third_party/blink/renderer/core/dom/shadow_root.h"
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.cc
index 62ab5e55..2bb07be 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.cc
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.h"
 
 #include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/platform/user_metrics_action.h"
 #include "third_party/blink/renderer/core/dom/dom_token_list.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
 #include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc b/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
index 858a14e9..e0927c62 100644
--- a/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
+++ b/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
@@ -28,6 +28,7 @@
 
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/task_type.h"
+#include "third_party/blink/public/platform/user_metrics_action.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_mutation_observer_init.h"
 #include "third_party/blink/renderer/core/css/css_property_value_set.h"
 #include "third_party/blink/renderer/core/dom/element_traversal.h"
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.cc b/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.cc
index 4863350..d279c2b1 100644
--- a/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.cc
+++ b/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.cc
@@ -7,6 +7,7 @@
 #include "third_party/blink/public/common/widget/screen_info.h"
 #include "third_party/blink/public/mojom/widget/screen_orientation.mojom-blink.h"
 #include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/platform/user_metrics_action.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
diff --git a/third_party/blink/renderer/modules/mediastream/DEPS b/third_party/blink/renderer/modules/mediastream/DEPS
index f3eb7f7..540bf87 100644
--- a/third_party/blink/renderer/modules/mediastream/DEPS
+++ b/third_party/blink/renderer/modules/mediastream/DEPS
@@ -46,9 +46,6 @@
     "+third_party/blink/renderer/modules/mediastream",
     "+third_party/blink/renderer/modules/modules_export.h",
     "+third_party/blink/renderer/modules/peerconnection",
-    "+third_party/blink/renderer/modules/webcodecs/audio_frame.h",
-    "+third_party/blink/renderer/modules/webcodecs/audio_frame_serialization_data.h",
-    "+third_party/blink/renderer/modules/webcodecs/video_frame.h",
     "+third_party/blink/renderer/modules/webrtc",
     "+ui/gfx/geometry/size.h",
 ]
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_sets.h b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_sets.h
index 0a397cb..01bb5b06 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_sets.h
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_sets.h
@@ -11,6 +11,7 @@
 #include <utility>
 
 #include "base/check_op.h"
+#include "base/containers/contains.h"
 #include "base/gtest_prod_util.h"
 #include "base/optional.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.cc b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.cc
index 87794eec..4e9f45a 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.cc
@@ -10,6 +10,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/containers/contains.h"
 #include "media/base/limits.h"
 #include "media/mojo/mojom/display_media_information.mojom-blink.h"
 #include "third_party/blink/public/platform/web_string.h"
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_source.cc b/third_party/blink/renderer/modules/mediastream/media_stream_video_source.cc
index 9c4561c..84b97d2 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_source.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_source.cc
@@ -10,6 +10,7 @@
 #include <utility>
 
 #include "base/callback_helpers.h"
+#include "base/containers/contains.h"
 #include "base/feature_list.h"
 #include "base/logging.h"
 #include "base/macros.h"
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc b/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc
index 109812b..4f1f1e2 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/containers/contains.h"
 #include "base/location.h"
 #include "base/macros.h"
 #include "base/single_thread_task_runner.h"
diff --git a/third_party/blink/renderer/modules/screen_enumeration/screens.cc b/third_party/blink/renderer/modules/screen_enumeration/screens.cc
index 50852f0..178c642 100644
--- a/third_party/blink/renderer/modules/screen_enumeration/screens.cc
+++ b/third_party/blink/renderer/modules/screen_enumeration/screens.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/modules/screen_enumeration/screens.h"
 
+#include "base/containers/contains.h"
 #include "third_party/blink/public/common/widget/screen_info.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
diff --git a/third_party/blink/renderer/modules/webcodecs/BUILD.gn b/third_party/blink/renderer/modules/webcodecs/BUILD.gn
index 6e6acaa8..6e6d0b0 100644
--- a/third_party/blink/renderer/modules/webcodecs/BUILD.gn
+++ b/third_party/blink/renderer/modules/webcodecs/BUILD.gn
@@ -9,16 +9,16 @@
 
 blink_modules_sources("webcodecs") {
   sources = [
+    "audio_data.cc",
+    "audio_data.h",
+    "audio_data_attachment.cc",
+    "audio_data_attachment.h",
     "audio_decoder.cc",
     "audio_decoder.h",
     "audio_decoder_broker.cc",
     "audio_decoder_broker.h",
     "audio_encoder.cc",
     "audio_encoder.h",
-    "audio_frame.cc",
-    "audio_frame.h",
-    "audio_frame_attachment.cc",
-    "audio_frame_attachment.h",
     "codec_config_eval.h",
     "codec_logger.cc",
     "codec_logger.h",
@@ -84,8 +84,8 @@
 source_set("unit_tests") {
   testonly = true
   sources = [
+    "audio_data_test.cc",
     "audio_decoder_broker_test.cc",
-    "audio_frame_test.cc",
     "decoder_selector_test.cc",
     "decoder_template_test.cc",
     "encoded_video_chunk_test.cc",
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_frame.cc b/third_party/blink/renderer/modules/webcodecs/audio_data.cc
similarity index 76%
rename from third_party/blink/renderer/modules/webcodecs/audio_frame.cc
rename to third_party/blink/renderer/modules/webcodecs/audio_data.cc
index 45398df0..21e9675 100644
--- a/third_party/blink/renderer/modules/webcodecs/audio_frame.cc
+++ b/third_party/blink/renderer/modules/webcodecs/audio_data.cc
@@ -2,22 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/modules/webcodecs/audio_frame.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_data.h"
 
 #include "media/base/audio_buffer.h"
 #include "media/base/audio_bus.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_frame_init.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_data_init.h"
 #include "third_party/blink/renderer/modules/webaudio/audio_buffer.h"
 
 namespace blink {
 
 // static
-AudioFrame* AudioFrame::Create(AudioFrameInit* init,
-                               ExceptionState& exception_state) {
-  return MakeGarbageCollected<AudioFrame>(init);
+AudioData* AudioData::Create(AudioDataInit* init,
+                             ExceptionState& exception_state) {
+  return MakeGarbageCollected<AudioData>(init);
 }
 
-AudioFrame::AudioFrame(AudioFrameInit* init)
+AudioData::AudioData(AudioDataInit* init)
     : timestamp_(init->timestamp()), buffer_(init->buffer()) {
   std::vector<const uint8_t*> wrapped_channels(buffer_->numberOfChannels());
   for (unsigned ch = 0; ch < buffer_->numberOfChannels(); ++ch) {
@@ -32,30 +32,30 @@
       wrapped_channels.data(), base::TimeDelta::FromMicroseconds(timestamp_));
 }
 
-AudioFrame::AudioFrame(scoped_refptr<media::AudioBuffer> buffer)
+AudioData::AudioData(scoped_refptr<media::AudioBuffer> buffer)
     : data_(std::move(buffer)),
       timestamp_(data_->timestamp().InMicroseconds()) {}
 
-AudioFrame* AudioFrame::clone(ExceptionState& exception_state) {
+AudioData* AudioData::clone(ExceptionState& exception_state) {
   if (!data_) {
     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
-                                      "Cannot clone closed AudioFrame.");
+                                      "Cannot clone closed AudioData.");
     return nullptr;
   }
 
-  return MakeGarbageCollected<AudioFrame>(data_);
+  return MakeGarbageCollected<AudioData>(data_);
 }
 
-void AudioFrame::close() {
+void AudioData::close() {
   data_.reset();
   buffer_.Clear();
 }
 
-int64_t AudioFrame::timestamp() const {
+int64_t AudioData::timestamp() const {
   return timestamp_;
 }
 
-void AudioFrame::CopyDataToBuffer() {
+void AudioData::CopyDataToBuffer() {
   DCHECK(!buffer_);
 
   // |this| might have been closed already.
@@ -77,14 +77,14 @@
   data_->ReadAllFrames(wrapped_channels);
 }
 
-AudioBuffer* AudioFrame::buffer() {
+AudioBuffer* AudioData::buffer() {
   if (!buffer_)
     CopyDataToBuffer();
 
   return buffer_;
 }
 
-void AudioFrame::Trace(Visitor* visitor) const {
+void AudioData::Trace(Visitor* visitor) const {
   visitor->Trace(buffer_);
   ScriptWrappable::Trace(visitor);
 }
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_frame.h b/third_party/blink/renderer/modules/webcodecs/audio_data.h
similarity index 67%
rename from third_party/blink/renderer/modules/webcodecs/audio_frame.h
rename to third_party/blink/renderer/modules/webcodecs/audio_data.h
index 0164fbf3..007ffef4 100644
--- a/third_party/blink/renderer/modules/webcodecs/audio_frame.h
+++ b/third_party/blink/renderer/modules/webcodecs/audio_data.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 THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_AUDIO_FRAME_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_AUDIO_FRAME_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_AUDIO_DATA_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_AUDIO_DATA_H_
 
 #include "media/base/audio_buffer.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
@@ -13,24 +13,24 @@
 namespace blink {
 
 class ExceptionState;
-class AudioFrameInit;
+class AudioDataInit;
 
-class MODULES_EXPORT AudioFrame final : public ScriptWrappable {
+class MODULES_EXPORT AudioData final : public ScriptWrappable {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static AudioFrame* Create(AudioFrameInit*, ExceptionState&);
+  static AudioData* Create(AudioDataInit*, ExceptionState&);
 
   // Internal constructor for creating from media::AudioDecoder output.
-  explicit AudioFrame(scoped_refptr<media::AudioBuffer>);
+  explicit AudioData(scoped_refptr<media::AudioBuffer>);
 
-  // audio_frame.idl implementation.
-  explicit AudioFrame(AudioFrameInit*);
+  // audio_data.idl implementation.
+  explicit AudioData(AudioDataInit*);
 
   // Creates a clone of |this|, taking on a new reference on |data_|. The cloned
   // frame will not be closed when |this| is, and its lifetime should be
   // independently managed.
-  AudioFrame* clone(ExceptionState&);
+  AudioData* clone(ExceptionState&);
 
   void close();
   int64_t timestamp() const;
@@ -52,4 +52,4 @@
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_AUDIO_FRAME_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_AUDIO_DATA_H_
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_frame.idl b/third_party/blink/renderer/modules/webcodecs/audio_data.idl
similarity index 67%
rename from third_party/blink/renderer/modules/webcodecs/audio_frame.idl
rename to third_party/blink/renderer/modules/webcodecs/audio_data.idl
index 397bf7a..61e8fbc 100644
--- a/third_party/blink/renderer/modules/webcodecs/audio_frame.idl
+++ b/third_party/blink/renderer/modules/webcodecs/audio_data.idl
@@ -6,11 +6,11 @@
 [
     Exposed=(Window,DedicatedWorker),
     RuntimeEnabled=WebCodecs
-] interface AudioFrame {
-  [RaisesException] constructor(AudioFrameInit init);
+] interface AudioData {
+  [RaisesException] constructor(AudioDataInit init);
 
-  // Creates a AudioFrame, which needs to be independently closed.
-  [RaisesException] AudioFrame clone();
+  // Creates identical AudioData, which needs to be independently closed.
+  [RaisesException] AudioData clone();
 
   void close();
 
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_data_attachment.cc b/third_party/blink/renderer/modules/webcodecs/audio_data_attachment.cc
new file mode 100644
index 0000000..e86df66
--- /dev/null
+++ b/third_party/blink/renderer/modules/webcodecs/audio_data_attachment.cc
@@ -0,0 +1,11 @@
+// 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 "third_party/blink/renderer/modules/webcodecs/audio_data_attachment.h"
+
+namespace blink {
+
+const void* const AudioDataAttachment::kAttachmentKey = nullptr;
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_frame_attachment.h b/third_party/blink/renderer/modules/webcodecs/audio_data_attachment.h
similarity index 70%
rename from third_party/blink/renderer/modules/webcodecs/audio_frame_attachment.h
rename to third_party/blink/renderer/modules/webcodecs/audio_data_attachment.h
index 7774631..e5f0160d 100644
--- a/third_party/blink/renderer/modules/webcodecs/audio_frame_attachment.h
+++ b/third_party/blink/renderer/modules/webcodecs/audio_data_attachment.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 THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_AUDIO_FRAME_ATTACHMENT_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_AUDIO_FRAME_ATTACHMENT_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_AUDIO_DATA_ATTACHMENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_AUDIO_DATA_ATTACHMENT_H_
 
 #include "base/optional.h"
 #include "media/base/audio_buffer.h"
@@ -12,15 +12,15 @@
 
 namespace blink {
 
-// Used to serialize audio frames.
-class MODULES_EXPORT AudioFrameAttachment
+// Used to serialize AudioData.
+class MODULES_EXPORT AudioDataAttachment
     : public SerializedScriptValue::Attachment {
  public:
   using AudioBufferVector = Vector<scoped_refptr<media::AudioBuffer>>;
 
   static const void* const kAttachmentKey;
-  AudioFrameAttachment() = default;
-  ~AudioFrameAttachment() override = default;
+  AudioDataAttachment() = default;
+  ~AudioDataAttachment() override = default;
 
   bool IsLockedToAgentCluster() const override {
     return !audio_buffers_.IsEmpty();
@@ -38,4 +38,4 @@
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_AUDIO_FRAME_ATTACHMENT_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_AUDIO_DATA_ATTACHMENT_H_
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_frame_init.idl b/third_party/blink/renderer/modules/webcodecs/audio_data_init.idl
similarity index 90%
rename from third_party/blink/renderer/modules/webcodecs/audio_frame_init.idl
rename to third_party/blink/renderer/modules/webcodecs/audio_data_init.idl
index 31328a9..0ec1f52 100644
--- a/third_party/blink/renderer/modules/webcodecs/audio_frame_init.idl
+++ b/third_party/blink/renderer/modules/webcodecs/audio_data_init.idl
@@ -4,7 +4,7 @@
 
 // https://github.com/WICG/web-codecs
 
-dictionary AudioFrameInit {
+dictionary AudioDataInit {
   required long long timestamp;  // microseconds
   required AudioBuffer buffer;
 };
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_frame_output_callback.idl b/third_party/blink/renderer/modules/webcodecs/audio_data_output_callback.idl
similarity index 79%
rename from third_party/blink/renderer/modules/webcodecs/audio_frame_output_callback.idl
rename to third_party/blink/renderer/modules/webcodecs/audio_data_output_callback.idl
index 145fbf8c..e7f2e21 100644
--- a/third_party/blink/renderer/modules/webcodecs/audio_frame_output_callback.idl
+++ b/third_party/blink/renderer/modules/webcodecs/audio_data_output_callback.idl
@@ -5,4 +5,4 @@
 // https://github.com/WICG/web-codecs
 
 [RuntimeEnabled=WebCodecs]
-callback AudioFrameOutputCallback = void(AudioFrame output);
+callback AudioDataOutputCallback = void(AudioData output);
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_frame_test.cc b/third_party/blink/renderer/modules/webcodecs/audio_data_test.cc
similarity index 81%
rename from third_party/blink/renderer/modules/webcodecs/audio_frame_test.cc
rename to third_party/blink/renderer/modules/webcodecs/audio_data_test.cc
index e941d4a..3b35bf5d 100644
--- a/third_party/blink/renderer/modules/webcodecs/audio_frame_test.cc
+++ b/third_party/blink/renderer/modules/webcodecs/audio_data_test.cc
@@ -2,11 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/modules/webcodecs/audio_frame.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_data.h"
+
 #include "media/base/test_helpers.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_frame_init.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_data_init.h"
 #include "third_party/blink/renderer/modules/webaudio/audio_buffer.h"
 #include "third_party/blink/renderer/platform/heap/thread_state.h"
 #include "ui/gfx/geometry/rect.h"
@@ -22,7 +23,7 @@
 constexpr int kSampleRate = 8000;
 }  // namespace
 
-class AudioFrameTest : public testing::Test {
+class AudioDataTest : public testing::Test {
  protected:
   AudioBuffer* CreateDefaultAudioBuffer() {
     auto* audio_buffer =
@@ -36,15 +37,15 @@
     return audio_buffer;
   }
 
-  AudioFrameInit* CreateDefaultAudioFrameInit(AudioBuffer* buffer) {
-    auto* audio_frame_init = AudioFrameInit::Create();
-    audio_frame_init->setBuffer(buffer);
-    audio_frame_init->setTimestamp(kTimestampInMicroSeconds);
-    return audio_frame_init;
+  AudioDataInit* CreateDefaultAudioDataInit(AudioBuffer* buffer) {
+    auto* audio_data_init = AudioDataInit::Create();
+    audio_data_init->setBuffer(buffer);
+    audio_data_init->setTimestamp(kTimestampInMicroSeconds);
+    return audio_data_init;
   }
 };
 
-TEST_F(AudioFrameTest, ConstructFromMediaBuffer) {
+TEST_F(AudioDataTest, ConstructFromMediaBuffer) {
   const media::ChannelLayout channel_layout =
       media::ChannelLayout::CHANNEL_LAYOUT_STEREO;
   const int channels = ChannelLayoutToChannelCount(channel_layout);
@@ -57,7 +58,7 @@
                                       channel_layout, channels, kSampleRate,
                                       kStart, kIncrement, kFrames, timestamp);
 
-  auto* frame = MakeGarbageCollected<AudioFrame>(media_buffer);
+  auto* frame = MakeGarbageCollected<AudioData>(media_buffer);
 
   EXPECT_EQ(frame->timestamp(), kTimestampInMicroSeconds);
 
@@ -87,12 +88,12 @@
   EXPECT_EQ(frame->data(), media_buffer);
 }
 
-TEST_F(AudioFrameTest, ConstructFromAudioFrameInit) {
+TEST_F(AudioDataTest, ConstructFromAudioDataInit) {
   auto* audio_buffer = CreateDefaultAudioBuffer();
 
-  auto* audio_frame_init = CreateDefaultAudioFrameInit(audio_buffer);
+  auto* audio_data_init = CreateDefaultAudioDataInit(audio_buffer);
 
-  auto* frame = MakeGarbageCollected<AudioFrame>(audio_frame_init);
+  auto* frame = MakeGarbageCollected<AudioData>(audio_data_init);
 
   EXPECT_EQ(frame->timestamp(), kTimestampInMicroSeconds);
   EXPECT_EQ(frame->buffer(), audio_buffer);
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_decoder.cc b/third_party/blink/renderer/modules/webcodecs/audio_decoder.cc
index c228be5..65eca413 100644
--- a/third_party/blink/renderer/modules/webcodecs/audio_decoder.cc
+++ b/third_party/blink/renderer/modules/webcodecs/audio_decoder.cc
@@ -20,8 +20,8 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_support.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk.h"
 #include "third_party/blink/renderer/modules/webaudio/base_audio_context.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_data.h"
 #include "third_party/blink/renderer/modules/webcodecs/audio_decoder_broker.h"
-#include "third_party/blink/renderer/modules/webcodecs/audio_frame.h"
 #include "third_party/blink/renderer/modules/webcodecs/codec_config_eval.h"
 #include "third_party/blink/renderer/platform/audio/audio_utilities.h"
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_decoder.h b/third_party/blink/renderer/modules/webcodecs/audio_decoder.h
index 420e5cd1e..2eac364 100644
--- a/third_party/blink/renderer/modules/webcodecs/audio_decoder.h
+++ b/third_party/blink/renderer/modules/webcodecs/audio_decoder.h
@@ -32,21 +32,21 @@
 
 namespace blink {
 
+class AudioData;
 class AudioDecoderConfig;
-class AudioFrame;
 class EncodedAudioChunk;
 class ExceptionState;
 class AudioDecoderInit;
 class ScriptPromise;
-class V8AudioFrameOutputCallback;
+class V8AudioDataOutputCallback;
 
 class MODULES_EXPORT AudioDecoderTraits {
  public:
   using InitType = AudioDecoderInit;
-  using OutputType = AudioFrame;
+  using OutputType = AudioData;
   using MediaOutputType = media::AudioBuffer;
   using MediaDecoderType = media::AudioDecoder;
-  using OutputCallbackType = V8AudioFrameOutputCallback;
+  using OutputCallbackType = V8AudioDataOutputCallback;
   using ConfigType = AudioDecoderConfig;
   using MediaConfigType = media::AudioDecoderConfig;
   using InputType = EncodedAudioChunk;
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_decoder_fuzzer.cc b/third_party/blink/renderer/modules/webcodecs/audio_decoder_fuzzer.cc
index bf1d96d..2dd60e57 100644
--- a/third_party/blink/renderer/modules/webcodecs/audio_decoder_fuzzer.cc
+++ b/third_party/blink/renderer/modules/webcodecs/audio_decoder_fuzzer.cc
@@ -5,9 +5,9 @@
 #include "base/run_loop.h"
 #include "testing/libfuzzer/proto/lpm_interface.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_data_output_callback.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_config.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_init.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_frame_output_callback.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_webcodecs_error_callback.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
@@ -59,8 +59,8 @@
         V8WebCodecsErrorCallback::Create(error_function->Bind());
     Persistent<FakeFunction> output_function =
         FakeFunction::Create(script_state, "output");
-    Persistent<V8AudioFrameOutputCallback> output_callback =
-        V8AudioFrameOutputCallback::Create(output_function->Bind());
+    Persistent<V8AudioDataOutputCallback> output_callback =
+        V8AudioDataOutputCallback::Create(output_function->Bind());
 
     Persistent<AudioDecoderInit> audio_decoder_init =
         MakeGarbageCollected<AudioDecoderInit>();
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_decoder_init.idl b/third_party/blink/renderer/modules/webcodecs/audio_decoder_init.idl
index 4a55d99..18a1d59 100644
--- a/third_party/blink/renderer/modules/webcodecs/audio_decoder_init.idl
+++ b/third_party/blink/renderer/modules/webcodecs/audio_decoder_init.idl
@@ -5,6 +5,6 @@
 // https://github.com/WICG/web-codecs
 
 dictionary AudioDecoderInit {
-  required AudioFrameOutputCallback output;
+  required AudioDataOutputCallback output;
   required WebCodecsErrorCallback error;
 };
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_encoder.cc b/third_party/blink/renderer/modules/webcodecs/audio_encoder.cc
index a1306f30..49d0ea5 100644
--- a/third_party/blink/renderer/modules/webcodecs/audio_encoder.cc
+++ b/third_party/blink/renderer/modules/webcodecs/audio_encoder.cc
@@ -14,10 +14,10 @@
 #include "media/base/mime_util.h"
 #include "media/base/offloading_audio_encoder.h"
 #include "third_party/blink/public/mojom/web_feature/web_feature.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_data_init.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_config.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_encoder_config.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_encoder_support.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_frame_init.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk_metadata.h"
 #include "third_party/blink/renderer/modules/webaudio/audio_buffer.h"
 #include "third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk.h"
@@ -203,11 +203,11 @@
   DCHECK_EQ(request->type, Request::Type::kEncode);
   DCHECK_GT(requested_encodes_, 0);
 
-  auto* frame = request->frame.Release();
+  auto* audio_data = request->input.Release();
 
-  auto data = frame->data();
+  auto data = audio_data->data();
 
-  // The frame shouldn't be closed at this point.
+  // The data shouldn't be closed at this point.
   DCHECK(data);
 
   auto done_callback = [](AudioEncoder* self, uint32_t reset_count,
@@ -230,7 +230,7 @@
 
     HandleError(logger_->MakeException(
         "Input audio buffer is incompatible with codec parameters", error));
-    frame->close();
+    audio_data->close();
     return;
   }
 
@@ -244,7 +244,7 @@
       ConvertToBaseOnceCallback(CrossThreadBindOnce(
           done_callback, WrapCrossThreadWeakPersistent(this), reset_count_)));
 
-  frame->close();
+  audio_data->close();
 }
 
 void AudioEncoder::ProcessReconfigure(Request* request) {
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_encoder.h b/third_party/blink/renderer/modules/webcodecs/audio_encoder.h
index c7e10c6..e711ce61 100644
--- a/third_party/blink/renderer/modules/webcodecs/audio_encoder.h
+++ b/third_party/blink/renderer/modules/webcodecs/audio_encoder.h
@@ -13,7 +13,7 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk_output_callback.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_webcodecs_error_callback.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/modules/webcodecs/audio_frame.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_data.h"
 #include "third_party/blink/renderer/modules/webcodecs/encoder_base.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 
@@ -41,7 +41,7 @@
   using Init = AudioEncoderInit;
   using Config = AudioEncoderConfig;
   using InternalConfig = ParsedConfig;
-  using Frame = AudioFrame;
+  using Input = AudioData;
   using EncodeOptions = AudioEncoderEncodeOptions;
   using OutputChunk = EncodedAudioChunk;
   using OutputCallback = V8EncodedAudioChunkOutputCallback;
@@ -63,8 +63,8 @@
   AudioEncoder(ScriptState*, const AudioEncoderInit*, ExceptionState&);
   ~AudioEncoder() override;
 
-  void encode(AudioFrame* frame, ExceptionState& exception_state) {
-    return Base::encode(frame, nullptr, exception_state);
+  void encode(AudioData* data, ExceptionState& exception_state) {
+    return Base::encode(data, nullptr, exception_state);
   }
 
   static ScriptPromise isConfigSupported(ScriptState*,
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_encoder.idl b/third_party/blink/renderer/modules/webcodecs/audio_encoder.idl
index b4dc3bc..b5b7846 100644
--- a/third_party/blink/renderer/modules/webcodecs/audio_encoder.idl
+++ b/third_party/blink/renderer/modules/webcodecs/audio_encoder.idl
@@ -17,26 +17,24 @@
     readonly attribute long encodeQueueSize;
 
     // Enqueues a control message to configure the audio encoder for encoding
-    // audio frames as described by config.
+    // audio data as described by config.
     [RaisesException]
     void configure(AudioEncoderConfig config);
 
-    // Enqueues a request to encode a frame.
+    // Enqueues a request to encode data.
     // Results of the encoding (EncodedAudioChunk) are returned via
     // the output callback provided in configure().
     [RaisesException]
-    void encode(AudioFrame frame);
+    void encode(AudioData data);
 
-
-    // Enqueues a request to produce outputs for all already encoded frames.
-    // Resolved after emitting outputs for all previously encoded frames.
+    // Enqueues a request to produce outputs for all already encoded data.
+    // Resolved after emitting outputs for all previously encoded data.
     [RaisesException]
     Promise<void> flush();
 
     // Discard all pending work and current encoder configuration.
     //
     // Output for earlier encoding requests will not be emitted.
-    // The next encoded frame will be a keyframe.
     // Requires configure() to be call to set configuration once again.
     [RaisesException]
     void reset();
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_encoder_fuzzer.cc b/third_party/blink/renderer/modules/webcodecs/audio_encoder_fuzzer.cc
index 075344a..9835d2d 100644
--- a/third_party/blink/renderer/modules/webcodecs/audio_encoder_fuzzer.cc
+++ b/third_party/blink/renderer/modules/webcodecs/audio_encoder_fuzzer.cc
@@ -92,12 +92,12 @@
             break;
           }
           case wc_fuzzer::AudioEncoderApiInvocation::kEncode: {
-            AudioFrame* frame =
-                MakeAudioFrame(script_state, invocation.encode().frame());
-            if (!frame)
+            AudioData* data =
+                MakeAudioData(script_state, invocation.encode().data());
+            if (!data)
               return;
 
-            audio_encoder->encode(frame, IGNORE_EXCEPTION_FOR_TESTING);
+            audio_encoder->encode(data, IGNORE_EXCEPTION_FOR_TESTING);
             break;
           }
           case wc_fuzzer::AudioEncoderApiInvocation::kFlush: {
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_frame_attachment.cc b/third_party/blink/renderer/modules/webcodecs/audio_frame_attachment.cc
deleted file mode 100644
index 1b2892a..0000000
--- a/third_party/blink/renderer/modules/webcodecs/audio_frame_attachment.cc
+++ /dev/null
@@ -1,11 +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 "third_party/blink/renderer/modules/webcodecs/audio_frame_attachment.h"
-
-namespace blink {
-
-const void* const AudioFrameAttachment::kAttachmentKey = nullptr;
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/webcodecs/decoder_template.cc b/third_party/blink/renderer/modules/webcodecs/decoder_template.cc
index 0055c5b..d85c7cc 100644
--- a/third_party/blink/renderer/modules/webcodecs/decoder_template.cc
+++ b/third_party/blink/renderer/modules/webcodecs/decoder_template.cc
@@ -16,9 +16,9 @@
 #include "media/video/gpu_video_accelerator_factories.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/task_type.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_data_output_callback.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_config.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_init.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_frame_output_callback.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_config.h"
@@ -26,8 +26,8 @@
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_data.h"
 #include "third_party/blink/renderer/modules/webcodecs/audio_decoder.h"
-#include "third_party/blink/renderer/modules/webcodecs/audio_frame.h"
 #include "third_party/blink/renderer/modules/webcodecs/codec_config_eval.h"
 #include "third_party/blink/renderer/modules/webcodecs/codec_state_helper.h"
 #include "third_party/blink/renderer/modules/webcodecs/video_decoder.h"
diff --git a/third_party/blink/renderer/modules/webcodecs/decoder_template_test.cc b/third_party/blink/renderer/modules/webcodecs/decoder_template_test.cc
index 9282451..0bcf7de 100644
--- a/third_party/blink/renderer/modules/webcodecs/decoder_template_test.cc
+++ b/third_party/blink/renderer/modules/webcodecs/decoder_template_test.cc
@@ -71,7 +71,7 @@
     MockFunction* output_callback,
     MockFunction* error_callback) {
   auto* init = MakeGarbageCollected<AudioDecoderInit>();
-  init->setOutput(V8AudioFrameOutputCallback::Create(output_callback->Bind()));
+  init->setOutput(V8AudioDataOutputCallback::Create(output_callback->Bind()));
   init->setError(V8WebCodecsErrorCallback::Create(error_callback->Bind()));
   return init;
 }
diff --git a/third_party/blink/renderer/modules/webcodecs/encoder_base.cc b/third_party/blink/renderer/modules/webcodecs/encoder_base.cc
index e59efd0..f159c05 100644
--- a/third_party/blink/renderer/modules/webcodecs/encoder_base.cc
+++ b/third_party/blink/renderer/modules/webcodecs/encoder_base.cc
@@ -108,7 +108,7 @@
 }
 
 template <typename Traits>
-void EncoderBase<Traits>::encode(FrameType* frame,
+void EncoderBase<Traits>::encode(InputType* input,
                                  const EncodeOptionsType* opts,
                                  ExceptionState& exception_state) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -121,22 +121,22 @@
 
   DCHECK(active_config_);
 
-  // This will fail if |frame| is already closed.
-  auto* internal_frame = frame->clone(exception_state);
+  // This will fail if |input| is already closed.
+  auto* internal_input = input->clone(exception_state);
 
-  if (!internal_frame) {
-    // Remove exceptions relating to cloning closed frames.
+  if (!internal_input) {
+    // Remove exceptions relating to cloning closed input.
     exception_state.ClearException();
 
     exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
-                                      "Cannot encode closed frame.");
+                                      "Cannot encode closed input.");
     return;
   }
 
   Request* request = MakeGarbageCollected<Request>();
   request->reset_count = reset_count_;
   request->type = Request::Type::kEncode;
-  request->frame = internal_frame;
+  request->input = internal_input;
   request->encodeOpts = opts;
   ++requested_encodes_;
   EnqueueRequest(request);
@@ -195,8 +195,8 @@
     DCHECK(pending_req);
     if (pending_req->resolver)
       pending_req->resolver.Release()->Resolve();
-    if (pending_req->frame)
-      pending_req->frame.Release()->close();
+    if (pending_req->input)
+      pending_req->input.Release()->close();
   }
   stall_request_processing_ = false;
 }
@@ -322,7 +322,7 @@
 
 template <typename Traits>
 void EncoderBase<Traits>::Request::Trace(Visitor* visitor) const {
-  visitor->Trace(frame);
+  visitor->Trace(input);
   visitor->Trace(encodeOpts);
   visitor->Trace(resolver);
 }
diff --git a/third_party/blink/renderer/modules/webcodecs/encoder_base.h b/third_party/blink/renderer/modules/webcodecs/encoder_base.h
index 4877ca2..e8dd404 100644
--- a/third_party/blink/renderer/modules/webcodecs/encoder_base.h
+++ b/third_party/blink/renderer/modules/webcodecs/encoder_base.h
@@ -33,7 +33,7 @@
   using InitType = typename Traits::Init;
   using ConfigType = typename Traits::Config;
   using InternalConfigType = typename Traits::InternalConfig;
-  using FrameType = typename Traits::Frame;
+  using InputType = typename Traits::Input;
   using EncodeOptionsType = typename Traits::EncodeOptions;
   using OutputChunkType = typename Traits::OutputChunk;
   using OutputCallbackType = typename Traits::OutputCallback;
@@ -47,7 +47,7 @@
 
   void configure(const ConfigType*, ExceptionState&);
 
-  void encode(FrameType* frame,
+  void encode(InputType* input,
               const EncodeOptionsType* opts,
               ExceptionState& exception_state);
 
@@ -84,7 +84,7 @@
     Type type;
     // Current value of EncoderBase.reset_count_ when request was created.
     uint32_t reset_count = 0;
-    Member<FrameType> frame;                     // used by kEncode
+    Member<InputType> input;                     // used by kEncode
     Member<const EncodeOptionsType> encodeOpts;  // used by kEncode
     Member<ScriptPromiseResolver> resolver;      // used by kFlush
   };
diff --git a/third_party/blink/renderer/modules/webcodecs/fuzzer_inputs.proto b/third_party/blink/renderer/modules/webcodecs/fuzzer_inputs.proto
index ecc4546..d003a56 100644
--- a/third_party/blink/renderer/modules/webcodecs/fuzzer_inputs.proto
+++ b/third_party/blink/renderer/modules/webcodecs/fuzzer_inputs.proto
@@ -90,7 +90,7 @@
   optional bytes rgb_bitmap = 4;
 }
 
-message AudioFrameInit {
+message AudioDataInit {
   optional uint64 timestamp = 1;
 
   optional uint32 length = 2;
@@ -107,7 +107,7 @@
 }
 
 message EncodeAudio {
-  optional AudioFrameInit frame = 1;
+  optional AudioDataInit data = 1;
 }
 
 message DecodeVideo {
diff --git a/third_party/blink/renderer/modules/webcodecs/fuzzer_utils.cc b/third_party/blink/renderer/modules/webcodecs/fuzzer_utils.cc
index b402c01..a17aa1c 100644
--- a/third_party/blink/renderer/modules/webcodecs/fuzzer_utils.cc
+++ b/third_party/blink/renderer/modules/webcodecs/fuzzer_utils.cc
@@ -10,8 +10,8 @@
 #include "third_party/blink/renderer/bindings/core/v8/script_function.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_image_bitmap_options.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_data_init.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_config.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_frame_init.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk_init.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk_init.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_config.h"
@@ -195,8 +195,8 @@
                             IGNORE_EXCEPTION_FOR_TESTING);
 }
 
-AudioFrame* MakeAudioFrame(ScriptState* script_state,
-                           const wc_fuzzer::AudioFrameInit& proto) {
+AudioData* MakeAudioData(ScriptState* script_state,
+                         const wc_fuzzer::AudioDataInit& proto) {
   if (proto.channels().size() > media::limits::kMaxChannels)
     return nullptr;
 
@@ -215,11 +215,11 @@
     memcpy(bus->Channel(i)->MutableData(), data, size);
   }
 
-  auto* init = AudioFrameInit::Create();
+  auto* init = AudioDataInit::Create();
   init->setTimestamp(proto.timestamp());
   init->setBuffer(AudioBuffer::CreateFromAudioBus(bus.get()));
 
-  return AudioFrame::Create(init, IGNORE_EXCEPTION_FOR_TESTING);
+  return AudioData::Create(init, IGNORE_EXCEPTION_FOR_TESTING);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webcodecs/fuzzer_utils.h b/third_party/blink/renderer/modules/webcodecs/fuzzer_utils.h
index d4ef5f1..d88626e 100644
--- a/third_party/blink/renderer/modules/webcodecs/fuzzer_utils.h
+++ b/third_party/blink/renderer/modules/webcodecs/fuzzer_utils.h
@@ -14,7 +14,7 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_video_encoder_config.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_video_encoder_encode_options.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
-#include "third_party/blink/renderer/modules/webcodecs/audio_frame.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_data.h"
 #include "third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk.h"
 #include "third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.h"
 #include "third_party/blink/renderer/modules/webcodecs/fuzzer_inputs.pb.h"
@@ -60,8 +60,8 @@
 VideoFrame* MakeVideoFrame(ScriptState* script_state,
                            const wc_fuzzer::VideoFrameBitmapInit& proto);
 
-AudioFrame* MakeAudioFrame(ScriptState* script_state,
-                           const wc_fuzzer::AudioFrameInit& proto);
+AudioData* MakeAudioData(ScriptState* script_state,
+                         const wc_fuzzer::AudioDataInit& proto);
 
 VideoEncoderEncodeOptions* MakeEncodeOptions(
     const wc_fuzzer::EncodeVideo_EncodeOptions& proto);
diff --git a/third_party/blink/renderer/modules/webcodecs/idls.gni b/third_party/blink/renderer/modules/webcodecs/idls.gni
index e9120fb..7cebc71 100644
--- a/third_party/blink/renderer/modules/webcodecs/idls.gni
+++ b/third_party/blink/renderer/modules/webcodecs/idls.gni
@@ -3,9 +3,9 @@
 # found in the LICENSE file.
 
 modules_idl_files = [
+  "audio_data.idl",
   "audio_decoder.idl",
   "audio_encoder.idl",
-  "audio_frame.idl",
   "encoded_audio_chunk.idl",
   "encoded_video_chunk.idl",
   "image_decoder.idl",
@@ -18,7 +18,7 @@
 ]
 
 modules_callback_function_idl_files = [
-  "audio_frame_output_callback.idl",
+  "audio_data_output_callback.idl",
   "encoded_audio_chunk_output_callback.idl",
   "encoded_video_chunk_output_callback.idl",
   "video_frame_output_callback.idl",
@@ -26,13 +26,13 @@
 ]
 
 modules_dictionary_idl_files = [
+  "audio_data_init.idl",
   "audio_decoder_config.idl",
   "audio_decoder_init.idl",
   "audio_decoder_support.idl",
   "audio_encoder_support.idl",
   "audio_encoder_config.idl",
   "audio_encoder_init.idl",
-  "audio_frame_init.idl",
   "avc_encoder_config.idl",
   "encoded_audio_chunk_init.idl",
   "encoded_video_chunk_init.idl",
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
index 702d157..c1150492 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
+++ b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
@@ -503,7 +503,7 @@
     self->ProcessRequests();
   };
 
-  scoped_refptr<media::VideoFrame> frame = request->frame->frame();
+  scoped_refptr<media::VideoFrame> frame = request->input->frame();
 
   // Currently underlying encoders can't handle frame backed by textures,
   // so let's readback pixel data to CPU memory.
@@ -552,7 +552,7 @@
                              WrapCrossThreadPersistent(request))));
 
   // We passed a copy of frame() above, so this should be safe to close here.
-  request->frame->close();
+  request->input->close();
 }
 
 void VideoEncoder::ProcessConfigure(Request* request) {
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder.h b/third_party/blink/renderer/modules/webcodecs/video_encoder.h
index f8fceb6c..071b1d8 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_encoder.h
+++ b/third_party/blink/renderer/modules/webcodecs/video_encoder.h
@@ -50,7 +50,7 @@
   using Init = VideoEncoderInit;
   using Config = VideoEncoderConfig;
   using InternalConfig = ParsedConfig;
-  using Frame = VideoFrame;
+  using Input = VideoFrame;
   using EncodeOptions = VideoEncoderEncodeOptions;
   using OutputChunk = EncodedVideoChunk;
   using OutputCallback = V8EncodedVideoChunkOutputCallback;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu.cc b/third_party/blink/renderer/modules/webgpu/gpu.cc
index a777ffc..e3be8df 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu.cc
@@ -193,7 +193,8 @@
       // Make a new DawnControlClientHolder with the context provider we just
       // made and set the lost context callback
       dawn_control_client_ = base::MakeRefCounted<DawnControlClientHolder>(
-          std::move(context_provider));
+          std::move(context_provider),
+          execution_context->GetTaskRunner(TaskType::kWebGPU));
       dawn_control_client_->SetLostContextCallback();
     }
   }
diff --git a/third_party/blink/renderer/modules/webrtc/webrtc_audio_renderer.cc b/third_party/blink/renderer/modules/webrtc/webrtc_audio_renderer.cc
index e128771..2cfcc47 100644
--- a/third_party/blink/renderer/modules/webrtc/webrtc_audio_renderer.cc
+++ b/third_party/blink/renderer/modules/webrtc/webrtc_audio_renderer.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "base/containers/contains.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
diff --git a/third_party/blink/renderer/modules/xr/xr_plane_manager.cc b/third_party/blink/renderer/modules/xr/xr_plane_manager.cc
index 4de5b40..51790cdb 100644
--- a/third_party/blink/renderer/modules/xr/xr_plane_manager.cc
+++ b/third_party/blink/renderer/modules/xr/xr_plane_manager.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/modules/xr/xr_plane_manager.h"
 
+#include "base/containers/contains.h"
 #include "base/trace_event/trace_event.h"
 #include "third_party/blink/renderer/modules/xr/xr_plane.h"
 #include "third_party/blink/renderer/modules/xr/xr_plane_set.h"
diff --git a/third_party/blink/renderer/modules/xr/xr_session.cc b/third_party/blink/renderer/modules/xr/xr_session.cc
index a4b9f5f82..681f63e 100644
--- a/third_party/blink/renderer/modules/xr/xr_session.cc
+++ b/third_party/blink/renderer/modules/xr/xr_session.cc
@@ -8,6 +8,7 @@
 #include <memory>
 #include <utility>
 
+#include "base/containers/contains.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
 
 #include "base/auto_reset.h"
diff --git a/third_party/blink/renderer/modules/xr/xr_system.cc b/third_party/blink/renderer/modules/xr/xr_system.cc
index 143424a14..b5194af 100644
--- a/third_party/blink/renderer/modules/xr/xr_system.cc
+++ b/third_party/blink/renderer/modules/xr/xr_system.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "base/containers/contains.h"
 #include "build/build_config.h"
 #include "device/vr/public/mojom/vr_service.mojom-blink.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
diff --git a/third_party/blink/renderer/platform/exported/platform.cc b/third_party/blink/renderer/platform/exported/platform.cc
index 3102c71..b06edfc 100644
--- a/third_party/blink/renderer/platform/exported/platform.cc
+++ b/third_party/blink/renderer/platform/exported/platform.cc
@@ -341,4 +341,8 @@
   return nullptr;
 }
 
+gfx::ColorSpace Platform::GetRenderingColorSpace() const {
+  return {};
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_settings.h b/third_party/blink/renderer/platform/graphics/dark_mode_settings.h
index d6b57286..e6904cc 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_settings.h
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_settings.h
@@ -48,6 +48,9 @@
   //
   // Warning: This behavior is the opposite of text_brightness_threshold!
   int background_brightness_threshold = 0;
+
+  // True if text contrast should be increased by painting an outline.
+  bool increase_text_contrast = false;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_settings_builder.cc b/third_party/blink/renderer/platform/graphics/dark_mode_settings_builder.cc
index b0ac0a9..5e58d300 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_settings_builder.cc
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_settings_builder.cc
@@ -131,6 +131,19 @@
   return std::max(min_value, std::min(value, max_value));
 }
 
+bool GetIncreaseTextContrast(const SwitchParams& switch_params) {
+  switch (features::kForceDarkIncreaseTextContrastParam.Get()) {
+    case ForceDarkIncreaseTextContrast::kUseBlinkSettings:
+      return GetIntegerSwitchParamValue<int>(switch_params,
+                                             "IncreaseTextContrast", 0);
+    case ForceDarkIncreaseTextContrast::kFalse:
+      return false;
+    case ForceDarkIncreaseTextContrast::kTrue:
+      return true;
+  }
+  NOTREACHED();
+}
+
 DarkModeSettings BuildDarkModeSettings() {
   SwitchParams switch_params = ParseDarkModeSettings();
 
@@ -156,12 +169,14 @@
                                kDefaultDarkModeImageGrayscalePercent),
       0.0f, 1.0f);
 
+  settings.increase_text_contrast = GetIncreaseTextContrast(switch_params);
+
   return settings;
 }
 
 }  // namespace
 
-DarkModeSettings GetCurrentDarkModeSettings() {
+const DarkModeSettings& GetCurrentDarkModeSettings() {
   static DarkModeSettings settings = BuildDarkModeSettings();
   return settings;
 }
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_settings_builder.h b/third_party/blink/renderer/platform/graphics/dark_mode_settings_builder.h
index d008b88..2582008 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_settings_builder.h
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_settings_builder.h
@@ -10,7 +10,7 @@
 
 namespace blink {
 
-DarkModeSettings PLATFORM_EXPORT GetCurrentDarkModeSettings();
+PLATFORM_EXPORT const DarkModeSettings& GetCurrentDarkModeSettings();
 
 }  // namespace blink
 
diff --git a/third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.cc b/third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.cc
index dd58a01..d97c597 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.cc
@@ -11,12 +11,13 @@
 namespace blink {
 
 DawnControlClientHolder::DawnControlClientHolder(
-    std::unique_ptr<WebGraphicsContext3DProvider> context_provider)
+    std::unique_ptr<WebGraphicsContext3DProvider> context_provider,
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner)
     : context_provider_(std::make_unique<WebGraphicsContext3DProviderWrapper>(
           std::move(context_provider))),
       interface_(GetContextProvider()->WebGPUInterface()),
       procs_(interface_->GetProcs()),
-      recyclable_resource_cache_(interface_) {}
+      recyclable_resource_cache_(interface_, task_runner) {}
 
 void DawnControlClientHolder::SetLostContextCallback() {
   GetContextProvider()->SetLostContextCallback(WTF::BindRepeating(
diff --git a/third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.h b/third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.h
index 9482ad60..45107df 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.h
+++ b/third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.h
@@ -30,7 +30,8 @@
     : public RefCounted<DawnControlClientHolder> {
  public:
   DawnControlClientHolder(
-      std::unique_ptr<WebGraphicsContext3DProvider> context_provider);
+      std::unique_ptr<WebGraphicsContext3DProvider> context_provider,
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner);
 
   void Destroy();
 
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler_test.cc b/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler_test.cc
index a952864b..26f10b4d 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler_test.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler_test.cc
@@ -368,8 +368,8 @@
     auto provider = std::make_unique<WebGraphicsContext3DProviderForTests>(
         std::move(webgpu));
 
-    dawn_control_client_ =
-        base::MakeRefCounted<DawnControlClientHolder>(std::move(provider));
+    dawn_control_client_ = base::MakeRefCounted<DawnControlClientHolder>(
+        std::move(provider), base::ThreadTaskRunnerHandle::Get());
 
     test_context_provider_ = viz::TestContextProvider::Create();
     InitializeSharedGpuContext(test_context_provider_.get());
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_resource_provider_cache.cc b/third_party/blink/renderer/platform/graphics/gpu/webgpu_resource_provider_cache.cc
index 5b4b78f..44b69ac 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_resource_provider_cache.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/webgpu_resource_provider_cache.cc
@@ -4,6 +4,9 @@
 
 #include "third_party/blink/renderer/platform/graphics/gpu/webgpu_resource_provider_cache.h"
 
+#include "base/metrics/histogram_functions.h"
+#include "base/time/time.h"
+
 namespace blink {
 
 ResourceCacheKey::ResourceCacheKey(const IntSize& size,
@@ -58,9 +61,15 @@
 }
 
 WebGPURecyclableResourceCache::WebGPURecyclableResourceCache(
-    gpu::webgpu::WebGPUInterface* webgpu_interface)
-    : webgpu_interface_(webgpu_interface) {
+    gpu::webgpu::WebGPUInterface* webgpu_interface,
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+    : webgpu_interface_(webgpu_interface),
+      task_runner_(std::move(task_runner)) {
   weak_ptr_ = weak_ptr_factory_.GetWeakPtr();
+  timer_func_ = WTF::BindRepeating(
+      &WebGPURecyclableResourceCache::ReleaseStaleResources, weak_ptr_);
+
+  DCHECK_LE(kTimerDurationInSeconds, kCleanUpDelayInSeconds);
 }
 
 std::unique_ptr<RecyclableCanvasResource>
@@ -86,19 +95,36 @@
 
 void WebGPURecyclableResourceCache::OnDestroyRecyclableResource(
     std::unique_ptr<CanvasResourceProvider> resource_provider) {
+  int resource_size = resource_provider->Size().Width() *
+                      resource_provider->Size().Height() *
+                      resource_provider->ColorParams().BytesPerPixel();
+  total_unused_resources_in_bytes_ += resource_size;
+
   // WaitSyncToken on the canvas resource.
   gpu::SyncToken finished_access_token;
   webgpu_interface_->GenUnverifiedSyncTokenCHROMIUM(
       finished_access_token.GetData());
   resource_provider->OnDestroyRecyclableCanvasResource(finished_access_token);
 
-  // Transfer to |unused_providers_|.  MRU goes to the front.
-  unused_providers_.push_front(std::move(resource_provider));
+  unused_providers_.push_front(
+      Resource(std::move(resource_provider), current_timer_id_, resource_size));
 
-  // If the cache is full, release the LRU one.
-  if (unused_providers_.size() >= capacity_) {
+  if (last_seen_max_unused_resources_in_bytes_ <
+      total_unused_resources_in_bytes_) {
+    last_seen_max_unused_resources_in_bytes_ = total_unused_resources_in_bytes_;
+  }
+  if (last_seen_max_unused_resources_ < unused_providers_.size()) {
+    last_seen_max_unused_resources_ = unused_providers_.size();
+  }
+
+  // If the cache is full, release LRU from the back.
+  while (total_unused_resources_in_bytes_ >
+         kMaxRecyclableResourceCachesInBytes) {
+    total_unused_resources_in_bytes_ -= unused_providers_.back().resource_size_;
     unused_providers_.pop_back();
   }
+
+  StartResourceCleanUpTimer();
 }
 
 std::unique_ptr<CanvasResourceProvider>
@@ -107,7 +133,7 @@
   // Loop from MRU to LRU
   DequeResourceProvider::iterator it;
   for (it = unused_providers_.begin(); it != unused_providers_.end(); ++it) {
-    CanvasResourceProvider* resource_provider = it->get();
+    CanvasResourceProvider* resource_provider = it->resource_provider_.get();
     const auto it_cache_key = ResourceCacheKey(
         resource_provider->Size(), resource_provider->ColorParams(),
         resource_provider->IsOriginTopLeft());
@@ -119,20 +145,87 @@
 
   // Found one.
   if (it != unused_providers_.end()) {
-    std::unique_ptr<CanvasResourceProvider> provider = (std::move(*it));
+    std::unique_ptr<CanvasResourceProvider> provider =
+        (std::move(it->resource_provider_));
+    total_unused_resources_in_bytes_ -= it->resource_size_;
     // TODO(magchen@): If the cache capacity increases a lot, will erase(it)
     // becomes inefficient?
     // Remove the provider from the |unused_providers_|.
     unused_providers_.erase(it);
     provider->OnAcquireRecyclableCanvasResource();
+
     return provider;
   }
   return nullptr;
 }
 
-void WebGPURecyclableResourceCache::SetWebGPUInterfaceForTesting(
-    gpu::webgpu::WebGPUInterface* webgpu_interface) {
-  webgpu_interface_ = webgpu_interface;
+void WebGPURecyclableResourceCache::ReleaseStaleResources() {
+  timer_is_running_ = false;
+
+  // Loop from LRU to MRU
+  int stale_resource_count = 0;
+  for (auto it = unused_providers_.rbegin(); it != unused_providers_.rend();
+       ++it) {
+    auto timer_id_ = it->timer_id_;
+    int delta;
+    delta = current_timer_id_ - timer_id_;
+    if ((current_timer_id_ - it->timer_id_) < kTimerIdDeltaForDeletion) {
+      // These are the resources which are recycled and stay in the cache for
+      // less than kCleanUpDelayInSeconds. They are not to be deleted this time.
+      break;
+    }
+    stale_resource_count++;
+  }
+
+  // Delete all stale resources.
+  for (int i = 0; i < stale_resource_count; ++i) {
+    total_unused_resources_in_bytes_ -= unused_providers_.back().resource_size_;
+    unused_providers_.pop_back();
+  }
+
+  // The number of stale Resources released this time in this function.
+  base::UmaHistogramCustomCounts("Blink.Canvas.WebGPUStaleResourceCount",
+                                 stale_resource_count, /*min=*/0,
+                                 /*max=*/300,
+                                 /*buckets=*/50);
+
+  // The maximum number of total resource memory size between two
+  // ReleaseStaleResources() calls.
+  // UmaHistogramCustomCounts only takes the int type as input.
+  int last_seen_max_unused_resources_in_kb =
+      static_cast<int>(last_seen_max_unused_resources_in_bytes_ / 1024);
+  base::UmaHistogramCustomCounts("Blink.Canvas.WebGPUMaxRecycledResourcesInKB",
+                                 last_seen_max_unused_resources_in_kb,
+                                 /*min=*/0,
+                                 /*max=*/kMaxRecyclableResourceCachesInKB,
+                                 /*buckets=*/50);
+  last_seen_max_unused_resources_in_bytes_ = 0;
+
+  // The maximum number of unused resources between two ReleaseStaleResources()
+  // calls.
+  base::UmaHistogramCustomCounts("Blink.Canvas.WebGPUMaxRecycledResourcesCount",
+                                 last_seen_max_unused_resources_,
+                                 /*min=*/0,
+                                 /*max=*/300,
+                                 /*buckets=*/50);
+  last_seen_max_unused_resources_ = 0;
+
+  current_timer_id_++;
+  StartResourceCleanUpTimer();
+}
+void WebGPURecyclableResourceCache::StartResourceCleanUpTimer() {
+  if (unused_providers_.size() > 0 && !timer_is_running_) {
+    task_runner_->PostDelayedTask(
+        FROM_HERE, timer_func_,
+        base::TimeDelta::FromSeconds(kTimerDurationInSeconds));
+    timer_is_running_ = true;
+  }
+}
+
+wtf_size_t
+WebGPURecyclableResourceCache::CleanUpResourcesAndReturnSizeForTesting() {
+  ReleaseStaleResources();
+  return unused_providers_.size();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_resource_provider_cache.h b/third_party/blink/renderer/platform/graphics/gpu/webgpu_resource_provider_cache.h
index b1ba772..b8327155 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_resource_provider_cache.h
+++ b/third_party/blink/renderer/platform/graphics/gpu/webgpu_resource_provider_cache.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_GPU_WEBGPU_RESOURCE_PROVIDER_CACHE_H_
 
 #include "base/threading/thread_checker.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "gpu/command_buffer/client/webgpu_interface.h"
 #include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
@@ -51,7 +52,8 @@
 class PLATFORM_EXPORT WebGPURecyclableResourceCache {
  public:
   explicit WebGPURecyclableResourceCache(
-      gpu::webgpu::WebGPUInterface* webgpu_interface);
+      gpu::webgpu::WebGPUInterface* webgpu_interface,
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner);
   ~WebGPURecyclableResourceCache() = default;
 
   std::unique_ptr<RecyclableCanvasResource> GetOrCreateCanvasResource(
@@ -64,30 +66,83 @@
   void OnDestroyRecyclableResource(
       std::unique_ptr<CanvasResourceProvider> resource_provider);
 
-  void SetWebGPUInterfaceForTesting(
-      gpu::webgpu::WebGPUInterface* webgpu_interface);
+  void ConfigureForTesting(gpu::webgpu::WebGPUInterface* webgpu_interface);
+  wtf_size_t CleanUpResourcesAndReturnSizeForTesting();
+
+  int GetWaitCountBeforeDeletionForTesting() {
+    return kTimerIdDeltaForDeletion;
+  }
 
  private:
-  // TODO(magchen@): Increase the size after the timer for cleaning up stale
-  // resources is added.
-  static constexpr wtf_size_t kMaxRecyclableResourceCaches = 4;
-  using DequeResourceProvider =
-      WTF::Deque<std::unique_ptr<CanvasResourceProvider>>;
+  // The maximum number of unused CanvasResourceProviders size, 128 MB.
+  static constexpr int kMaxRecyclableResourceCachesInKB = 128 * 1024;
+  static constexpr int kMaxRecyclableResourceCachesInBytes =
+      kMaxRecyclableResourceCachesInKB * 1024;
+
+  // A resource is deleted from the cache if it's not reused after this delay.
+  static constexpr int kCleanUpDelayInSeconds = 2;
+
+  // The duration set to the resource clean-up timer function.
+  // Because the resource clean-up function runs every kCleanUpDelayInSeconds
+  // and the stale resource can only be deleted in the call to
+  // ReleaseStaleResources(). The actually delay could be as long as
+  // (kCleanUpDelayInSeconds + kCleanUpDelayInSeconds).
+  static constexpr int kTimerDurationInSeconds = 1;
+
+  // The time it takes to increase the Timer Id by this delta is equivalent to
+  // kCleanUpDelayInSeconds.
+  static constexpr int kTimerIdDeltaForDeletion =
+      kCleanUpDelayInSeconds / kTimerDurationInSeconds;
+
+  struct Resource {
+    explicit Resource(std::unique_ptr<CanvasResourceProvider> resource_provider,
+                      unsigned int timer_id,
+                      int resource_size)
+        : resource_provider_(std::move(resource_provider)),
+          timer_id_(timer_id),
+          resource_size_(resource_size) {}
+
+    std::unique_ptr<CanvasResourceProvider> resource_provider_;
+    unsigned int timer_id_ = 0;
+    int resource_size_ = 0;
+  };
+
+  using DequeResourceProvider = WTF::Deque<Resource>;
 
   // Search |unused_providers_| and acquire the canvas resource provider with
   // the same cache key for re-use.
   std::unique_ptr<CanvasResourceProvider> AcquireCachedProvider(
       const ResourceCacheKey& cache_key);
 
+  // Release the stale resources which are recycled before the last clean-up.
+  void ReleaseStaleResources();
+
+  // Start the clean-up function runs when there are unused resources.
+  void StartResourceCleanUpTimer();
+
   // This is the place to keep the unused CanvasResourceProviders. They are
   // waiting to be used. MRU is in the front of the deque.
   DequeResourceProvider unused_providers_;
 
-  // The maximum number of unused CanvasResourceProviders that we can cached.
-  const wtf_size_t capacity_ = kMaxRecyclableResourceCaches;
+  uint64_t total_unused_resources_in_bytes_ = 0;
+
+  // For histograms only.
+  uint64_t last_seen_max_unused_resources_in_bytes_ = 0;
+  wtf_size_t last_seen_max_unused_resources_ = 0;
 
   gpu::webgpu::WebGPUInterface* webgpu_interface_;
 
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+  base::RepeatingCallback<void()> timer_func_;
+
+  // This ensures only one timer task is scheduled.
+  bool timer_is_running_ = false;
+
+  // |current_timer_id_| increases by 1 when the clean-up timer function is
+  // called. This id is saved in Resource when the resource is recycled and is
+  // checked later to determine whether this resource is stale.
+  unsigned int current_timer_id_ = 0;
+
   THREAD_CHECKER(thread_checker_);
   base::WeakPtr<WebGPURecyclableResourceCache> weak_ptr_;
   base::WeakPtrFactory<WebGPURecyclableResourceCache> weak_ptr_factory_{this};
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_resource_provider_cache_test.cc b/third_party/blink/renderer/platform/graphics/gpu/webgpu_resource_provider_cache_test.cc
index e36e084..9ef7fdf 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_resource_provider_cache_test.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/webgpu_resource_provider_cache_test.cc
@@ -4,11 +4,12 @@
 
 #include "third_party/blink/renderer/platform/graphics/gpu/webgpu_resource_provider_cache.h"
 
-#include "base/test/null_task_runner.h"
+#include "base/test/task_environment.h"
 #include "cc/test/stub_decode_cache.h"
 #include "components/viz/test/test_context_provider.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.h"
+#include "third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test_helpers.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
 #include "third_party/blink/renderer/platform/graphics/test/gpu_test_utils.h"
 
@@ -24,29 +25,27 @@
   void TearDown() override;
 
  protected:
-  WebGPURecyclableResourceCache recyclable_resource_cache_{nullptr};
-  scoped_refptr<base::NullTaskRunner> task_runner_;
-  std::unique_ptr<base::ThreadTaskRunnerHandle> handle_;
+  base::test::TaskEnvironment task_environment_;
+  std::unique_ptr<WebGPURecyclableResourceCache> recyclable_resource_cache_;
   cc::StubDecodeCache image_decode_cache_;
   scoped_refptr<viz::TestContextProvider> test_context_provider_;
 };
 
 void WebGPURecyclableResourceCacheTest::SetUp() {
-  task_runner_ = base::MakeRefCounted<base::NullTaskRunner>();
-  handle_ = std::make_unique<base::ThreadTaskRunnerHandle>(task_runner_);
+  Platform::SetMainThreadTaskRunnerForTesting();
   test_context_provider_ = viz::TestContextProvider::Create();
   InitializeSharedGpuContext(test_context_provider_.get(),
                              &image_decode_cache_);
-
   auto* webgpu_interface = SharedGpuContext::ContextProviderWrapper()
                                ->ContextProvider()
                                ->WebGPUInterface();
-  recyclable_resource_cache_.SetWebGPUInterfaceForTesting(webgpu_interface);
+
+  recyclable_resource_cache_ = std::make_unique<WebGPURecyclableResourceCache>(
+      webgpu_interface, base::ThreadTaskRunnerHandle::Get());
 }
 
 void WebGPURecyclableResourceCacheTest::TearDown() {
-  handle_.reset();
-  task_runner_.reset();
+  Platform::UnsetMainThreadTaskRunnerForTesting();
   SharedGpuContext::ResetForTesting();
 }
 
@@ -57,21 +56,21 @@
   const CanvasResourceParams params(
       CanvasColorSpace::kSRGB, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
   std::unique_ptr<RecyclableCanvasResource> provider_holder_0 =
-      recyclable_resource_cache_.GetOrCreateCanvasResource(
+      recyclable_resource_cache_->GetOrCreateCanvasResource(
           kSize, params, /*is_origin_top_left=*/true);
   returned_resource_providers.push_back(provider_holder_0->resource_provider());
 
   std::unique_ptr<RecyclableCanvasResource> provider_holder_1 =
-      recyclable_resource_cache_.GetOrCreateCanvasResource(
+      recyclable_resource_cache_->GetOrCreateCanvasResource(
           kSize, params, /*is_origin_top_left=*/true);
   returned_resource_providers.push_back(provider_holder_1->resource_provider());
 
-  // Now release the holder to recycle the resource_provider.
+  // Now release the holders to recycle the resource_providers.
   provider_holder_0.reset();
   provider_holder_1.reset();  // MRU
 
   std::unique_ptr<RecyclableCanvasResource> provider_holder_2 =
-      recyclable_resource_cache_.GetOrCreateCanvasResource(
+      recyclable_resource_cache_->GetOrCreateCanvasResource(
           kSize, params, /*is_origin_top_left=*/true);
   returned_resource_providers.push_back(provider_holder_2->resource_provider());
 
@@ -87,12 +86,12 @@
   const CanvasResourceParams params(
       CanvasColorSpace::kSRGB, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
   std::unique_ptr<RecyclableCanvasResource> provider_holder_0 =
-      recyclable_resource_cache_.GetOrCreateCanvasResource(
+      recyclable_resource_cache_->GetOrCreateCanvasResource(
           kSizes[0], params, /*is_origin_top_left=*/true);
   returned_resource_providers.push_back(provider_holder_0->resource_provider());
 
   std::unique_ptr<RecyclableCanvasResource> provider_holder_1 =
-      recyclable_resource_cache_.GetOrCreateCanvasResource(
+      recyclable_resource_cache_->GetOrCreateCanvasResource(
           kSizes[1], params, /*is_origin_top_left=*/true);
   returned_resource_providers.push_back(provider_holder_1->resource_provider());
 
@@ -101,12 +100,12 @@
   provider_holder_0.reset();
 
   std::unique_ptr<RecyclableCanvasResource> provider_holder_2 =
-      recyclable_resource_cache_.GetOrCreateCanvasResource(
+      recyclable_resource_cache_->GetOrCreateCanvasResource(
           kSizes[0], params, /*is_origin_top_left=*/true);
   returned_resource_providers.push_back(provider_holder_2->resource_provider());
 
   std::unique_ptr<RecyclableCanvasResource> provider_holder_3 =
-      recyclable_resource_cache_.GetOrCreateCanvasResource(
+      recyclable_resource_cache_->GetOrCreateCanvasResource(
           kSizes[1], params, /*is_origin_top_left=*/true);
   returned_resource_providers.push_back(provider_holder_3->resource_provider());
 
@@ -123,7 +122,7 @@
   const CanvasResourceParams params(
       CanvasColorSpace::kSRGB, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
   std::unique_ptr<RecyclableCanvasResource> provider_holder_0 =
-      recyclable_resource_cache_.GetOrCreateCanvasResource(
+      recyclable_resource_cache_->GetOrCreateCanvasResource(
           kSizes[0], params, /*is_origin_top_left=*/true);
   returned_resource_providers.push_back(provider_holder_0->resource_provider());
 
@@ -132,7 +131,7 @@
 
   // (1) For different size.
   std::unique_ptr<RecyclableCanvasResource> provider_holder_1 =
-      recyclable_resource_cache_.GetOrCreateCanvasResource(
+      recyclable_resource_cache_->GetOrCreateCanvasResource(
           kSizes[1], params, /*is_origin_top_left=*/true);
   returned_resource_providers.push_back(provider_holder_1->resource_provider());
 
@@ -141,7 +140,7 @@
 
   // (2) For different is_origin_top_left.
   std::unique_ptr<RecyclableCanvasResource> provider_holder_2 =
-      recyclable_resource_cache_.GetOrCreateCanvasResource(
+      recyclable_resource_cache_->GetOrCreateCanvasResource(
           kSizes[0], params, /*is_origin_top_left=*/false);
   returned_resource_providers.push_back(provider_holder_2->resource_provider());
 
@@ -152,7 +151,7 @@
   const CanvasResourceParams params_3(
       CanvasColorSpace::kRec2020, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
   std::unique_ptr<RecyclableCanvasResource> provider_holder_3 =
-      recyclable_resource_cache_.GetOrCreateCanvasResource(
+      recyclable_resource_cache_->GetOrCreateCanvasResource(
           kSizes[0], params_3, /*is_origin_top_left=*/true);
   returned_resource_providers.push_back(provider_holder_3->resource_provider());
 
@@ -163,7 +162,7 @@
   const CanvasResourceParams params_4(
       CanvasColorSpace::kSRGB, kRGBA_F16_SkColorType, kPremul_SkAlphaType);
   std::unique_ptr<RecyclableCanvasResource> provider_holder_4 =
-      recyclable_resource_cache_.GetOrCreateCanvasResource(
+      recyclable_resource_cache_->GetOrCreateCanvasResource(
           kSizes[0], params_4, /*is_origin_top_left=*/true);
   returned_resource_providers.push_back(provider_holder_4->resource_provider());
 
@@ -174,7 +173,7 @@
   const CanvasResourceParams params_5(
       CanvasColorSpace::kSRGB, kRGBA_8888_SkColorType, kOpaque_SkAlphaType);
   std::unique_ptr<RecyclableCanvasResource> provider_holder_5 =
-      recyclable_resource_cache_.GetOrCreateCanvasResource(
+      recyclable_resource_cache_->GetOrCreateCanvasResource(
           kSizes[0], params_5, /*is_origin_top_left=*/true);
   returned_resource_providers.push_back(provider_holder_5->resource_provider());
 
@@ -183,7 +182,7 @@
 
   // (6) For the same config again.
   std::unique_ptr<RecyclableCanvasResource> provider_holder_6 =
-      recyclable_resource_cache_.GetOrCreateCanvasResource(
+      recyclable_resource_cache_->GetOrCreateCanvasResource(
           kSizes[0], params, /*is_origin_top_left=*/true);
   returned_resource_providers.push_back(provider_holder_6->resource_provider());
 
@@ -191,4 +190,91 @@
   EXPECT_EQ(returned_resource_providers[0], returned_resource_providers[6]);
 }
 
+TEST_F(WebGPURecyclableResourceCacheTest, StaleResourcesCleanUp) {
+  const IntSize kSize(10, 10);
+  Vector<CanvasResourceProvider*> returned_resource_providers;
+  // The loop count for CleanUpResources before the resource gets cleaned up.
+  int wait_count =
+      recyclable_resource_cache_->GetWaitCountBeforeDeletionForTesting();
+
+  const CanvasResourceParams params(
+      CanvasColorSpace::kSRGB, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
+  std::unique_ptr<RecyclableCanvasResource> provider_holder_0 =
+      recyclable_resource_cache_->GetOrCreateCanvasResource(
+          kSize, params, /*is_origin_top_left=*/true);
+  returned_resource_providers.push_back(provider_holder_0->resource_provider());
+
+  std::unique_ptr<RecyclableCanvasResource> provider_holder_1 =
+      recyclable_resource_cache_->GetOrCreateCanvasResource(
+          kSize, params, /*is_origin_top_left=*/true);
+  returned_resource_providers.push_back(provider_holder_1->resource_provider());
+
+  // Now release the holders to recycle the resource_providers.
+  provider_holder_0.reset();
+  provider_holder_1.reset();
+
+  // Before the intended delay, the recycled resources should not be released
+  // from cache.
+  for (int i = 0; i < wait_count; i++) {
+    wtf_size_t size =
+        recyclable_resource_cache_->CleanUpResourcesAndReturnSizeForTesting();
+    EXPECT_EQ(2u, size);
+  }
+
+  // After the intended delay, all stale resources should be released now.
+  wtf_size_t size_after =
+      recyclable_resource_cache_->CleanUpResourcesAndReturnSizeForTesting();
+  EXPECT_EQ(0u, size_after);
+}
+
+TEST_F(WebGPURecyclableResourceCacheTest, ReuseBeforeCleanUp) {
+  const IntSize kSize(10, 10);
+  Vector<CanvasResourceProvider*> returned_resource_providers;
+  // The loop count for CleanUpResources before the resource gets cleaned up.
+  int wait_count =
+      recyclable_resource_cache_->GetWaitCountBeforeDeletionForTesting();
+
+  const CanvasResourceParams params(
+      CanvasColorSpace::kSRGB, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
+  std::unique_ptr<RecyclableCanvasResource> provider_holder_0 =
+      recyclable_resource_cache_->GetOrCreateCanvasResource(
+          kSize, params, /*is_origin_top_left=*/true);
+  returned_resource_providers.push_back(provider_holder_0->resource_provider());
+
+  // Release the holder to recycle the resource_provider.
+  provider_holder_0.reset();
+
+  // Before the intended delay, the recycled resources should not be released
+  // from cache.
+  for (int i = 0; i < wait_count; i++) {
+    if (i == 1) {
+      // Now request a resource with the same configuration.
+      std::unique_ptr<RecyclableCanvasResource> provider_holder_1 =
+          recyclable_resource_cache_->GetOrCreateCanvasResource(
+              kSize, params, /*is_origin_top_left=*/true);
+      returned_resource_providers.push_back(
+          provider_holder_1->resource_provider());
+
+      // Release the holders again to recycle the resource_providers.
+      provider_holder_1.reset();
+    }
+
+    wtf_size_t size =
+        recyclable_resource_cache_->CleanUpResourcesAndReturnSizeForTesting();
+    EXPECT_EQ(1u, size);
+  }
+
+  // Since the resource is reused before it gets deleted, it should not be
+  // cleaned up on the next scheduled clean up. Instead, it will be cleaned up
+  // with a new schedule.
+  //
+  wtf_size_t size =
+      recyclable_resource_cache_->CleanUpResourcesAndReturnSizeForTesting();
+  EXPECT_EQ(1u, size);
+
+  // Now, the resource should be deleted.
+  size = recyclable_resource_cache_->CleanUpResourcesAndReturnSizeForTesting();
+  EXPECT_EQ(0u, size);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider_test.cc b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider_test.cc
index 90b3916..3441283d 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider_test.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider_test.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.h"
 
+#include "base/test/task_environment.h"
 #include "gpu/command_buffer/client/webgpu_interface_stub.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -94,18 +95,23 @@
     auto webgpu = std::make_unique<MockWebGPUInterface>();
     webgpu_ = webgpu.get();
 
+    Platform::SetMainThreadTaskRunnerForTesting();
+
     auto provider = std::make_unique<WebGraphicsContext3DProviderForTests>(
         std::move(webgpu));
     sii_ = provider->SharedImageInterface();
 
-    dawn_control_client_ =
-        base::MakeRefCounted<DawnControlClientHolder>(std::move(provider));
+    dawn_control_client_ = base::MakeRefCounted<DawnControlClientHolder>(
+        std::move(provider), base::ThreadTaskRunnerHandle::Get());
 
     provider_ = base::MakeRefCounted<WebGPUSwapBufferProviderForTests>(
         &provider_alive_, &client_, fake_device_, dawn_control_client_,
         WGPUTextureUsage_RenderAttachment, WGPUTextureFormat_RGBA8Unorm);
   }
 
+  void TearDown() override { Platform::UnsetMainThreadTaskRunnerForTesting(); }
+
+  base::test::TaskEnvironment task_environment_;
   scoped_refptr<DawnControlClientHolder> dawn_control_client_;
   MockWebGPUInterface* webgpu_;
   viz::TestSharedImageInterface* sii_;
diff --git a/third_party/blink/renderer/platform/graphics/graphics_context.cc b/third_party/blink/renderer/platform/graphics/graphics_context.cc
index 030e035..59c8ea88 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_context.cc
+++ b/third_party/blink/renderer/platform/graphics/graphics_context.cc
@@ -110,6 +110,8 @@
     flags_ = &flags;
   }
 
+  bool applied_dark_mode() const { return !!dark_mode_flags_; }
+
   operator const PaintFlags&() const { return *flags_; }
 
  private:
@@ -669,17 +671,25 @@
   TextDrawingModeFlags mode_flags = TextDrawingMode();
 
   if (mode_flags & kTextModeFill) {
-    draw_text(ImmutableState()->FillFlags());
+    const PaintFlags& flags = ImmutableState()->FillFlags();
+    DarkModeFlags dark_flags(this, flags, DarkModeFilter::ElementRole::kText);
+    if (UNLIKELY(ShouldDrawDarkModeTextContrastOutline(flags, dark_flags))) {
+      PaintFlags outline_flags(flags);
+      outline_flags.setStyle(PaintFlags::kStroke_Style);
+      outline_flags.setStrokeWidth(1);
+      draw_text(outline_flags);
+    }
+    draw_text(dark_flags);
   }
 
   if ((mode_flags & kTextModeStroke) && GetStrokeStyle() != kNoStroke &&
       StrokeThickness() > 0) {
-    PaintFlags stroke_flags(ImmutableState()->StrokeFlags());
+    PaintFlags flags(ImmutableState()->StrokeFlags());
     if (mode_flags & kTextModeFill) {
       // shadow was already applied during fill pass
-      stroke_flags.setLooper(nullptr);
+      flags.setLooper(nullptr);
     }
-    draw_text(stroke_flags);
+    draw_text(DarkModeFlags(this, flags, DarkModeFilter::ElementRole::kText));
   }
 }
 
@@ -689,14 +699,31 @@
                                        const FloatPoint& point,
                                        DOMNodeId node_id) {
   DrawTextPasses([&](const PaintFlags& flags) {
-    font.DrawText(
-        canvas_, text_info, point, device_scale_factor_, node_id,
-        DarkModeFlags(this, flags, DarkModeFilter::ElementRole::kText),
-        printing_ ? Font::DrawType::kGlyphsAndClusters
-                  : Font::DrawType::kGlyphsOnly);
+    font.DrawText(canvas_, text_info, point, device_scale_factor_, node_id,
+                  flags,
+                  printing_ ? Font::DrawType::kGlyphsAndClusters
+                            : Font::DrawType::kGlyphsOnly);
   });
 }
 
+bool GraphicsContext::ShouldDrawDarkModeTextContrastOutline(
+    const PaintFlags& original_flags,
+    const DarkModeFlags& dark_flags) const {
+  if (!dark_flags.applied_dark_mode())
+    return false;
+  if (!GetCurrentDarkModeSettings().increase_text_contrast)
+    return false;
+
+  // To avoid outlining all text, only draw an outline that improves contrast.
+  // 90000 represents a difference of roughly 175 in all three channels.
+  // TODO(pdr): Calculate a contrast ratio using luminance (see:
+  // https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html).
+  constexpr int kMinimumDifferenceSq = 90000;
+  Color dark_color(static_cast<const PaintFlags&>(dark_flags).getColor());
+  Color original_color(original_flags.getColor());
+  return DifferenceSquared(dark_color, original_color) > kMinimumDifferenceSq;
+}
+
 void GraphicsContext::DrawText(const Font& font,
                                const TextRunPaintInfo& text_info,
                                const FloatPoint& point,
diff --git a/third_party/blink/renderer/platform/graphics/graphics_context.h b/third_party/blink/renderer/platform/graphics/graphics_context.h
index 8affd5dd..539fbc3 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_context.h
+++ b/third_party/blink/renderer/platform/graphics/graphics_context.h
@@ -501,6 +501,10 @@
 
   class DarkModeFlags;
 
+  bool ShouldDrawDarkModeTextContrastOutline(
+      const PaintFlags& original_flags,
+      const DarkModeFlags& dark_flags) const;
+
   // This is owned by paint_recorder_. Never delete this object.
   // Drawing operations are allowed only after the first BeginRecording() which
   // initializes this to not null.
diff --git a/third_party/blink/renderer/platform/heap/impl/heap_page.cc b/third_party/blink/renderer/platform/heap/impl/heap_page.cc
index a6e16d7..96f3b88 100644
--- a/third_party/blink/renderer/platform/heap/impl/heap_page.cc
+++ b/third_party/blink/renderer/platform/heap/impl/heap_page.cc
@@ -824,7 +824,7 @@
   DCHECK_GE(shrink_size, sizeof(HeapObjectHeader));
   DCHECK_GT(header->GcInfoIndex(), 0u);
   Address shrink_address = header->PayloadEnd() - shrink_size;
-  HeapObjectHeader* freed_header = new (NotNull, shrink_address)
+  HeapObjectHeader* freed_header = new (NotNullTag::kNotNull, shrink_address)
       HeapObjectHeader(shrink_size, header->GcInfoIndex());
   // Since only size has been changed, we don't need to update object starts.
   PromptlyFreeObjectInFreeList(freed_header, shrink_size);
@@ -1011,7 +1011,7 @@
   DCHECK_GT(gc_info_index, 0u);
   LargeObjectPage* large_page = new (large_page_address)
       LargeObjectPage(page_memory, this, allocation_size);
-  HeapObjectHeader* header = new (NotNull, header_address)
+  HeapObjectHeader* header = new (NotNullTag::kNotNull, header_address)
       HeapObjectHeader(kLargeObjectSizeInHeader, gc_info_index);
   Address result = header_address + sizeof(*header);
   DCHECK(!(reinterpret_cast<uintptr_t>(result) & kAllocationMask));
@@ -1105,13 +1105,13 @@
     // Create a dummy header with only a size and freelist bit set.
     DCHECK_GE(size, sizeof(HeapObjectHeader));
     // Free list encode the size to mark the lost memory as freelist memory.
-    new (NotNull, address)
+    new (NotNullTag::kNotNull, address)
         HeapObjectHeader(size, kGcInfoIndexForFreeListHeader);
     ASAN_POISON_MEMORY_REGION(address, size);
     // This memory gets lost. Sweeping can reclaim it.
     return;
   }
-  entry = new (NotNull, address) FreeListEntry(size);
+  entry = new (NotNullTag::kNotNull, address) FreeListEntry(size);
 
 #if DCHECK_IS_ON() || defined(LEAK_SANITIZER) || defined(ADDRESS_SANITIZER)
   // The following logic delays reusing free lists for (at least) one GC
diff --git a/third_party/blink/renderer/platform/heap/impl/heap_page.h b/third_party/blink/renderer/platform/heap/impl/heap_page.h
index 99e34d6..f68c999 100644
--- a/third_party/blink/renderer/platform/heap/impl/heap_page.h
+++ b/third_party/blink/renderer/platform/heap/impl/heap_page.h
@@ -1333,7 +1333,7 @@
     current_allocation_point_ += allocation_size;
     remaining_allocation_size_ -= allocation_size;
     DCHECK_GT(gc_info_index, 0u);
-    new (NotNull, header_address)
+    new (NotNullTag::kNotNull, header_address)
         HeapObjectHeader(allocation_size, gc_info_index);
     DCHECK(!PageFromObject(header_address)->IsLargeObjectPage());
     static_cast<NormalPage*>(PageFromObject(header_address))
diff --git a/third_party/blink/renderer/platform/heap/impl/member.h b/third_party/blink/renderer/platform/heap/impl/member.h
index 4552423a..97073bff 100644
--- a/third_party/blink/renderer/platform/heap/impl/member.h
+++ b/third_party/blink/renderer/platform/heap/impl/member.h
@@ -504,7 +504,7 @@
  public:
   template <typename... Args>
   static T* Construct(void* location, Args&&... args) {
-    return new (NotNull, location) T(std::forward<Args>(args)...);
+    return new (NotNullTag::kNotNull, location) T(std::forward<Args>(args)...);
   }
 
   static void NotifyNewElement(T* element) { element->WriteBarrier(); }
diff --git a/third_party/blink/renderer/platform/heap/test/heap_test.cc b/third_party/blink/renderer/platform/heap/test/heap_test.cc
index 715cafe..f1ef45da 100644
--- a/third_party/blink/renderer/platform/heap/test/heap_test.cc
+++ b/third_party/blink/renderer/platform/heap/test/heap_test.cc
@@ -500,7 +500,8 @@
     : GenericHashTraits<blink::ThreadMarker> {
   static const bool kEmptyValueIsZero = true;
   static void ConstructDeletedValue(blink::ThreadMarker& slot, bool) {
-    new (NotNull, &slot) blink::ThreadMarker(kHashTableDeletedValue);
+    new (NotNullTag::kNotNull, &slot)
+        blink::ThreadMarker(kHashTableDeletedValue);
   }
   static bool IsDeletedValue(const blink::ThreadMarker& slot) {
     return slot.IsHashTableDeletedValue();
diff --git a/third_party/blink/renderer/platform/heap/v8_wrapper/member.h b/third_party/blink/renderer/platform/heap/v8_wrapper/member.h
index 5799b7b..3366052 100644
--- a/third_party/blink/renderer/platform/heap/v8_wrapper/member.h
+++ b/third_party/blink/renderer/platform/heap/v8_wrapper/member.h
@@ -58,7 +58,7 @@
  public:
   template <typename... Args>
   static T* Construct(void* location, Args&&... args) {
-    return new (NotNull, location) T(std::forward<Args>(args)...);
+    return new (NotNullTag::kNotNull, location) T(std::forward<Args>(args)...);
   }
 
   static void NotifyNewElement(T* element) {
diff --git a/third_party/blink/renderer/platform/loader/internet_disconnected_web_url_loader.cc b/third_party/blink/renderer/platform/loader/internet_disconnected_web_url_loader.cc
index 635edb5b..ecf5a73 100644
--- a/third_party/blink/renderer/platform/loader/internet_disconnected_web_url_loader.cc
+++ b/third_party/blink/renderer/platform/loader/internet_disconnected_web_url_loader.cc
@@ -10,6 +10,7 @@
 #include "third_party/blink/public/platform/scheduler/web_resource_loading_task_runner_handle.h"
 #include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
 #include "third_party/blink/public/platform/web_url.h"
+#include "third_party/blink/public/platform/web_url_error.h"
 #include "third_party/blink/public/platform/web_url_loader_client.h"
 #include "third_party/blink/public/platform/web_url_request.h"
 #include "third_party/blink/public/platform/web_url_request_extra_data.h"
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_audio_deliverer.h b/third_party/blink/renderer/platform/mediastream/media_stream_audio_deliverer.h
index dcfbf08..b8cb825 100644
--- a/third_party/blink/renderer/platform/mediastream/media_stream_audio_deliverer.h
+++ b/third_party/blink/renderer/platform/mediastream/media_stream_audio_deliverer.h
@@ -7,6 +7,7 @@
 
 #include <algorithm>
 
+#include "base/containers/contains.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_checker.h"
 #include "base/trace_event/trace_event.h"
diff --git a/third_party/blink/renderer/platform/mhtml/mhtml_archive.cc b/third_party/blink/renderer/platform/mhtml/mhtml_archive.cc
index c02c324..bf6b198 100644
--- a/third_party/blink/renderer/platform/mhtml/mhtml_archive.cc
+++ b/third_party/blink/renderer/platform/mhtml/mhtml_archive.cc
@@ -31,6 +31,7 @@
 #include "third_party/blink/renderer/platform/mhtml/mhtml_archive.h"
 
 #include <stddef.h>
+#include "base/containers/contains.h"
 #include "base/metrics/histogram_macros.h"
 #include "build/build_config.h"
 #include "services/network/public/cpp/is_potentially_trustworthy.h"
diff --git a/third_party/blink/renderer/platform/peerconnection/transmission_encoding_info_handler.cc b/third_party/blink/renderer/platform/peerconnection/transmission_encoding_info_handler.cc
index 0ab2d62..52cbb46c 100644
--- a/third_party/blink/renderer/platform/peerconnection/transmission_encoding_info_handler.cc
+++ b/third_party/blink/renderer/platform/peerconnection/transmission_encoding_info_handler.cc
@@ -7,6 +7,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/containers/contains.h"
 #include "base/cpu.h"
 #include "base/logging.h"
 #include "base/system/sys_info.h"
diff --git a/third_party/blink/renderer/platform/weborigin/security_origin.cc b/third_party/blink/renderer/platform/weborigin/security_origin.cc
index d0483ac..9c22e00 100644
--- a/third_party/blink/renderer/platform/weborigin/security_origin.cc
+++ b/third_party/blink/renderer/platform/weborigin/security_origin.cc
@@ -34,6 +34,7 @@
 #include <string>
 #include <utility>
 
+#include "base/containers/contains.h"
 #include "net/base/url_util.h"
 #include "services/network/public/cpp/is_potentially_trustworthy.h"
 #include "third_party/blink/renderer/platform/blob/blob_url.h"
diff --git a/third_party/blink/renderer/platform/webrtc/convert_to_webrtc_video_frame_buffer.cc b/third_party/blink/renderer/platform/webrtc/convert_to_webrtc_video_frame_buffer.cc
index ab99c40..2117ca38 100644
--- a/third_party/blink/renderer/platform/webrtc/convert_to_webrtc_video_frame_buffer.cc
+++ b/third_party/blink/renderer/platform/webrtc/convert_to_webrtc_video_frame_buffer.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/platform/webrtc/convert_to_webrtc_video_frame_buffer.h"
 
 #include "base/callback_helpers.h"
+#include "base/containers/contains.h"
 #include "base/containers/span.h"
 #include "base/logging.h"
 #include "media/base/video_util.h"
diff --git a/third_party/blink/renderer/platform/webrtc/legacy_webrtc_video_frame_adapter.cc b/third_party/blink/renderer/platform/webrtc/legacy_webrtc_video_frame_adapter.cc
index 63d1cb927..aca7c83 100644
--- a/third_party/blink/renderer/platform/webrtc/legacy_webrtc_video_frame_adapter.cc
+++ b/third_party/blink/renderer/platform/webrtc/legacy_webrtc_video_frame_adapter.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/platform/webrtc/legacy_webrtc_video_frame_adapter.h"
 
 #include "base/callback_helpers.h"
+#include "base/containers/contains.h"
 #include "base/containers/span.h"
 #include "base/logging.h"
 #include "base/threading/thread_restrictions.h"
diff --git a/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.cc b/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.cc
index 041fd5a..a57b0cd 100644
--- a/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.cc
+++ b/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.cc
@@ -7,6 +7,7 @@
 #include <cmath>
 #include <vector>
 
+#include "base/containers/contains.h"
 #include "base/dcheck_is_on.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread_restrictions.h"
diff --git a/third_party/blink/renderer/platform/wtf/allocator/allocator.h b/third_party/blink/renderer/platform/wtf/allocator/allocator.h
index 3b035d0..03b0c45 100644
--- a/third_party/blink/renderer/platform/wtf/allocator/allocator.h
+++ b/third_party/blink/renderer/platform/wtf/allocator/allocator.h
@@ -376,7 +376,7 @@
 }  // namespace WTF
 
 // This version of placement new omits a 0 check.
-enum NotNullTag { NotNull };
+enum class NotNullTag { kNotNull };
 inline void* operator new(size_t, NotNullTag, void* location) {
   DCHECK(location);
   return location;
diff --git a/third_party/blink/renderer/platform/wtf/construct_traits.h b/third_party/blink/renderer/platform/wtf/construct_traits.h
index 02741c5..65f3fe1 100644
--- a/third_party/blink/renderer/platform/wtf/construct_traits.h
+++ b/third_party/blink/renderer/platform/wtf/construct_traits.h
@@ -23,7 +23,7 @@
   // placement new.
   template <typename... Args>
   static T* Construct(void* location, Args&&... args) {
-    return new (NotNull, location) T(std::forward<Args>(args)...);
+    return new (NotNullTag::kNotNull, location) T(std::forward<Args>(args)...);
   }
 
   // After constructing elements using memcopy or memmove (or similar)
diff --git a/third_party/blink/renderer/platform/wtf/hash_table.h b/third_party/blink/renderer/platform/wtf/hash_table.h
index 41c2d14c..cc1a784 100644
--- a/third_party/blink/renderer/platform/wtf/hash_table.h
+++ b/third_party/blink/renderer/platform/wtf/hash_table.h
@@ -569,7 +569,7 @@
   STATIC_ONLY(Mover);
   static void Move(T&& from, T& to) {
     to.~T();
-    new (NotNull, &to) T(std::move(from));
+    new (NotNullTag::kNotNull, &to) T(std::move(from));
   }
 };
 
@@ -579,7 +579,7 @@
   static void Move(T&& from, T& to) {
     Allocator::EnterGCForbiddenScope();
     to.~T();
-    new (NotNull, &to) T(std::move(from));
+    new (NotNullTag::kNotNull, &to) T(std::move(from));
     Allocator::LeaveGCForbiddenScope();
   }
 };
diff --git a/third_party/blink/renderer/platform/wtf/hash_traits.h b/third_party/blink/renderer/platform/wtf/hash_traits.h
index eb836152..ca5ed2a 100644
--- a/third_party/blink/renderer/platform/wtf/hash_traits.h
+++ b/third_party/blink/renderer/platform/wtf/hash_traits.h
@@ -218,7 +218,7 @@
     static const bool value = false;
   };
   static void ConstructDeletedValue(T& slot, bool) {
-    new (NotNull, &slot) T(kHashTableDeletedValue);
+    new (NotNullTag::kNotNull, &slot) T(kHashTableDeletedValue);
   }
   static bool IsDeletedValue(const T& value) {
     return value.IsHashTableDeletedValue();
@@ -310,7 +310,8 @@
   static void ConstructDeletedValue(std::unique_ptr<T>& slot, bool) {
     // Dirty trick: implant an invalid pointer to unique_ptr. Destructor isn't
     // called for deleted buckets, so this is okay.
-    new (NotNull, &slot) std::unique_ptr<T>(reinterpret_cast<T*>(1u));
+    new (NotNullTag::kNotNull, &slot)
+        std::unique_ptr<T>(reinterpret_cast<T*>(1u));
   }
   static bool IsDeletedValue(const std::unique_ptr<T>& value) {
     return value.get() == reinterpret_cast<T*>(1u);
diff --git a/third_party/blink/renderer/platform/wtf/text/string_statics.cc b/third_party/blink/renderer/platform/wtf/text/string_statics.cc
index 8652c13d..aeb0d1d2 100644
--- a/third_party/blink/renderer/platform/wtf/text/string_statics.cc
+++ b/third_party/blink/renderer/platform/wtf/text/string_statics.cc
@@ -61,8 +61,8 @@
 void AtomicString::Init() {
   DCHECK(IsMainThread());
 
-  new (NotNull, (void*)&g_null_atom) AtomicString;
-  new (NotNull, (void*)&g_empty_atom) AtomicString("");
+  new (NotNullTag::kNotNull, (void*)&g_null_atom) AtomicString;
+  new (NotNullTag::kNotNull, (void*)&g_empty_atom) AtomicString("");
 }
 
 template <unsigned charactersCount>
@@ -78,20 +78,22 @@
   DCHECK(IsMainThread());
 
   StringImpl::InitStatics();
-  new (NotNull, (void*)&g_empty_string) String(StringImpl::empty_);
-  new (NotNull, (void*)&g_empty_string16_bit) String(StringImpl::empty16_bit_);
+  new (NotNullTag::kNotNull, (void*)&g_empty_string) String(StringImpl::empty_);
+  new (NotNullTag::kNotNull, (void*)&g_empty_string16_bit)
+      String(StringImpl::empty16_bit_);
 
   // FIXME: These should be allocated at compile time.
-  new (NotNull, (void*)&g_star_atom) AtomicString("*");
-  new (NotNull, (void*)&g_xml_atom) AtomicString(AddStaticASCIILiteral("xml"));
-  new (NotNull, (void*)&g_xmlns_atom)
+  new (NotNullTag::kNotNull, (void*)&g_star_atom) AtomicString("*");
+  new (NotNullTag::kNotNull, (void*)&g_xml_atom)
+      AtomicString(AddStaticASCIILiteral("xml"));
+  new (NotNullTag::kNotNull, (void*)&g_xmlns_atom)
       AtomicString(AddStaticASCIILiteral("xmlns"));
-  new (NotNull, (void*)&g_xlink_atom)
+  new (NotNullTag::kNotNull, (void*)&g_xlink_atom)
       AtomicString(AddStaticASCIILiteral("xlink"));
-  new (NotNull, (void*)&g_xmlns_with_colon) String("xmlns:");
-  new (NotNull, (void*)&g_http_atom)
+  new (NotNullTag::kNotNull, (void*)&g_xmlns_with_colon) String("xmlns:");
+  new (NotNullTag::kNotNull, (void*)&g_http_atom)
       AtomicString(AddStaticASCIILiteral("http"));
-  new (NotNull, (void*)&g_https_atom)
+  new (NotNullTag::kNotNull, (void*)&g_https_atom)
       AtomicString(AddStaticASCIILiteral("https"));
 }
 
diff --git a/third_party/blink/renderer/platform/wtf/thread_specific.h b/third_party/blink/renderer/platform/wtf/thread_specific.h
index d691242..6d26f60 100644
--- a/third_party/blink/renderer/platform/wtf/thread_specific.h
+++ b/third_party/blink/renderer/platform/wtf/thread_specific.h
@@ -134,7 +134,7 @@
     }
 
     Set(*ptr);
-    new (NotNull, *ptr) T;
+    new (NotNullTag::kNotNull, *ptr) T;
   }
   return *ptr;
 }
diff --git a/third_party/blink/renderer/platform/wtf/vector_backed_linked_list.h b/third_party/blink/renderer/platform/wtf/vector_backed_linked_list.h
index 13e24d6..d8990c46 100644
--- a/third_party/blink/renderer/platform/wtf/vector_backed_linked_list.h
+++ b/third_party/blink/renderer/platform/wtf/vector_backed_linked_list.h
@@ -99,7 +99,8 @@
  public:
   template <typename... Args>
   static Node* Construct(void* location, Args&&... args) {
-    return new (NotNull, location) Node(std::forward<Args>(args)...);
+    return new (NotNullTag::kNotNull, location)
+        Node(std::forward<Args>(args)...);
   }
 
   static void NotifyNewElement(Node* element) {
diff --git a/third_party/blink/tools/blinkpy/common/config/builders.json b/third_party/blink/tools/blinkpy/common/config/builders.json
index ec83fda..e22e3d6 100644
--- a/third_party/blink/tools/blinkpy/common/config/builders.json
+++ b/third_party/blink/tools/blinkpy/common/config/builders.json
@@ -153,18 +153,20 @@
         "is_try_builder": true,
         "is_cq_builder":true
     },
-    "android-pie-arm64-wpt-rel-non-cq": {
-        "port_name": "android-android-pie",
-        "specifiers": [
-            "Android", "android_weblayer", "android_webview",
-            "chrome_android", "Release"],
-        "is_try_builder": true
-    },
     "android-weblayer-pie-x86-wpt-fyi-rel": {
         "port_name": "android-android-pie",
         "master": "chromium.android.fyi",
         "specifiers": [
-            "Android", "android_weblayer", "Release"]
+            "Android", "android_weblayer", "Release"
+        ]
+    },
+    "android-weblayer-pie-x86-wpt-smoketest": {
+        "port_name": "android-android-pie",
+        "master": "chromium.android.fyi",
+        "specifiers": [
+            "Android", "android_weblayer", "Release"
+        ],
+        "is_try_builder": true
     },
     "android-web-platform-pie-x86-fyi-rel": {
         "port_name": "android-android-pie",
diff --git a/third_party/blink/tools/blinkpy/w3c/android_wpt_expectations_updater.py b/third_party/blink/tools/blinkpy/w3c/android_wpt_expectations_updater.py
index 752346c8..3d05f88 100644
--- a/third_party/blink/tools/blinkpy/w3c/android_wpt_expectations_updater.py
+++ b/third_party/blink/tools/blinkpy/w3c/android_wpt_expectations_updater.py
@@ -39,12 +39,13 @@
     NEVER_FIX_MARKER_COMMENT = '# Add untriaged disabled tests in this block'
     UMBRELLA_BUG = 'crbug.com/1050754'
 
-    def __init__(self, host, args=None):
-        super(AndroidWPTExpectationsUpdater, self).__init__(host, args)
+    def __init__(self, host, args=None, wpt_manifests=None):
+        super(AndroidWPTExpectationsUpdater, self).__init__(host, args, wpt_manifests)
         self._never_fix_expectations = TestExpectations(
             self.port, {
                 ANDROID_DISABLED_TESTS:
                 host.filesystem.read_text_file(ANDROID_DISABLED_TESTS)})
+        self._baseline_expectations = TestExpectations(self.port)
 
     def expectations_files(self):
         # We need to put all the Android expectation files in
@@ -154,6 +155,17 @@
                     test=test, reason=self.UMBRELLA_BUG,
                     results={ResultType.Skip}, tags=tags, raw_tags=tags)
 
+    def _get_expectations_from_baseline(self, test_name):
+        exps_test_name = 'external/wpt/%s' % test_name
+        expectation_line = self._baseline_expectations.get_expectations(
+            exps_test_name)
+        results_from_expectation = expectation_line.results
+        if expectation_line.is_default_pass:
+            # Expectation is default pass, also check baseline expectation
+            if self.port.expected_subtest_failure(test_name):
+                results_from_expectation = set([ResultType.Failure])
+        return results_from_expectation
+
     def write_to_test_expectations(self, test_to_results):
         """Each expectations file is browser specific, and currently only
         runs on pie. Therefore we do not need any configuration specifiers
@@ -166,6 +178,9 @@
         Returns:
             Dictionary mapping test names to lists of expectation strings.
         """
+        browser_to_product = {
+            browser: product
+            for product, browser in PRODUCTS_TO_BROWSER_TAGS.items()}
         browser_to_exp_path = {
             browser: PRODUCTS_TO_EXPECTATION_FILE_PATHS[product]
             for product, browser in PRODUCTS_TO_BROWSER_TAGS.items()}
@@ -186,6 +201,7 @@
                 ANDROID_DISABLED_TESTS,
                 reduce(lambda x, y: x + y, neverfix_tests.values()))
 
+        exp_lines_dict_by_product = defaultdict(dict)
         for results_test_name, platform_results in test_to_results.items():
             exps_test_name = 'external/wpt/%s' % results_test_name
             for configs, test_results in platform_results.items():
@@ -206,15 +222,24 @@
                             r for r in test_results.actual.split()
                             if r not in test_results.expected.split()}
 
-                        if exps_test_name not in untriaged_exps[path]:
-                            untriaged_exps[path].setdefault(
-                                exps_test_name, []).append(Expectation(
-                                    test=exps_test_name, reason=self.UMBRELLA_BUG,
-                                    results=unexpected_results))
-                        else:
-                            exp = untriaged_exps[path][exps_test_name][0]
-                            exp.add_expectations(
-                                unexpected_results, reason=self.UMBRELLA_BUG)
+                        # as we are using override expectations for Android
+                        # side, do not create override expectations if it is a
+                        # subset of default expectations or baseline
+                        default_expectation = \
+                            self._get_expectations_from_baseline(results_test_name)
+                        if unexpected_results.issubset(default_expectation):
+                            continue
+
+                        # Test expectations for modified test cases are already
+                        # deleted, so all tests should be new test
+                        expectation = Expectation(
+                            test=exps_test_name, reason=self.UMBRELLA_BUG,
+                            results=unexpected_results)
+                        product = browser_to_product[config.browser]
+                        exp_lines_dict_by_product[product][exps_test_name] = \
+                            expectation.to_string()
+                        untriaged_exps[path].setdefault(
+                            exps_test_name, []).append(expectation)
 
         for path in untriaged_exps:
             marker_lineno = self._get_marker_line_number(
@@ -240,9 +265,9 @@
         self._test_expectations.commit_changes()
         self._never_fix_expectations.commit_changes()
 
-        # TODO(rmhasan): Return dictionary mapping test names to lists of
-        # test expectation strings.
-        return {}
+        # returns dictionary mapping product to dictionary that maps test names
+        # to test expectation strings.
+        return exp_lines_dict_by_product
 
     def _is_wpt_test(self, _):
         """On Android we use the wpt executable. The test results do not include
diff --git a/third_party/blink/tools/blinkpy/w3c/android_wpt_expectations_updater_unittest.py b/third_party/blink/tools/blinkpy/w3c/android_wpt_expectations_updater_unittest.py
index a62e9ad..a5400cd 100644
--- a/third_party/blink/tools/blinkpy/w3c/android_wpt_expectations_updater_unittest.py
+++ b/third_party/blink/tools/blinkpy/w3c/android_wpt_expectations_updater_unittest.py
@@ -26,23 +26,16 @@
 CHROME_ANDROID_WPT_STEP = PRODUCTS_TO_STEPNAMES[CHROME_ANDROID]
 
 class AndroidWPTExpectationsUpdaterTest(LoggingTestCase):
-
-    _raw_android_expectations = (
+    _raw_baseline_expectations = (
         '# results: [ Failure Crash Timeout]\n'
         '\n'
-        '# Add untriaged failures in this block\n'
-        'external/wpt/abc.html [ Failure ]\n'
-        'crbug.com/1050754 external/wpt/def.html [ Crash ]\n'
-        'crbug.com/1050754 external/wpt/ghi.html [ Timeout ]\n'
-        'crbug.com/1111111 external/wpt/jkl.html [ Failure ]\n'
-        'external/wpt/www.html [ Crash Failure ]\n'
-        'crbug.com/1050754 external/wpt/cat.html [ Failure ]\n'
-        'external/wpt/dog.html [ Crash Timeout ]\n'
-        'crbug.com/6789043 external/wpt/van.html [ Failure ]\n'
-        'external/wpt/unexpected_pass.html [ Failure ]\n'
-        '\n'
-        '# This comment will not be deleted\n'
-        'crbug.com/111111 external/wpt/hello_world.html [ Crash ]\n')
+        'crbug.com/1111111 external/wpt/new1.html [ Failure Timeout ]\n')
+
+    # baseline for external/wpt/new2.html
+    _raw_expected_text = (
+        'This is a testharness.js-based test.\n'
+        'FAIL a failed subtest\n'
+        'Harness: the test ran to completion.\n')
 
     _raw_android_never_fix_tests = (
         '# tags: [ android-weblayer android-webview chrome-android ]\n'
@@ -51,7 +44,7 @@
         '# Add untriaged disabled tests in this block\n'
         'crbug.com/1050754 [ android-webview ] external/wpt/disabled.html [ Skip ]\n')
 
-    def _setup_host(self):
+    def _setup_host(self, raw_android_expectations):
         """Returns a mock host with fake values set up for testing."""
         self.set_logging_level(logging.DEBUG)
         host = MockHost()
@@ -60,168 +53,72 @@
 
         # Set up a fake list of try builders.
         host.builders = BuilderList({
-            'MOCK Try Precise': {
-                'port_name': 'test-linux-precise',
-                'specifiers': ['Precise', 'Release'],
-                'is_try_builder': True,
-            },
             'MOCK Android Weblayer - Pie': {
                 'port_name': 'test-android-pie',
                 'specifiers': ['Precise', 'Release',
                                'anDroid', 'android_Weblayer'],
                 'is_try_builder': True,
             },
-            'MOCK Android Pie': {
-                'port_name': 'test-android-pie',
-                'specifiers': ['Precise', 'Release', 'anDroid',
-                               'Android_Webview', 'Chrome_Android'],
-                'is_try_builder': True,
-            },
         })
+
         host.filesystem.write_text_file(
             host.port_factory.get().web_tests_dir() + '/external/' +
             BASE_MANIFEST_NAME,
             json.dumps({
                 'items': {
                     'testharness': {
-                        'ghi.html': ['abcdef123', [None, {}]],
-                        'van.html': ['abcdef123', [None, {}]],
+                        'foo1.html': ['abcdef123', [None, {}]],
+                        'foo2.html': ['abcdef123', [None, {}]],
+                        'bar.html': ['abcdef123', [None, {}]],
                     },
                 },
             }))
 
         # Write dummy expectations
+        path = host.port_factory.get().web_tests_dir() + '/TestExpectations'
+        host.filesystem.write_text_file(
+            path, self._raw_baseline_expectations)
+        path = host.port_factory.get().web_tests_dir() + '/new2-expected.txt'
+        host.filesystem.write_text_file(
+            path, self._raw_expected_text)
+
         for path in PRODUCTS_TO_EXPECTATION_FILE_PATHS.values():
             host.filesystem.write_text_file(
-                path, self._raw_android_expectations)
+                path, raw_android_expectations)
 
         host.filesystem.write_text_file(
             ANDROID_DISABLED_TESTS, self._raw_android_never_fix_tests)
         return host
 
-    def testUpdateTestExpectationsForWebview(self):
-        host = self._setup_host()
-        host.results_fetcher.set_results(
-            Build('MOCK Android Pie', 123),
-            WebTestResults({
-                'tests': {
-                    'abc.html': {
-                        'expected': 'PASS',
-                        'actual': 'CRASH TIMEOUT',
-                        'is_unexpected': True,
-                    },
-                    'jkl.html': {
-                        'expected': 'PASS',
-                        'actual': 'FAIL',
-                        'is_unexpected': True,
-                    },
-                    'cat.html': {
-                        'expected': 'PASS',
-                        'actual': 'CRASH CRASH TIMEOUT',
-                        'is_unexpected': True,
-                    },
-                    'unexpected_pass.html': {
-                        'expected': 'FAIL',
-                        'actual': 'PASS',
-                        'is_unexpected': True
-                    },
-                    'dog.html': {
-                        'expected': 'SKIP',
-                        'actual': 'SKIP',
-                        'is_unexpected': True,
-                    },
-                },
-            }, step_name=WEBVIEW_WPT_STEP + ' (with patch)'),
-            step_name=WEBVIEW_WPT_STEP + ' (with patch)')
-        updater = AndroidWPTExpectationsUpdater(
-            host, ['-vvv',  '--android-product', ANDROID_WEBVIEW,
-                   '--clean-up-test-expectations',
-                   '--clean-up-affected-tests-only',
-                   '--include-unexpected-pass'])
-        updater.git_cl = MockGitCL(host, {
-            Build('MOCK Android Pie', 123):
-            TryJobStatus('COMPLETED', 'FAILURE')})
-        # Run command
-        updater.run()
-        # Get new expectations
-        content = host.filesystem.read_text_file(
-            PRODUCTS_TO_EXPECTATION_FILE_PATHS[ANDROID_WEBVIEW])
-        self.assertEqual(
-            content,
-            ('# results: [ Failure Crash Timeout]\n'
-             '\n'
-             '# Add untriaged failures in this block\n'
-             'crbug.com/1050754 external/wpt/abc.html [ Crash Failure Timeout ]\n'
-             'crbug.com/1050754 external/wpt/cat.html [ Crash Failure Timeout ]\n'
-             'crbug.com/1050754 external/wpt/def.html [ Crash ]\n'
-             'external/wpt/dog.html [ Crash Timeout ]\n'
-             'crbug.com/1050754 external/wpt/ghi.html [ Timeout ]\n'
-             'crbug.com/1111111 crbug.com/1050754'
-             ' external/wpt/jkl.html [ Failure ]\n'
-             'crbug.com/1050754 external/wpt/unexpected_pass.html [ Failure Pass ]\n'
-             'crbug.com/6789043 external/wpt/van.html [ Failure ]\n'
-             'external/wpt/www.html [ Crash Failure ]\n'
-             '\n'
-             '# This comment will not be deleted\n'
-             'crbug.com/111111 external/wpt/hello_world.html [ Crash ]\n'))
-        neverfix_content = host.filesystem.read_text_file(
-            ANDROID_DISABLED_TESTS)
-        self.assertEqual(
-            neverfix_content,
-            ('# tags: [ android-weblayer android-webview chrome-android ]\n'
-             '# results: [ Skip ]\n'
-             '\n'
-             '# Add untriaged disabled tests in this block\n'
-             'crbug.com/1050754 [ android-webview ] external/wpt/disabled.html [ Skip ]\n'
-             'crbug.com/1050754 [ android-webview ] external/wpt/dog.html [ Skip ]\n'))
-        # check that chrome android's expectation file was not modified
-        # since the same bot is used to update chrome android & webview
-        # expectations
-        self.assertEqual(
-            host.filesystem.read_text_file(
-                PRODUCTS_TO_EXPECTATION_FILE_PATHS[CHROME_ANDROID]),
-            self._raw_android_expectations)
-        # Check logs
-        logs = ''.join(self.logMessages()).lower()
-        self.assertNotIn(WEBLAYER_WPT_STEP, logs)
-        self.assertNotIn(CHROME_ANDROID_WPT_STEP, logs)
-        # Check that weblayer and chrome expectation files were not changed
-        self.assertEqual(
-            self._raw_android_expectations,
-            host.filesystem.read_text_file(
-                PRODUCTS_TO_EXPECTATION_FILE_PATHS[CHROME_ANDROID]))
-        self.assertEqual(
-            self._raw_android_expectations,
-            host.filesystem.read_text_file(
-                PRODUCTS_TO_EXPECTATION_FILE_PATHS[ANDROID_WEBLAYER]))
-
     def testUpdateTestExpectationsForWeblayer(self):
-        host = self._setup_host()
+        raw_android_expectations = (
+            '# results: [ Failure Crash Timeout]\n'
+            '\n'
+            'crbug.com/1000754 external/wpt/foo.html [ Failure ]\n'
+            '\n'
+            '# Add untriaged failures in this block\n'
+            'crbug.com/1050754 external/wpt/bar.html [ Failure ]\n'
+            '\n'
+            '# This comment will not be deleted\n')
+        host = self._setup_host(raw_android_expectations)
         host.results_fetcher.set_results(
             Build('MOCK Android Weblayer - Pie', 123),
             WebTestResults({
                 'tests': {
-                    'abc.html': {
-                        'expected': 'PASS',
-                        'actual': 'CRASH TIMEOUT',
-                        'is_unexpected': True,
-                    },
-                    'jkl.html': {
+                    # A test result covered by default expectation
+                    'new1.html': {
                         'expected': 'PASS',
                         'actual': 'FAIL',
                         'is_unexpected': True,
                     },
-                    'cat.html': {
+                    # A test result covered by baseline
+                    'new2.html': {
                         'expected': 'PASS',
-                        'actual': 'CRASH CRASH TIMEOUT',
+                        'actual': 'FAIL',
                         'is_unexpected': True,
                     },
-                    'unexpected_pass.html': {
-                        'expected': 'FAIL',
-                        'actual': 'PASS',
-                        'is_unexpected': True,
-                    },
-                    'new.html': {
+                    # A new test case
+                    'new3.html': {
                         'expected': 'PASS',
                         'actual': 'CRASH CRASH FAIL',
                         'is_unexpected': True,
@@ -231,8 +128,6 @@
             step_name=WEBLAYER_WPT_STEP + ' (with patch)')
         updater = AndroidWPTExpectationsUpdater(
             host, ['-vvv', '--android-product', ANDROID_WEBLAYER,
-                   '--clean-up-test-expectations',
-                   '--clean-up-affected-tests-only',
                    '--include-unexpected-pass'])
         updater.git_cl = MockGitCL(host, {
             Build('MOCK Android Weblayer - Pie', 123):
@@ -242,38 +137,19 @@
         # Get new expectations
         content = host.filesystem.read_text_file(
             PRODUCTS_TO_EXPECTATION_FILE_PATHS[ANDROID_WEBLAYER])
-        self.assertEqual(
-            content,
-            ('# results: [ Failure Crash Timeout]\n'
-             '\n'
-             '# Add untriaged failures in this block\n'
-             'crbug.com/1050754 external/wpt/abc.html [ Crash Failure Timeout ]\n'
-             'crbug.com/1050754 external/wpt/cat.html [ Crash Failure Timeout ]\n'
-             'crbug.com/1050754 external/wpt/def.html [ Crash ]\n'
-             'external/wpt/dog.html [ Crash Timeout ]\n'
-             'crbug.com/1050754 external/wpt/ghi.html [ Timeout ]\n'
-             'crbug.com/1111111 crbug.com/1050754'
-             ' external/wpt/jkl.html [ Failure ]\n'
-             'crbug.com/1050754 external/wpt/new.html [ Failure Crash ]\n'
-             'crbug.com/1050754 external/wpt/unexpected_pass.html [ Failure Pass ]\n'
-             'crbug.com/6789043 external/wpt/van.html [ Failure ]\n'
-             'external/wpt/www.html [ Crash Failure ]\n'
-             '\n'
-             '# This comment will not be deleted\n'
-             'crbug.com/111111 external/wpt/hello_world.html [ Crash ]\n'))
-        # Check logs
-        logs = ''.join(self.logMessages()).lower()
-        self.assertNotIn(WEBVIEW_WPT_STEP, logs)
-        self.assertNotIn(CHROME_ANDROID_WPT_STEP, logs)
-        # Check that webview and chrome expectation files were not changed
-        self.assertEqual(
-            self._raw_android_expectations,
-            host.filesystem.read_text_file(
-                PRODUCTS_TO_EXPECTATION_FILE_PATHS[CHROME_ANDROID]))
-        self.assertEqual(
-            self._raw_android_expectations,
-            host.filesystem.read_text_file(
-                PRODUCTS_TO_EXPECTATION_FILE_PATHS[ANDROID_WEBVIEW]))
+        _new_expectations = (
+            '# results: [ Failure Crash Timeout]\n'
+            '\n'
+            'crbug.com/1000754 external/wpt/foo.html [ Failure ]\n'
+            '\n'
+            '# Add untriaged failures in this block\n'
+            'crbug.com/1050754 external/wpt/bar.html [ Failure ]\n'
+            'crbug.com/1050754 external/wpt/new3.html [ Failure Crash ]\n'
+            '\n'
+            '# This comment will not be deleted\n')
+        self.assertEqual(content, _new_expectations)
+
+        # Check that ANDROID_DISABLED_TESTS expectation files were not changed
         self.assertEqual(
             self._raw_android_never_fix_tests,
             host.filesystem.read_text_file(ANDROID_DISABLED_TESTS))
@@ -281,110 +157,53 @@
     def testCleanupAndUpdateTestExpectationsForAll(self):
         # Full integration test for expectations cleanup and update
         # using builder results.
-        host = self._setup_host()
+        raw_android_expectations = (
+            '# results: [ Failure Crash Timeout]\n'
+            '\n'
+            'crbug.com/1000754 external/wpt/foo1.html [ Failure ]\n'
+            'crbug.com/1000754 external/wpt/foo2.html [ Failure ]\n'
+            'crbug.com/1000754 external/wpt/bar.html [ Failure ]\n'
+            '\n'
+            '# Add untriaged failures in this block\n'
+            '\n'
+            '# This comment will not be deleted\n')
+        host = self._setup_host(raw_android_expectations)
         # Add results for Weblayer
         host.results_fetcher.set_results(
             Build('MOCK Android Weblayer - Pie', 123),
             WebTestResults({
                 'tests': {
-                    'abc.html': {
-                        'expected': 'PASS',
-                        'actual': 'CRASH TIMEOUT',
-                        'is_unexpected': True,
-                    },
-                    'weblayer_only.html': {
-                        'expected': 'PASS',
-                        'actual': 'CRASH CRASH FAIL',
-                        'is_unexpected': True,
-                    },
                     'disabled_weblayer_only.html': {
                         'expected': 'SKIP',
                         'actual': 'SKIP',
                         'is_unexpected': True,
                     },
-                    'unexpected_pass.html': {
+                    'bar.html': {
                         'expected': 'FAIL',
-                        'actual': 'PASS',
+                        'actual': 'CRASH',
                         'is_unexpected': True
                     },
                 },
             }, step_name=WEBLAYER_WPT_STEP + ' (with patch)'),
             step_name=WEBLAYER_WPT_STEP + ' (with patch)')
-        # Add Results for Webview
-        host.results_fetcher.set_results(
-            Build('MOCK Android Pie', 101),
-            WebTestResults({
-                'tests': {
-                    'cat.html': {
-                        'expected': 'PASS',
-                        'actual': 'CRASH FAIL TIMEOUT',
-                        'is_unexpected': True,
-                    },
-                    'webview_only.html': {
-                        'expected': 'PASS',
-                        'actual': 'TIMEOUT',
-                        'is_unexpected': True,
-                    },
-                    'disabled.html': {
-                        'expected': 'SKIP',
-                        'actual': 'SKIP',
-                    },
-                    'unexpected_pass.html': {
-                        'expected': 'FAIL',
-                        'actual': 'PASS',
-                        'is_unexpected': True
-                    },
-                },
-            }, step_name=WEBVIEW_WPT_STEP + ' (with patch)'),
-            step_name=WEBVIEW_WPT_STEP + ' (with patch)')
-        # Add Results for Chrome
-        host.results_fetcher.set_results(
-            Build('MOCK Android Pie', 101),
-            WebTestResults({
-                'tests': {
-                    'jkl.html': {
-                        'expected': 'PASS',
-                        'actual': 'FAIL',
-                        'is_unexpected': True,
-                    },
-                    'chrome_only.html': {
-                        'expected': 'PASS',
-                        'actual': 'CRASH CRASH TIMEOUT',
-                        'is_unexpected': True,
-                    },
-                    'disabled.html': {
-                        'expected': 'SKIP',
-                        'actual': 'SKIP',
-                        'is_unexpected': True,
-                    },
-                    'unexpected_pass.html': {
-                        'expected': 'FAIL',
-                        'actual': 'PASS',
-                        'is_unexpected': True
-                    },
-                },
-            }, step_name=CHROME_ANDROID_WPT_STEP + ' (with patch)'),
-            step_name=CHROME_ANDROID_WPT_STEP + ' (with patch)')
         updater = AndroidWPTExpectationsUpdater(
             host, ['-vvv',
                    '--clean-up-test-expectations',
                    '--clean-up-affected-tests-only',
                    '--include-unexpected-pass',
-                   '--android-product', ANDROID_WEBLAYER,
-                   '--android-product', CHROME_ANDROID,
-                   '--android-product', ANDROID_WEBVIEW])
+                   '--android-product', ANDROID_WEBLAYER])
 
         def _git_command_return_val(cmd):
             if '--diff-filter=D' in cmd:
-                return 'external/wpt/ghi.html'
+                return 'external/wpt/foo2.html'
             if '--diff-filter=R' in cmd:
-                return 'C external/wpt/van.html external/wpt/wagon.html'
+                return 'C external/wpt/foo1.html external/wpt/foo3.html'
+            if '--diff-filter=M' in cmd:
+                return 'external/wpt/bar.html'
             return ''
 
         updater.git_cl = MockGitCL(host, {
             Build('MOCK Android Weblayer - Pie', 123):
-            TryJobStatus('COMPLETED', 'FAILURE'),
-            Build('MOCK Android Pie', 101):
             TryJobStatus('COMPLETED', 'FAILURE')})
 
         updater.git.run = _git_command_return_val
@@ -392,67 +211,21 @@
 
         # Run command
         updater.run()
+
         # Check expectations for weblayer
         content = host.filesystem.read_text_file(
             PRODUCTS_TO_EXPECTATION_FILE_PATHS[ANDROID_WEBLAYER])
-        self.assertEqual(
-            content,
-            ('# results: [ Failure Crash Timeout]\n'
-             '\n'
-             '# Add untriaged failures in this block\n'
-             'crbug.com/1050754 external/wpt/abc.html [ Crash Failure Timeout ]\n'
-             'crbug.com/1050754 external/wpt/cat.html [ Failure ]\n'
-             'crbug.com/1050754 external/wpt/def.html [ Crash ]\n'
-             'external/wpt/dog.html [ Crash Timeout ]\n'
-             'crbug.com/1111111 external/wpt/jkl.html [ Failure ]\n'
-             'crbug.com/1050754 external/wpt/unexpected_pass.html [ Failure Pass ]\n'
-             'crbug.com/6789043 external/wpt/wagon.html [ Failure ]\n'
-             'crbug.com/1050754 external/wpt/weblayer_only.html [ Failure Crash ]\n'
-             'external/wpt/www.html [ Crash Failure ]\n'
-             '\n'
-             '# This comment will not be deleted\n'
-             'crbug.com/111111 external/wpt/hello_world.html [ Crash ]\n'))
-        # Check expectations for webview
-        content = host.filesystem.read_text_file(
-            PRODUCTS_TO_EXPECTATION_FILE_PATHS[ANDROID_WEBVIEW])
-        self.assertEqual(
-            content,
-            ('# results: [ Failure Crash Timeout]\n'
-             '\n'
-             '# Add untriaged failures in this block\n'
-             'external/wpt/abc.html [ Failure ]\n'
-             'crbug.com/1050754 external/wpt/cat.html [ Crash Failure Timeout ]\n'
-             'crbug.com/1050754 external/wpt/def.html [ Crash ]\n'
-             'external/wpt/dog.html [ Crash Timeout ]\n'
-             'crbug.com/1111111 external/wpt/jkl.html [ Failure ]\n'
-             'crbug.com/1050754 external/wpt/unexpected_pass.html [ Failure Pass ]\n'
-             'crbug.com/6789043 external/wpt/wagon.html [ Failure ]\n'
-             'crbug.com/1050754 external/wpt/webview_only.html [ Timeout ]\n'
-             'external/wpt/www.html [ Crash Failure ]\n'
-             '\n'
-             '# This comment will not be deleted\n'
-             'crbug.com/111111 external/wpt/hello_world.html [ Crash ]\n'))
-        # Check expectations chrome
-        content = host.filesystem.read_text_file(
-            PRODUCTS_TO_EXPECTATION_FILE_PATHS[CHROME_ANDROID])
-        self.assertEqual(
-            content,
-            ('# results: [ Failure Crash Timeout]\n'
-             '\n'
-             '# Add untriaged failures in this block\n'
-             'external/wpt/abc.html [ Failure ]\n'
-             'crbug.com/1050754 external/wpt/cat.html [ Failure ]\n'
-             'crbug.com/1050754 external/wpt/chrome_only.html [ Crash Timeout ]\n'
-             'crbug.com/1050754 external/wpt/def.html [ Crash ]\n'
-             'external/wpt/dog.html [ Crash Timeout ]\n'
-             'crbug.com/1111111 crbug.com/1050754'
-             ' external/wpt/jkl.html [ Failure ]\n'
-             'crbug.com/1050754 external/wpt/unexpected_pass.html [ Failure Pass ]\n'
-             'crbug.com/6789043 external/wpt/wagon.html [ Failure ]\n'
-             'external/wpt/www.html [ Crash Failure ]\n'
-             '\n'
-             '# This comment will not be deleted\n'
-             'crbug.com/111111 external/wpt/hello_world.html [ Crash ]\n'))
+        _new_expectations = (
+            '# results: [ Failure Crash Timeout]\n'
+            '\n'
+            'crbug.com/1000754 external/wpt/foo3.html [ Failure ]\n'
+            '\n'
+            '# Add untriaged failures in this block\n'
+            'crbug.com/1050754 external/wpt/bar.html [ Crash ]\n'
+            '\n'
+            '# This comment will not be deleted\n')
+        self.assertEqual(content, _new_expectations)
+
         # Check disabled test file
         neverfix_content = host.filesystem.read_text_file(ANDROID_DISABLED_TESTS)
         self.assertEqual(
@@ -462,5 +235,4 @@
              '\n'
              '# Add untriaged disabled tests in this block\n'
              'crbug.com/1050754 [ android-webview ] external/wpt/disabled.html [ Skip ]\n'
-             'crbug.com/1050754 [ chrome-android ] external/wpt/disabled.html [ Skip ]\n'
              'crbug.com/1050754 [ android-weblayer ] external/wpt/disabled_weblayer_only.html [ Skip ]\n'))
diff --git a/third_party/blink/tools/blinkpy/w3c/import_notifier.py b/third_party/blink/tools/blinkpy/w3c/import_notifier.py
index 9169fe5..dbcbb056 100644
--- a/third_party/blink/tools/blinkpy/w3c/import_notifier.py
+++ b/third_party/blink/tools/blinkpy/w3c/import_notifier.py
@@ -19,6 +19,8 @@
 from blinkpy.w3c.directory_owners_extractor import DirectoryOwnersExtractor
 from blinkpy.w3c.monorail import MonorailAPI, MonorailIssue
 from blinkpy.w3c.wpt_expectations_updater import WPTExpectationsUpdater
+from blinkpy.web_tests.port.android import (
+    PRODUCTS, ANDROID_WEBLAYER)
 
 _log = logging.getLogger(__name__)
 
@@ -36,12 +38,17 @@
         self.finder = PathFinder(host.filesystem)
         self.owners_extractor = DirectoryOwnersExtractor(host)
         self.new_failures_by_directory = defaultdict(list)
+        self.components_for_product = {ANDROID_WEBLAYER: ["Internals>WebLayer"]}
+        self.labels_for_product = {
+            ANDROID_WEBLAYER: ["Project-WebLayer-WebPlatformSupport", "WL-WPT-Compat"]
+        }
 
     def main(self,
              wpt_revision_start,
              wpt_revision_end,
              rebaselined_tests,
              test_expectations,
+             new_override_expectations,
              issue,
              patchset,
              dry_run=True,
@@ -78,6 +85,14 @@
                                                   wpt_revision_end, gerrit_url)
         self.file_bugs(bugs, dry_run, service_account_key_json)
 
+        for product, expectation_lines in new_override_expectations.items():
+            bugs = self.create_bugs_for_product(wpt_revision_start,
+                                                wpt_revision_end,
+                                                gerrit_url,
+                                                product,
+                                                expectation_lines)
+            self.file_bugs(bugs, dry_run, service_account_key_json)
+
     def find_changed_baselines_of_tests(self, rebaselined_tests):
         """Finds the corresponding changed baselines of each test.
 
@@ -172,6 +187,52 @@
                         test_name,
                         expectation_line=expectation_line))
 
+    def create_bugs_for_product(self, wpt_revision_start, wpt_revision_end,
+                                gerrit_url, product, expectation_lines):
+        """Files bug reports for new failures per product
+
+        Args:
+            wpt_revision_start: The start of the imported WPT revision range
+                (exclusive), i.e. the last imported revision.
+            wpt_revision_end: The end of the imported WPT revision range
+                (inclusive), i.e. the current imported revision.
+            gerrit_url: Gerrit URL of the CL.
+            product: the product for which to file bugs for.
+            expectation_lines: list of new expectations for this product
+
+        Return:
+            A MonorailIssue object that should be filed.
+        """
+        bugs = []
+        summary = '[WPT] New failures introduced by import {}'.format(gerrit_url)
+
+        prologue = ('WPT import {} introduced new failures:\n\n'
+                    'List of new failures:\n'.format(gerrit_url))
+
+        failure_list = ''
+        for _, failure in expectation_lines.items():
+            failure_list += str(failure) + '\n'
+
+        expectations_statement = (
+            '\nExpectations have been automatically added for '
+            'the failing results to keep the bots green. Please '
+            'investigate the new failures and triage as appropriate.\n')
+
+        range_statement = '\nThis import contains upstream changes from {} to {}:\n'.format(
+            wpt_revision_start, wpt_revision_end)
+
+        description = (prologue + failure_list + expectations_statement +
+                       range_statement)
+
+        bug = MonorailIssue.new_chromium_issue(
+            summary,
+            description,
+            cc=[],
+            components=self.components_for_product[product],
+            labels=self.labels_for_product[product])
+        bugs.append(bug)
+        return bugs
+
     def create_bugs_from_new_failures(self, wpt_revision_start,
                                       wpt_revision_end, gerrit_url):
         """Files bug reports for new failures.
diff --git a/third_party/blink/tools/blinkpy/w3c/import_notifier_unittest.py b/third_party/blink/tools/blinkpy/w3c/import_notifier_unittest.py
index 3d4babb..a961b8f0 100644
--- a/third_party/blink/tools/blinkpy/w3c/import_notifier_unittest.py
+++ b/third_party/blink/tools/blinkpy/w3c/import_notifier_unittest.py
@@ -260,6 +260,21 @@
             self.notifier.find_owned_directory(
                 'virtual/gpu/external/wpt/foo/bar.html'), 'external/wpt/foo')
 
+    def test_create_bugs_for_product(self):
+        expectation_lines = {}
+        expectation_lines['external/wpt/foo/baz.html'] = \
+            'crbug/123456 external/wpt/foo/baz.html [ Failure ]'
+
+        bugs = self.notifier.create_bugs_for_product(
+            'SHA_START', 'SHA_END', 'https://crrev.com/c/12345',
+            'android_weblayer', expectation_lines)
+
+        self.assertEqual(len(bugs), 1)
+        self.assertEqual(bugs[0].body['components'], ['Internals>WebLayer'])
+        self.assertEqual(
+            bugs[0].body['summary'],
+            '[WPT] New failures introduced by import https://crrev.com/c/12345')
+
     def test_create_bugs_from_new_failures(self):
         self.host.filesystem.write_text_file(
             MOCK_WEB_TESTS + 'external/wpt/foo/OWNERS', 'foolip@chromium.org')
diff --git a/third_party/blink/tools/blinkpy/w3c/test_importer.py b/third_party/blink/tools/blinkpy/w3c/test_importer.py
index 520ddf719..c6dab87 100644
--- a/third_party/blink/tools/blinkpy/w3c/test_importer.py
+++ b/third_party/blink/tools/blinkpy/w3c/test_importer.py
@@ -21,6 +21,7 @@
 from blinkpy.common.path_finder import PathFinder
 from blinkpy.common.system.executive import ScriptError
 from blinkpy.common.system.log_utils import configure_logging
+from blinkpy.w3c.android_wpt_expectations_updater import AndroidWPTExpectationsUpdater
 from blinkpy.w3c.chromium_exportable_commits import exportable_commits_over_last_n_commits
 from blinkpy.w3c.common import read_credentials, is_testharness_baseline, is_file_exportable, WPT_GH_URL
 from blinkpy.w3c.directory_owners_extractor import DirectoryOwnersExtractor
@@ -69,6 +70,9 @@
         # wpt_expectations_updater.SimpleTestResult.
         self.rebaselined_tests = set()
         self.new_test_expectations = {}
+        # New override expectations for Android targets. A dictionary mapping
+        # products to dictionary that maps test names to test expectation lines
+        self.new_override_expectations = {}
         self.verbose = False
 
         args = [
@@ -82,6 +86,13 @@
         self._expectations_updater = WPTExpectationsUpdater(
             self.host, args, wpt_manifests)
 
+        args = [
+            '--android-product',
+            'android_weblayer'
+        ]
+        self._android_expectations_updater = AndroidWPTExpectationsUpdater(
+            self.host, args, wpt_manifests)
+
     def main(self, argv=None):
         # TODO(robertma): Test this method! Split it to make it easier to test
         # if necessary.
@@ -181,14 +192,15 @@
             _log.info('Only manifest was updated; skipping the import.')
             return 0
 
-        self._commit_changes(commit_message)
-        _log.info('Changes imported and committed.')
+        with self._expectations_updater.prepare_smoke_tests():
+            self._commit_changes(commit_message)
+            _log.info('Changes imported and committed.')
 
-        if not options.auto_upload and not options.auto_update:
-            return 0
+            if not options.auto_upload and not options.auto_update:
+                return 0
 
-        self._upload_cl()
-        _log.info('Issue: %s', self.git_cl.run(['issue']).strip())
+            self._upload_cl()
+            _log.info('Issue: %s', self.git_cl.run(['issue']).strip())
 
         if not self.update_expectations_for_cl():
             return 1
@@ -236,6 +248,7 @@
 
         if try_results and self.git_cl.some_failed(try_results):
             self.fetch_new_expectations_and_baselines()
+            self.fetch_wpt_override_expectations()
             if self.chromium_git.has_working_directory_changes():
                 self._generate_manifest()
                 message = 'Update test expectations and baselines.'
@@ -307,8 +320,7 @@
 
     def blink_try_bots(self):
         """Returns the collection of builders used for updating expectations."""
-        return self.host.builders.filter_builders(
-            is_try=True, exclude_specifiers={'android'})
+        return self.host.builders.filter_builders(is_try=True)
 
     def parse_args(self, argv):
         parser = argparse.ArgumentParser()
@@ -632,6 +644,19 @@
         self.rebaselined_tests, self.new_test_expectations = (
             self._expectations_updater.update_expectations())
 
+    def fetch_wpt_override_expectations(self):
+        """Modifies WPT Override expectations based on try job results.
+
+        Assuming that there are some try job results available, this
+        adds new expectation lines to WPT Override Expectation files,
+        e.g. WebLayerWPTOverrideExpectations
+
+        This is the same as invoking the `wpt-update-expectations` script.
+        """
+        _log.info('Adding test expectations lines to Override Expectations.')
+        _, self.new_override_expectations = (
+            self._android_expectations_updater.update_expectations())
+
     def _get_last_imported_wpt_revision(self):
         """Finds the last imported WPT revision."""
         # TODO(robertma): Only match commit subjects.
@@ -656,6 +681,7 @@
             self.wpt_revision,
             self.rebaselined_tests,
             self.new_test_expectations,
+            self.new_override_expectations,
             issue,
             patchset,
             dry_run=not auto_file_bugs,
diff --git a/third_party/blink/tools/blinkpy/w3c/test_importer_unittest.py b/third_party/blink/tools/blinkpy/w3c/test_importer_unittest.py
index d0da7615..e62539e 100644
--- a/third_party/blink/tools/blinkpy/w3c/test_importer_unittest.py
+++ b/third_party/blink/tools/blinkpy/w3c/test_importer_unittest.py
@@ -22,6 +22,7 @@
 from blinkpy.w3c.wpt_github_mock import MockWPTGitHub
 from blinkpy.w3c.wpt_manifest import BASE_MANIFEST_NAME
 from blinkpy.web_tests.port.android import PRODUCTS_TO_EXPECTATION_FILE_PATHS
+from blinkpy.web_tests.port.android import ANDROID_DISABLED_TESTS
 
 MOCK_WEB_TESTS = '/mock-checkout/' + RELATIVE_WEB_TESTS
 MANIFEST_INSTALL_CMD = [
@@ -36,6 +37,7 @@
         host = MockHost()
         for path in PRODUCTS_TO_EXPECTATION_FILE_PATHS.values():
             host.filesystem.write_text_file(path, '')
+        host.filesystem.write_text_file(ANDROID_DISABLED_TESTS, '')
         return host
 
     @staticmethod
@@ -108,6 +110,7 @@
                 Build('builder-a', 123): TryJobStatus('COMPLETED', 'FAILURE'),
             })
         importer.fetch_new_expectations_and_baselines = lambda: None
+        importer.fetch_wpt_override_expectations = lambda: None
         success = importer.update_expectations_for_cl()
         self.assertTrue(success)
         self.assertLog([
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py
index 0e30f14..02a6990a 100644
--- a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py
+++ b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py
@@ -9,9 +9,13 @@
 """
 
 import argparse
+import contextlib
 import copy
 import logging
+import os
 import re
+import shutil
+import tempfile
 from collections import defaultdict, namedtuple
 
 from blinkpy.common.memoized import memoized
@@ -19,9 +23,10 @@
 from blinkpy.common.path_finder import PathFinder
 from blinkpy.common.system.executive import ScriptError
 from blinkpy.common.system.log_utils import configure_logging
+from blinkpy.w3c.wpt_manifest import WPTManifest, BASE_MANIFEST_NAME
 from blinkpy.web_tests.models.test_expectations import TestExpectations
 from blinkpy.web_tests.port.android import (
-    PRODUCTS, PRODUCTS_TO_EXPECTATION_FILE_PATHS)
+    PRODUCTS, PRODUCTS_TO_EXPECTATION_FILE_PATHS, WPT_SMOKE_TESTS_FILE)
 
 _log = logging.getLogger(__name__)
 
@@ -237,7 +242,7 @@
         # same OS or all builders), so we are usually over-expecting.
         for config_no_result in configs_with_no_results:
             _log.warning("No results for %s, inheriting from other builds" %
-                         config_no_result)
+                         str(config_no_result))
             for test_name in test_expectations:
                 # The union of all other actual statuses is used when there is
                 # no similar OS to inherit from (eg: no results on Linux, and
@@ -780,6 +785,46 @@
                                                  wont_fix_file_content)
         return line_dict
 
+    @contextlib.contextmanager
+    def prepare_smoke_tests(self):
+        """List test cases that should be run by the smoke test builder
+
+        Add new and modified test cases to WPT_SMOKE_TESTS_FILE,
+        builder android-weblayer-pie-x86-wpt-smoketest will run those
+        tests. wpt-importer will generate initial expectations for weblayer
+        based on the result. Save and restore WPT_SMOKE_TESTS_FILE as
+        necessary.
+        """
+        _log.info('Backup file WPTSmokeTestCases.')
+        temp_dir = tempfile.gettempdir()
+        base_path = os.path.basename(WPT_SMOKE_TESTS_FILE)
+        self._saved_test_cases_file = os.path.join(temp_dir, base_path)
+        shutil.copyfile(WPT_SMOKE_TESTS_FILE, self._saved_test_cases_file)
+        tests = (self._list_add_files()
+                 + self._list_modified_files())
+
+        manifest_path = os.path.join(
+            self.finder.web_tests_dir(), "external", BASE_MANIFEST_NAME)
+        manifest = WPTManifest(self.host, manifest_path)
+        with open(WPT_SMOKE_TESTS_FILE, 'w') as out_file:
+            _log.info('Test cases to run on smoke test builder:')
+            prelen = len('external/wpt/')
+            for test in sorted(tests):
+                if test.startswith('external/wpt/') \
+                        and manifest.is_test_file(test[prelen:]):
+                    # path should be the relative path of the test case to
+                    # out/Release dir, as that will be same as that on swarming
+                    # infra. We use path instead of the test case name, because
+                    # that is needed to correctly run cases in js files
+                    path = '../../third_party/blink/web_tests/' + test
+                    _log.info('  ' + path)
+                    out_file.write(path + '\n')
+        try:
+            yield
+        finally:
+            _log.info('Restore file WPTSmokeTestCases.')
+            shutil.copyfile(self._saved_test_cases_file, WPT_SMOKE_TESTS_FILE)
+
     def cleanup_test_expectations_files(self):
         """Removes deleted tests from expectations files.
 
@@ -792,26 +837,42 @@
         """
         deleted_files = self._list_deleted_files()
         renamed_files = self._list_renamed_files()
+        modified_files = self._list_modified_files()
 
         for path in self._test_expectations.expectations_dict:
             _log.info('Updating %s for any removed or renamed tests.',
                       self.host.filesystem.basename(path))
-            self._clean_single_test_expectations_file(
-                path, deleted_files, renamed_files)
+            if path in PRODUCTS_TO_EXPECTATION_FILE_PATHS.values():
+                # Also delete any expectations for modified test cases at
+                # android side to avoid any conflict
+                # TODO: consider keep the triaged expectations when results do
+                # not change
+                self._clean_single_test_expectations_file(
+                    path, deleted_files + modified_files, renamed_files)
+            else:
+                self._clean_single_test_expectations_file(
+                    path, deleted_files, renamed_files)
         self._test_expectations.commit_changes()
 
-    def _list_deleted_files(self):
-        # TODO(robertma): Improve Git.changed_files so that we can use
-        # it here.
+    def _list_files(self, diff_filter):
         paths = self.git.run(
-            ['diff', 'origin/main', '--diff-filter=D',
+            ['diff', 'origin/main', '--diff-filter=' + diff_filter,
              '--name-only']).splitlines()
-        deleted_files = []
+        files = []
         for p in paths:
             rel_path = self._relative_to_web_test_dir(p)
             if rel_path:
-                deleted_files.append(rel_path)
-        return deleted_files
+                files.append(rel_path)
+        return files
+
+    def _list_add_files(self):
+        return self._list_files('A')
+
+    def _list_modified_files(self):
+        return self._list_files('M')
+
+    def _list_deleted_files(self):
+        return self._list_files('D')
 
     def _list_renamed_files(self):
         """Returns a dictionary mapping tests to their new name.
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_metadata_builder.py b/third_party/blink/tools/blinkpy/w3c/wpt_metadata_builder.py
index 0373e86..6f2b11a 100644
--- a/third_party/blink/tools/blinkpy/w3c/wpt_metadata_builder.py
+++ b/third_party/blink/tools/blinkpy/w3c/wpt_metadata_builder.py
@@ -258,9 +258,8 @@
             if self.process_baselines:
                 test_baseline = self.port.expected_text(test_name)
                 if test_baseline:
-                    self._handle_test_with_baseline(
-                        test_name, test_baseline.decode('utf8', 'replace'),
-                        tests_needing_metadata)
+                    self._handle_test_with_baseline(test_name,
+                                                    tests_needing_metadata)
 
             # Next check for expectations, which could overwrite baselines
             expectation_line = self.expectations.get_expectations(test_name)
@@ -330,13 +329,12 @@
         return test_name in status_dict and (
             status_dict[test_name] & SKIP_TEST)
 
-    def _handle_test_with_baseline(self, test_name, test_baseline,
-                                   status_dict):
+    def _handle_test_with_baseline(self, test_name, status_dict):
         """Handles a single test baseline and updates |status_dict|."""
         status_bitmap = 0
-        if re.search(r"^(FAIL|NOTRUN|TIMEOUT)", test_baseline, re.MULTILINE):
+        if self.port.expected_subtest_failure(test_name):
             status_bitmap |= SUBTEST_FAIL
-        if re.search(r"^Harness Error\.", test_baseline, re.MULTILINE):
+        if self.port.expected_harness_error(test_name):
             status_bitmap |= HARNESS_ERROR
         if status_bitmap > 0:
             status_dict[test_name] |= status_bitmap
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/android.py b/third_party/blink/tools/blinkpy/web_tests/port/android.py
index fa11335..ca11515 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/android.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/android.py
@@ -99,6 +99,10 @@
 ANDROID_DISABLED_TESTS = os.path.join(
     ANDROID_WEB_TESTS_DIR, 'AndroidWPTNeverFixTests')
 
+# List of test cases to be run by wptrunner
+WPT_SMOKE_TESTS_FILE = os.path.join(
+    ANDROID_WEB_TESTS_DIR, 'WPTSmokeTestCases')
+
 _friendly_browser_names = {
     'weblayershell': 'weblayer',
     'systemwebviewshell': 'webview',
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/base.py b/third_party/blink/tools/blinkpy/web_tests/port/base.py
index 1108a459..90d98ede 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/base.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/base.py
@@ -847,6 +847,22 @@
         text = self._filesystem.read_binary_file(baseline_path)
         return text.replace(b'\r\n', b'\n')
 
+    def expected_subtest_failure(self, test_name):
+        baseline = self.expected_text(test_name)
+        if baseline:
+            baseline = baseline.decode('utf8', 'replace')
+            if re.search(r"^(FAIL|NOTRUN|TIMEOUT)", baseline, re.MULTILINE):
+                return True
+        return False
+
+    def expected_harness_error(self, test_name):
+        baseline = self.expected_text(test_name)
+        if baseline:
+            baseline = baseline.decode('utf8', 'replace')
+            if re.search(r"^Harness Error\.", baseline, re.MULTILINE):
+                return True
+        return False
+
     def reference_files(self, test_name):
         """Returns a list of expectation (== or !=) and filename pairs"""
 
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 28915a8..550ee6f5 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -6859,6 +6859,9 @@
 crbug.com/1207709 [ Mac10.13 ] virtual/plz-dedicated-worker/external/wpt/resource-timing/document-domain-no-impact-opener.html [ Pass Failure ]
 crbug.com/1207709 [ Mac10.13 ] external/wpt/pointerevents/pointerevent_contextmenu_is_a_pointerevent.html?touch [ Pass Failure ]
 
+# Will be passed when compositing-after-paint is used by default 2021-05-13
+crbug.com/1208213 external/wpt/css/css-transforms/add-child-in-empty-layer.html [ Failure ]
+
 # Sheriff 2021-05-12
 crbug.com/1095540 [ Linux Debug ] virtual/compositor-threaded-percent-based-scrolling/fast/scrolling/resize-corner-tracking-touch.html [ Pass Failure ]
 
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 7d2083fd..60907ec 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -365,6 +365,12 @@
              "--dark-mode-settings=ImagePolicy=0,ImageGrayScalePercent=1.0"]
   },
   {
+    "prefix": "dark-mode-increase-text-contrast",
+    "bases": ["dark-mode/colors"],
+    "args": ["--blink-settings=forceDarkModeEnabled=true",
+             "--dark-mode-settings=IncreaseTextContrast=1"]
+  },
+  {
     "prefix": "presentation",
     "bases": [],
     "args": ["--force-presentation-receiver-for-testing"]
diff --git a/third_party/blink/web_tests/WPTOverrideExpectations b/third_party/blink/web_tests/WPTOverrideExpectations
index 5e3bc60..3afc434 100644
--- a/third_party/blink/web_tests/WPTOverrideExpectations
+++ b/third_party/blink/web_tests/WPTOverrideExpectations
@@ -211,3 +211,25 @@
 external/wpt/webauthn/securecontext.http.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/webauthn/securecontext.https.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/webauthn/webauthn-testdriver-basic.https.html [ Pass ] # wpt_use_checked_in_metadata
+
+crbug.com/1208893 external/wpt/pointerevents/compat/pointerevent_touch-action_two-finger_interaction.html [ Failure ]
+crbug.com/1208893 external/wpt/pointerevents/pointerevent_attributes_nohover_pointers.html [ Failure ]
+crbug.com/1208893 external/wpt/pointerevents/pointerevent_change-touch-action-onpointerdown_touch.html [ Failure ]
+crbug.com/1208893 external/wpt/pointerevents/pointerevent_click_is_a_pointerevent_multiple_clicks.html?touch [ Failure ]
+crbug.com/1208893 external/wpt/pointerevents/pointerevent_fractional_coordinates.html?touch [ Failure ]
+crbug.com/1208893 external/wpt/pointerevents/pointerevent_pointercancel_touch.html [ Failure ]
+crbug.com/1208893 external/wpt/pointerevents/pointerevent_pointerleave_after_pointercancel_touch.html [ Failure ]
+crbug.com/1208893 external/wpt/pointerevents/pointerevent_pointerout_after_pointercancel_touch.html [ Failure ]
+crbug.com/1208893 external/wpt/pointerevents/pointerevent_releasepointercapture_onpointercancel_touch.html [ Failure ]
+crbug.com/1208893 external/wpt/pointerevents/pointerevent_touch-action-auto-css_touch.html [ Failure ]
+crbug.com/1208893 external/wpt/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch.html [ Failure ]
+crbug.com/1208893 external/wpt/pointerevents/pointerevent_touch-action-inherit_highest-parent-none_touch.html [ Failure ]
+crbug.com/1208893 external/wpt/pointerevents/pointerevent_touch-action-pan-down-css_touch.html [ Failure ]
+crbug.com/1208893 external/wpt/pointerevents/pointerevent_touch-action-pan-left-css_touch.html [ Failure ]
+crbug.com/1208893 external/wpt/pointerevents/pointerevent_touch-action-pan-right-css_touch.html [ Failure ]
+crbug.com/1208893 external/wpt/pointerevents/pointerevent_touch-action-pan-up-css_touch.html [ Failure ]
+crbug.com/1208893 external/wpt/pointerevents/pointerevent_touch-action-pan-x-css_touch.html [ Failure ]
+crbug.com/1208893 external/wpt/pointerevents/pointerevent_touch-action-pan-x-pan-y_touch.html [ Failure ]
+crbug.com/1208893 external/wpt/pointerevents/pointerevent_touch-action-pan-y-css_touch.html [ Failure ]
+crbug.com/1208893 external/wpt/pointerevents/pointerevent_touch-action-span-none-test_touch.html [ Failure ]
+crbug.com/1208893 external/wpt/pointerevents/pointerevent_touch-action-table-none-test_touch.html [ Failure ]
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/contentvisibility-nestedslot-crash.html b/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/contentvisibility-nestedslot-crash.html
new file mode 100644
index 0000000..f4f0781
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/contentvisibility-nestedslot-crash.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html class="test-wait">
+<link rel="author" title="Joey Arhar" href="mailto:jarhar@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1208573">
+
+<div style="content-visibility:hidden">hidden</div>
+
+<div id=host>
+  <template shadowroot=open>
+    <div>nested slots:</div>
+    <slot name=parent>
+      <slot name=child></slot>
+    </slot>
+  </template>
+  <div slot=parent>lightdom slot=parent</div>
+  <div slot=child>lightdom slot=child</div>
+</div>
+
+<script>
+  requestAnimationFrame(() => {
+    requestAnimationFrame(() => {
+      const div = document.createElement('div');
+      div.textContent = 'new lightdom child';
+      host.appendChild(div);
+
+      requestAnimationFrame(() => {
+        document.documentElement.classList.remove('test-wait');
+      });
+    });
+  });
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/image-within-indefinite-row-flexbox.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/image-within-indefinite-row-flexbox.tentative.html
new file mode 100644
index 0000000..cb70568
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/image-within-indefinite-row-flexbox.tentative.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<link rel="help" href="https://github.com/web-platform-tests/wpt/issues/28805">
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<p>Test passes if there is a filled green square.</p>
+<div style="display: flex; flex-direction: column; height: 100px; width: max-content; background: green;">
+  <div style="display: flex; height: 50px; flex: 1; width: max-content; min-width: 0; min-height: 0;">
+    <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100px' height='100px'></svg>" />
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/add-child-in-empty-layer-ref.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/add-child-in-empty-layer-ref.html
new file mode 100644
index 0000000..38ab96a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/add-child-in-empty-layer-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<link rel="help" href="https://www.w3.org/TR/css-transforms-2/">
+<style>
+.empty-layer {
+  transform: rotateY(30deg) rotateX(-30deg);
+  width: 100px;
+  height: 100px;
+}
+.inserted {
+  width: 50px;
+  height: 50px;
+  background-color: red;
+}
+</style>
+<!--
+  Force to create composited layer with empty then inserts a child the layer.
+-->
+<div id="empty-layer" class="empty-layer">
+  <div id="inserted" class="inserted"></div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/add-child-in-empty-layer.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/add-child-in-empty-layer.html
new file mode 100644
index 0000000..71b5b24d3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/add-child-in-empty-layer.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>Adding a child to an empty layer</title>
+<link rel="help" href="https://www.w3.org/TR/css-transforms-2/">
+<link rel="match" href="add-child-in-empty-layer-ref.html">
+<style>
+.empty-layer {
+  transform: rotateY(30deg) rotateX(-30deg);
+  width: 100px;
+  height: 100px;
+}
+.inserted {
+  width: 50px;
+  height: 50px;
+  background-color: red;
+}
+</style>
+<!--
+  Force to create composited layer with empty then inserts a child the layer.
+-->
+<div id="empty-layer" class="empty-layer"></div>
+<script>
+requestAnimationFrame(() => {
+  requestAnimationFrame(() => {
+    var div = document.getElementById("empty-layer");
+    div.innerHTML = '<div id="inserted" class="inserted"></div>';
+    requestAnimationFrame(() => {
+      document.documentElement.removeAttribute('class');
+    });
+  });
+});
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-insertable-streams/MediaStreamTrackGenerator-audio.https.html b/third_party/blink/web_tests/external/wpt/mediacapture-insertable-streams/MediaStreamTrackGenerator-audio.https.html
index 8fdb353..d89d0ac 100644
--- a/third_party/blink/web_tests/external/wpt/mediacapture-insertable-streams/MediaStreamTrackGenerator-audio.https.html
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-insertable-streams/MediaStreamTrackGenerator-audio.https.html
@@ -15,7 +15,7 @@
   <script src=/resources/testharnessreport.js></script>
   <script>
 
-    function makeAudioFrame(timestamp) {
+    function makeAudioData(timestamp) {
       const sampleRate = 3000;
       const buffer = new AudioBuffer({
         length: sampleRate / 10, // 100ms
@@ -30,7 +30,7 @@
         array[i] = Math.sin(t);
       }
 
-      return new AudioFrame({
+      return new AudioData({
         timestamp: timestamp,
         buffer: buffer
       });
@@ -40,7 +40,7 @@
       const generator = new MediaStreamTrackGenerator("audio");
 
       const writer = generator.writable.getWriter();
-      await writer.write(makeAudioFrame(1));
+      await writer.write(makeAudioData(1));
 
       assert_equals(generator.kind, "audio");
       assert_equals(generator.readyState, "live");
@@ -58,8 +58,8 @@
       t.add_cleanup(() => generator.stop());
 
       const writer = generator.writable.getWriter();
-      const frame = makeAudioFrame(1);
-      await writer.write(frame);
+      const data = makeAudioData(1);
+      await writer.write(data);
 
       assert_equals(generator.kind, "audio");
       assert_equals(generator.readyState, "live");
@@ -96,10 +96,10 @@
       t.add_cleanup(() => generator.stop());
 
       const writer = generator.writable.getWriter();
-      const frame = makeAudioFrame(1);
+      const data = makeAudioData(1);
 
-      writer.write(frame).then(t.step_func(() => assert_unreached("Write should reject")), t.step_func(f => assert_true(f instanceof TypeError, "write rejects with a TypeError")));
-    }, "Mismatched frame and generator kind throws on write.");
+      writer.write(data).then(t.step_func(() => assert_unreached("Write should reject")), t.step_func(f => assert_true(f instanceof TypeError, "write rejects with a TypeError")));
+    }, "Mismatched data and generator kind throws on write.");
 
     promise_test(async t => {
       const generator = new MediaStreamTrackGenerator("audio");
@@ -110,7 +110,7 @@
       await audioElement.play();
 
       const writer = generator.writable.getWriter();
-      await writer.write(makeAudioFrame(1));
+      await writer.write(makeAudioData(1));
 
       // Wait for audio playout to actually happen.
       await t.step_wait(() => audioElement.currentTime > 0, "audioElement played out generated track");
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-insertable-streams/MediaStreamTrackProcessor-audio.https.html b/third_party/blink/web_tests/external/wpt/mediacapture-insertable-streams/MediaStreamTrackProcessor-audio.https.html
index 8487f7d2..516f267b 100644
--- a/third_party/blink/web_tests/external/wpt/mediacapture-insertable-streams/MediaStreamTrackProcessor-audio.https.html
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-insertable-streams/MediaStreamTrackProcessor-audio.https.html
@@ -21,9 +21,9 @@
 
       return new Promise((resolve, reject) => {
         const writableStream = new WritableStream({
-          write(audioFrame) {
-            assert_true(audioFrame instanceof AudioFrame);
-            assert_not_equals(audioFrame.timestamp, null);
+          write(audioData) {
+            assert_true(audioData instanceof AudioData);
+            assert_not_equals(audioData.timestamp, null);
             resolve();
           },
           close() {
diff --git a/third_party/blink/web_tests/external/wpt/shadow-dom/user-agent-shadow-root-crash.html b/third_party/blink/web_tests/external/wpt/shadow-dom/user-agent-shadow-root-crash.html
new file mode 100644
index 0000000..bd90b04
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/shadow-dom/user-agent-shadow-root-crash.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="help" href="https://crbug.com/1205246">
+<meta name="assert" content="The renderer should not crash.">
+
+This test passes if it does not crash.
+
+<details> sample1
+<marquee dir="auto">marquee1</marquee>
+<marquee dir="auto">marquee2</marquee>
+<marquee dir="auto">marquee3</marquee>
+<marquee dir="auto">marquee4</marquee>
+<marquee dir="auto">marquee5</marquee>
+<marquee dir="auto">marquee6</marquee>
+<marquee dir="auto">marquee7</marquee>
+<marquee dir="auto">marquee8</marquee>
+<marquee dir="auto">marquee9</marquee>
+</details>
diff --git a/third_party/blink/web_tests/external/wpt/webcodecs/audio-frame-serialization.any.js b/third_party/blink/web_tests/external/wpt/webcodecs/audio-data-serialization.any.js
similarity index 65%
rename from third_party/blink/web_tests/external/wpt/webcodecs/audio-frame-serialization.any.js
rename to third_party/blink/web_tests/external/wpt/webcodecs/audio-data-serialization.any.js
index a16207f..3d42aec8 100644
--- a/third_party/blink/web_tests/external/wpt/webcodecs/audio-frame-serialization.any.js
+++ b/third_party/blink/web_tests/external/wpt/webcodecs/audio-data-serialization.any.js
@@ -9,64 +9,64 @@
   frames: 100,
 }
 
-function createDefaultAudioFrame() {
-  return make_audio_frame(defaultInit.timestamp,
+function createDefaultAudioData() {
+  return make_audio_data(defaultInit.timestamp,
                           defaultInit.channels,
                           defaultInit.sampleRate,
                           defaultInit.frames);
 }
 
 async_test(t => {
-  let localFrame = createDefaultAudioFrame();
+  let localData = createDefaultAudioData();
 
   let channel = new MessageChannel();
   let localPort = channel.port1;
   let externalPort = channel.port2;
 
   externalPort.onmessage = t.step_func((e) => {
-    let externalFrame = e.data;
-    let buffer = externalFrame.buffer;
+    let externalData = e.data;
+    let buffer = externalData.buffer;
     // We should have a valid deserialized buffer.
     assert_true(buffer != undefined || buffer != null);
     assert_equals(buffer.numberOfChannels,
-                  localFrame.buffer.numberOfChannels, "numberOfChannels");
+                  localData.buffer.numberOfChannels, "numberOfChannels");
 
     for (var channel = 0; channel < buffer.numberOfChannels; channel++) {
       // This gives us the actual array that contains the data
       var dest_array = buffer.getChannelData(channel);
-      var source_array = localFrame.buffer.getChannelData(channel);
+      var source_array = localData.buffer.getChannelData(channel);
       for (var i = 0; i < dest_array.length; i+=10) {
         assert_equals(dest_array[i], source_array[i],
           "data (ch=" + channel + ", i=" + i + ")");
       }
     }
 
-    externalFrame.close();
+    externalData.close();
     externalPort.postMessage("Done");
   })
 
   localPort.onmessage = t.step_func_done((e) => {
-    assert_true(localFrame.buffer != null);
-    localFrame.close();
+    assert_true(localData.buffer != null);
+    localData.close();
   })
 
-  localPort.postMessage(localFrame);
+  localPort.postMessage(localData);
 
-}, 'Verify closing frames does not propagate accross contexts.');
+}, 'Verify closing AudioData does not propagate accross contexts.');
 
 async_test(t => {
-  let localFrame = createDefaultAudioFrame();
+  let localData = createDefaultAudioData();
 
   let channel = new MessageChannel();
   let localPort = channel.port1;
 
   localPort.onmessage = t.unreached_func();
 
-  localFrame.close();
+  localData.close();
 
   assert_throws_dom("DataCloneError", () => {
-    localPort.postMessage(localFrame);
+    localPort.postMessage(localData);
   });
 
   t.done();
-}, 'Verify posting closed frames throws.');
+}, 'Verify posting closed AudioData throws.');
diff --git a/third_party/blink/web_tests/external/wpt/webcodecs/audio-data.any.js b/third_party/blink/web_tests/external/wpt/webcodecs/audio-data.any.js
new file mode 100644
index 0000000..e196cb8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webcodecs/audio-data.any.js
@@ -0,0 +1,113 @@
+// META: global=window
+// META: script=/common/media.js
+// META: script=/webcodecs/utils.js
+
+var defaultInit =
+    {
+      timestamp: 1234,
+      channels: 2,
+      sampleRate: 8000,
+      frames: 100,
+    }
+
+function
+createDefaultAudioData() {
+  return make_audio_data(
+      defaultInit.timestamp, defaultInit.channels, defaultInit.sampleRate,
+      defaultInit.frames);
+}
+
+test(t => {
+  let localBuffer = new AudioBuffer({
+    length: defaultInit.frames,
+    numberOfChannels: defaultInit.channels,
+    sampleRate: defaultInit.sampleRate
+  });
+
+  let audioDataInit = {timestamp: defaultInit.timestamp, buffer: localBuffer}
+
+  let data = new AudioData(audioDataInit);
+
+  assert_equals(data.timestamp, defaultInit.timestamp, 'timestamp');
+  assert_equals(data.buffer.length, defaultInit.frames, 'frames');
+  assert_equals(
+      data.buffer.numberOfChannels, defaultInit.channels, 'channels');
+  assert_equals(data.buffer.sampleRate, defaultInit.sampleRate, 'sampleRate');
+
+  assert_throws_js(
+      TypeError, () => {let data = new AudioData({buffer: localBuffer})},
+      'AudioData requires \'timestamp\'')
+
+  assert_throws_js(
+      TypeError,
+      () => {let data = new AudioData({timestamp: defaultInit.timestamp})},
+      'AudioData requires \'buffer\'')
+}, 'Verify AudioData constructors');
+
+test(t => {
+  let data = createDefaultAudioData();
+
+  let clone = data.clone();
+
+  // Verify the parameters match.
+  assert_equals(data.timestamp, clone.timestamp, 'timestamp');
+  assert_equals(data.buffer.length, clone.buffer.length, 'frames');
+  assert_equals(
+      data.buffer.numberOfChannels, clone.buffer.numberOfChannels, 'channels');
+  assert_equals(data.buffer.sampleRate, clone.buffer.sampleRate, 'sampleRate');
+
+  // Verify the data matches.
+  for (var channel = 0; channel < data.buffer.numberOfChannels; channel++) {
+    var orig_ch = data.buffer.getChannelData(channel);
+    var cloned_ch = clone.buffer.getChannelData(channel);
+
+    assert_array_equals(orig_ch, cloned_ch, 'Cloned data ch=' + channel);
+  }
+
+  // Verify closing the original data doesn't close the clone.
+  data.close();
+  assert_equals(data.buffer, null, 'data.buffer (closed)');
+  assert_not_equals(clone.buffer, null, 'clone.buffer (not closed)');
+
+  clone.close();
+  assert_equals(clone.buffer, null, 'clone.buffer (closed)');
+
+  // Verify closing a closed AudioData does not throw.
+  data.close();
+}, 'Verify closing and cloning AudioData');
+
+test(t => {
+  let data = createDefaultAudioData();
+
+  // Get a copy of the original data.
+  let pre_modification_clone = data.clone();
+
+  for (var channel = 0; channel < data.buffer.numberOfChannels; channel++) {
+    var orig_ch = data.buffer.getChannelData(channel);
+
+    // Flip the polarity of the original data's buffer.
+    for (let i = 0; i < orig_ch.length; ++i) {
+      orig_ch.buffer[i] = -orig_ch.buffer[i];
+    }
+  }
+
+  // The data in 'data' should have been snapshotted internally, and
+  // despite changes to data.buffer, post_modification_clone should not contain
+  // modified data.
+  let post_modification_clone = data.clone();
+
+  // Verify the data matches.
+  for (var channel = 0; channel < data.buffer.numberOfChannels; channel++) {
+    var pre_ch = pre_modification_clone.buffer.getChannelData(channel);
+    var post_ch = post_modification_clone.buffer.getChannelData(channel);
+
+    assert_array_equals(pre_ch, post_ch, 'Cloned data ch=' + channel);
+  }
+}, 'Verify AudioData is snapshotted and internally immutable');
+
+test(t => {
+  let data = make_audio_data(
+      -10, defaultInit.channels, defaultInit.sampleRate, defaultInit.frames);
+  assert_equals(data.timestamp, -10, 'timestamp');
+  data.close();
+}, 'Test we can construct AudioData with a negative timestamp.');
diff --git a/third_party/blink/web_tests/external/wpt/webcodecs/audio-encoder.any.js b/third_party/blink/web_tests/external/wpt/webcodecs/audio-encoder.any.js
index 654c301..7785b17d 100644
--- a/third_party/blink/web_tests/external/wpt/webcodecs/audio-encoder.any.js
+++ b/third_party/blink/web_tests/external/wpt/webcodecs/audio-encoder.any.js
@@ -35,7 +35,7 @@
 promise_test(async t => {
   let sample_rate = 48000;
   let total_duration_s = 1;
-  let frame_count = 10;
+  let data_count = 10;
   let outputs = [];
   let init = {
     error: e => {
@@ -59,18 +59,18 @@
   encoder.configure(config);
 
   let timestamp_us = 0;
-  let frame_duration_s = total_duration_s / frame_count;
-  let frame_length = frame_duration_s * config.sampleRate;
-  for (let i = 0; i < frame_count; i++) {
-    let frame = make_audio_frame(timestamp_us, config.numberOfChannels,
-      config.sampleRate, frame_length);
-    encoder.encode(frame);
-    frame.close();
-    timestamp_us += frame_duration_s * 1_000_000;
+  let data_duration_s = total_duration_s / data_count;
+  let data_length = data_duration_s * config.sampleRate;
+  for (let i = 0; i < data_count; i++) {
+    let data = make_audio_data(timestamp_us, config.numberOfChannels,
+      config.sampleRate, data_length);
+    encoder.encode(data);
+    data.close();
+    timestamp_us += data_duration_s * 1_000_000;
   }
   await encoder.flush();
   encoder.close();
-  assert_greater_than_equal(outputs.length, frame_count);
+  assert_greater_than_equal(outputs.length, data_count);
   assert_equals(outputs[0].timestamp, 0, "first chunk timestamp");
   for (chunk of outputs) {
     assert_greater_than(chunk.data.byteLength, 0);
@@ -81,7 +81,7 @@
 promise_test(async t => {
   let sample_rate = 48000;
   let total_duration_s = 1;
-  let frame_count = 10;
+  let data_count = 10;
   let outputs = [];
   let init = {
     error: e => {
@@ -105,10 +105,10 @@
   encoder.configure(config);
 
   let timestamp_us = -10000;
-  let frame = make_audio_frame(
+  let data = make_audio_data(
       timestamp_us, config.numberOfChannels, config.sampleRate, 10000);
-  encoder.encode(frame);
-  frame.close();
+  encoder.encode(data);
+  data.close();
   await encoder.flush();
   encoder.close();
   assert_greater_than_equal(outputs.length, 1);
@@ -119,7 +119,7 @@
   }
 }, 'Encode audio with negative timestamp');
 
-async function checkEncodingError(config, good_frames, bad_frame) {
+async function checkEncodingError(config, good_data, bad_data) {
   let error = null;
   let outputs = 0;
   let init = {
@@ -138,9 +138,9 @@
   config = support.config;
 
   encoder.configure(config);
-  for (let frame of good_frames) {
-    encoder.encode(frame);
-    frame.close();
+  for (let data of good_data) {
+    encoder.encode(data);
+    data.close();
   }
   await encoder.flush();
 
@@ -148,7 +148,7 @@
                  + " numberOfChannels: " + config.numberOfChannels;
   assert_equals(error, null, txt_config);
   assert_greater_than(outputs, 0);
-  encoder.encode(bad_frame);
+  encoder.encode(bad_data);
   await encoder.flush().catch(() => {});
   assert_not_equals(error, null, txt_config);
 }
@@ -165,15 +165,15 @@
 
     let ts = 0;
     let length = sample_rate / 10;
-    let frame1 = make_audio_frame(ts, channels, sample_rate, length);
+    let data1 = make_audio_data(ts, channels, sample_rate, length);
 
-    ts += Math.floor(frame1.buffer.duration / 1000000);
-    let frame2 = make_audio_frame(ts, channels, sample_rate, length);
-    ts += Math.floor(frame2.buffer.duration / 1000000);
+    ts += Math.floor(data1.buffer.duration / 1000000);
+    let data2 = make_audio_data(ts, channels, sample_rate, length);
+    ts += Math.floor(data2.buffer.duration / 1000000);
 
-    let bad_frame = make_audio_frame(ts, channels + 1, sample_rate, length);
+    let bad_data = make_audio_data(ts, channels + 1, sample_rate, length);
     promise_test(async t =>
-      checkEncodingError(config, [frame1, frame2], bad_frame),
+      checkEncodingError(config, [data1, data2], bad_data),
       "Channel number variation: " + channels);
   }
 }
@@ -191,15 +191,15 @@
 
     let ts = 0;
     let length = sample_rate / 10;
-    let frame1 = make_audio_frame(ts, channels, sample_rate, length);
+    let data1 = make_audio_data(ts, channels, sample_rate, length);
 
-    ts += Math.floor(frame1.buffer.duration / 1000000);
-    let frame2 = make_audio_frame(ts, channels, sample_rate, length);
-    ts += Math.floor(frame2.buffer.duration / 1000000);
+    ts += Math.floor(data1.buffer.duration / 1000000);
+    let data2 = make_audio_data(ts, channels, sample_rate, length);
+    ts += Math.floor(data2.buffer.duration / 1000000);
 
-    let bad_frame = make_audio_frame(ts, channels, sample_rate + 333, length);
+    let bad_data = make_audio_data(ts, channels, sample_rate + 333, length);
     promise_test(async t =>
-      checkEncodingError(config, [frame1, frame2], bad_frame),
+      checkEncodingError(config, [data1, data2], bad_data),
       "Sample rate variation: " + sample_rate);
   }
 }
@@ -208,14 +208,14 @@
 promise_test(async t => {
   let sample_rate = 48000;
   let total_duration_s = 1;
-  let frame_count = 10;
-  let input_frames = [];
-  let output_frames = [];
+  let data_count = 10;
+  let input_data = [];
+  let output_data = [];
 
   let decoder_init = {
     error: t.unreached_func("Decode error"),
-    output: frame => {
-      output_frames.push(frame);
+    output: data => {
+      output_data.push(data);
     }
   };
   let decoder = new AudioDecoder(decoder_init);
@@ -240,14 +240,14 @@
   encoder.configure(config);
 
   let timestamp_us = 0;
-  const frame_duration_s = total_duration_s / frame_count;
-  const frame_length = frame_duration_s * config.sampleRate;
-  for (let i = 0; i < frame_count; i++) {
-    let frame = make_audio_frame(timestamp_us, config.numberOfChannels,
-      config.sampleRate, frame_length);
-    input_frames.push(frame);
-    encoder.encode(frame);
-    timestamp_us += frame_duration_s * 1_000_000;
+  const data_duration_s = total_duration_s / data_count;
+  const data_length = data_duration_s * config.sampleRate;
+  for (let i = 0; i < data_count; i++) {
+    let data = make_audio_data(timestamp_us, config.numberOfChannels,
+      config.sampleRate, data_length);
+    input_data.push(data);
+    encoder.encode(data);
+    timestamp_us += data_duration_s * 1_000_000;
   }
   await encoder.flush();
   encoder.close();
@@ -255,8 +255,8 @@
   decoder.close();
 
 
-  let total_input = join_buffers(input_frames.map(f => f.buffer));
-  let total_output = join_buffers(output_frames.map(f => f.buffer));
+  let total_input = join_buffers(input_data.map(f => f.buffer));
+  let total_output = join_buffers(output_data.map(f => f.buffer));
   assert_equals(total_output.numberOfChannels, 2);
   assert_equals(total_output.sampleRate, sample_rate);
 
@@ -311,12 +311,12 @@
   let encoder = new AudioEncoder(init);
   encoder.configure(encoder_config);
 
-  let long_frame = make_audio_frame(0, encoder_config.numberOfChannels,
+  let large_data = make_audio_data(0, encoder_config.numberOfChannels,
     encoder_config.sampleRate, encoder_config.sampleRate);
-  encoder.encode(long_frame);
+  encoder.encode(large_data);
   await encoder.flush();
 
-  // Long frame produced more than one output, and we've got decoder_config
+  // Large data produced more than one output, and we've got decoder_config
   assert_greater_than(output_count, 1);
   assert_not_equals(decoder_config, null);
   assert_equals(decoder_config.codec, encoder_config.codec);
@@ -334,7 +334,7 @@
   output_count = 0;
   encoder_config.bitrate = 256000;
   encoder.configure(encoder_config);
-  encoder.encode(long_frame);
+  encoder.encode(large_data);
   await encoder.flush();
 
   // After reconfiguring encoder should produce decoder config again
diff --git a/third_party/blink/web_tests/external/wpt/webcodecs/audio-frame.any.js b/third_party/blink/web_tests/external/wpt/webcodecs/audio-frame.any.js
deleted file mode 100644
index 039a6d1..0000000
--- a/third_party/blink/web_tests/external/wpt/webcodecs/audio-frame.any.js
+++ /dev/null
@@ -1,113 +0,0 @@
-// META: global=window
-// META: script=/common/media.js
-// META: script=/webcodecs/utils.js
-
-var defaultInit =
-    {
-      timestamp: 1234,
-      channels: 2,
-      sampleRate: 8000,
-      frames: 100,
-    }
-
-function
-createDefaultAudioFrame() {
-  return make_audio_frame(
-      defaultInit.timestamp, defaultInit.channels, defaultInit.sampleRate,
-      defaultInit.frames);
-}
-
-test(t => {
-  let localBuffer = new AudioBuffer({
-    length: defaultInit.frames,
-    numberOfChannels: defaultInit.channels,
-    sampleRate: defaultInit.sampleRate
-  });
-
-  let audioFrameInit = {timestamp: defaultInit.timestamp, buffer: localBuffer}
-
-  let frame = new AudioFrame(audioFrameInit);
-
-  assert_equals(frame.timestamp, defaultInit.timestamp, 'timestamp');
-  assert_equals(frame.buffer.length, defaultInit.frames, 'frames');
-  assert_equals(
-      frame.buffer.numberOfChannels, defaultInit.channels, 'channels');
-  assert_equals(frame.buffer.sampleRate, defaultInit.sampleRate, 'sampleRate');
-
-  assert_throws_js(
-      TypeError, () => {let frame = new AudioFrame({buffer: localBuffer})},
-      'AudioFrames require \'timestamp\'')
-
-  assert_throws_js(
-      TypeError,
-      () => {let frame = new AudioFrame({timestamp: defaultInit.timestamp})},
-      'AudioFrames require \'buffer\'')
-}, 'Verify AudioFrame constructors');
-
-test(t => {
-  let frame = createDefaultAudioFrame();
-
-  let clone = frame.clone();
-
-  // Verify the parameters match.
-  assert_equals(frame.timestamp, clone.timestamp, 'timestamp');
-  assert_equals(frame.buffer.length, clone.buffer.length, 'frames');
-  assert_equals(
-      frame.buffer.numberOfChannels, clone.buffer.numberOfChannels, 'channels');
-  assert_equals(frame.buffer.sampleRate, clone.buffer.sampleRate, 'sampleRate');
-
-  // Verify the data matches.
-  for (var channel = 0; channel < frame.buffer.numberOfChannels; channel++) {
-    var orig_ch = frame.buffer.getChannelData(channel);
-    var cloned_ch = clone.buffer.getChannelData(channel);
-
-    assert_array_equals(orig_ch, cloned_ch, 'Cloned data ch=' + channel);
-  }
-
-  // Verify closing the original frame doesn't close the clone.
-  frame.close();
-  assert_equals(frame.buffer, null, 'frame.buffer (closed)');
-  assert_not_equals(clone.buffer, null, 'clone.buffer (not closed)');
-
-  clone.close();
-  assert_equals(clone.buffer, null, 'clone.buffer (closed)');
-
-  // Verify closing a closed frame does not throw.
-  frame.close();
-}, 'Verify closing and cloning AudioFrames');
-
-test(t => {
-  let frame = createDefaultAudioFrame();
-
-  // Get a copy of the original data.
-  let pre_modification_clone = frame.clone();
-
-  for (var channel = 0; channel < frame.buffer.numberOfChannels; channel++) {
-    var orig_ch = frame.buffer.getChannelData(channel);
-
-    // Flip the polarity of the original frame's buffer.
-    for (let i = 0; i < orig_ch.length; ++i) {
-      orig_ch.buffer[i] = -orig_ch.buffer[i];
-    }
-  }
-
-  // The data in 'frame' should have been snapshotted internally, and
-  // despite changes to frame.buffer, post_modification_clone should not contain
-  // modified data.
-  let post_modification_clone = frame.clone();
-
-  // Verify the data matches.
-  for (var channel = 0; channel < frame.buffer.numberOfChannels; channel++) {
-    var pre_ch = pre_modification_clone.buffer.getChannelData(channel);
-    var post_ch = post_modification_clone.buffer.getChannelData(channel);
-
-    assert_array_equals(pre_ch, post_ch, 'Cloned data ch=' + channel);
-  }
-}, 'Verify frame data is snapshotted and internally immutable');
-
-test(t => {
-  let frame = make_audio_frame(
-      -10, defaultInit.channels, defaultInit.sampleRate, defaultInit.frames);
-  assert_equals(frame.timestamp, -10, 'timestamp');
-  frame.close();
-}, 'Test we can construct a AudioFrame with a negative timestamp.');
diff --git a/third_party/blink/web_tests/external/wpt/webcodecs/utils.js b/third_party/blink/web_tests/external/wpt/webcodecs/utils.js
index a1175bc1..2e7d8b3 100644
--- a/third_party/blink/web_tests/external/wpt/webcodecs/utils.js
+++ b/third_party/blink/web_tests/external/wpt/webcodecs/utils.js
@@ -1,4 +1,4 @@
-function make_audio_frame(timestamp, channels, sampleRate, length) {
+function make_audio_data(timestamp, channels, sampleRate, length) {
   let buffer = new AudioBuffer({
     length: length,
     numberOfChannels: channels,
@@ -15,7 +15,7 @@
     }
   }
 
-  return new AudioFrame({
+  return new AudioData({
     timestamp: timestamp,
     buffer: buffer
   });
diff --git a/third_party/blink/web_tests/fast/dom/shadow/user-agent-shadow-root-crash.html b/third_party/blink/web_tests/fast/dom/shadow/user-agent-shadow-root-crash.html
deleted file mode 100644
index b377855..0000000
--- a/third_party/blink/web_tests/fast/dom/shadow/user-agent-shadow-root-crash.html
+++ /dev/null
@@ -1,22 +0,0 @@
-<!DOCTYPE html>
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-
-<title>Test: the shadow roots for UserAgent should not crash</title>
-
-<!-- This is a minified version of the clusterfuzz test case at https://crbug.com/1205246-->
-<details> sample1
-<marquee dir="auto">marquee1</marquee>
-<marquee dir="auto">marquee2</marquee>
-<marquee dir="auto">marquee3</marquee>
-<marquee dir="auto">marquee4</marquee>
-<marquee dir="auto">marquee5</marquee>
-<marquee dir="auto">marquee6</marquee>
-<marquee dir="auto">marquee7</marquee>
-<marquee dir="auto">marquee8</marquee>
-<marquee dir="auto">marquee9</marquee>
-</details>
-
-<script>
-test(() => {}, "Don't crash during recalculating user agent's shadow roots");
-</script>
diff --git a/third_party/blink/web_tests/platform/linux/virtual/dark-mode-increase-text-contrast/dark-mode/colors/list-markers-expected.png b/third_party/blink/web_tests/platform/linux/virtual/dark-mode-increase-text-contrast/dark-mode/colors/list-markers-expected.png
new file mode 100644
index 0000000..72828ee
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/dark-mode-increase-text-contrast/dark-mode/colors/list-markers-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/dark-mode-increase-text-contrast/dark-mode/colors/text-input-elements_with_native_theme-expected.png b/third_party/blink/web_tests/platform/linux/virtual/dark-mode-increase-text-contrast/dark-mode/colors/text-input-elements_with_native_theme-expected.png
new file mode 100644
index 0000000..bb7a337
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/dark-mode-increase-text-contrast/dark-mode/colors/text-input-elements_with_native_theme-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/dark-mode-increase-text-contrast/dark-mode/colors/text-input-elements_without_native_theme-expected.png b/third_party/blink/web_tests/platform/linux/virtual/dark-mode-increase-text-contrast/dark-mode/colors/text-input-elements_without_native_theme-expected.png
new file mode 100644
index 0000000..df843714
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/dark-mode-increase-text-contrast/dark-mode/colors/text-input-elements_without_native_theme-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/dark-mode-increase-text-contrast/dark-mode/colors/text-on-backgrounds-expected.png b/third_party/blink/web_tests/platform/linux/virtual/dark-mode-increase-text-contrast/dark-mode/colors/text-on-backgrounds-expected.png
new file mode 100644
index 0000000..8b5a1b9
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/dark-mode-increase-text-contrast/dark-mode/colors/text-on-backgrounds-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/dark-mode-increase-text-contrast/dark-mode/colors/list-markers-expected.png b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/dark-mode-increase-text-contrast/dark-mode/colors/list-markers-expected.png
new file mode 100644
index 0000000..8677154
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/dark-mode-increase-text-contrast/dark-mode/colors/list-markers-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/dark-mode-increase-text-contrast/dark-mode/colors/text-on-backgrounds-expected.png b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/dark-mode-increase-text-contrast/dark-mode/colors/text-on-backgrounds-expected.png
new file mode 100644
index 0000000..fe5fe105
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/dark-mode-increase-text-contrast/dark-mode/colors/text-on-backgrounds-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/dark-mode-increase-text-contrast/dark-mode/colors/text-input-elements_with_native_theme-expected.png b/third_party/blink/web_tests/platform/win/virtual/dark-mode-increase-text-contrast/dark-mode/colors/text-input-elements_with_native_theme-expected.png
new file mode 100644
index 0000000..d5cb972
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/virtual/dark-mode-increase-text-contrast/dark-mode/colors/text-input-elements_with_native_theme-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/dark-mode-increase-text-contrast/dark-mode/colors/text-input-elements_without_native_theme-expected.png b/third_party/blink/web_tests/platform/win/virtual/dark-mode-increase-text-contrast/dark-mode/colors/text-input-elements_without_native_theme-expected.png
new file mode 100644
index 0000000..78f9e2d4
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/virtual/dark-mode-increase-text-contrast/dark-mode/colors/text-input-elements_without_native_theme-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/dark-mode-increase-text-contrast/dark-mode/colors/README.txt b/third_party/blink/web_tests/virtual/dark-mode-increase-text-contrast/dark-mode/colors/README.txt
new file mode 100644
index 0000000..e2d4fe8
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/dark-mode-increase-text-contrast/dark-mode/colors/README.txt
@@ -0,0 +1,4 @@
+# This suite runs the tests in web_tests/dark-mode/colors with
+# --blink-settings=forceDarkModeEnabled=true and
+# --dark-mode-settings=IncreaseTextContrast=1
+# See the virtual_test_suites() method in tools/blinkpy/web_tests/port/base.py.
diff --git a/third_party/blink/web_tests/virtual/dark-mode-increase-text-contrast/dark-mode/colors/list-markers-expected.png b/third_party/blink/web_tests/virtual/dark-mode-increase-text-contrast/dark-mode/colors/list-markers-expected.png
new file mode 100644
index 0000000..deb2268
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/dark-mode-increase-text-contrast/dark-mode/colors/list-markers-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/dark-mode-increase-text-contrast/dark-mode/colors/text-input-elements_with_native_theme-expected.png b/third_party/blink/web_tests/virtual/dark-mode-increase-text-contrast/dark-mode/colors/text-input-elements_with_native_theme-expected.png
new file mode 100644
index 0000000..17750ab6
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/dark-mode-increase-text-contrast/dark-mode/colors/text-input-elements_with_native_theme-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/dark-mode-increase-text-contrast/dark-mode/colors/text-input-elements_without_native_theme-expected.png b/third_party/blink/web_tests/virtual/dark-mode-increase-text-contrast/dark-mode/colors/text-input-elements_without_native_theme-expected.png
new file mode 100644
index 0000000..7d5742d
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/dark-mode-increase-text-contrast/dark-mode/colors/text-input-elements_without_native_theme-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/dark-mode-increase-text-contrast/dark-mode/colors/text-on-backgrounds-expected.png b/third_party/blink/web_tests/virtual/dark-mode-increase-text-contrast/dark-mode/colors/text-on-backgrounds-expected.png
new file mode 100644
index 0000000..e5414a3
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/dark-mode-increase-text-contrast/dark-mode/colors/text-on-backgrounds-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
index 58c1ec90..75a99b0 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -15,6 +15,13 @@
 [Worker]     getter onabort
 [Worker]     method constructor
 [Worker]     setter onabort
+[Worker] interface AudioData
+[Worker]     attribute @@toStringTag
+[Worker]     getter buffer
+[Worker]     getter timestamp
+[Worker]     method clone
+[Worker]     method close
+[Worker]     method constructor
 [Worker] interface AudioDecoder
 [Worker]     static method isConfigSupported
 [Worker]     attribute @@toStringTag
@@ -37,13 +44,6 @@
 [Worker]     method encode
 [Worker]     method flush
 [Worker]     method reset
-[Worker] interface AudioFrame
-[Worker]     attribute @@toStringTag
-[Worker]     getter buffer
-[Worker]     getter timestamp
-[Worker]     method clone
-[Worker]     method close
-[Worker]     method constructor
 [Worker] interface BackgroundFetchManager
 [Worker]     attribute @@toStringTag
 [Worker]     method constructor
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
index 369525f..0297b2f 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -244,6 +244,7 @@
 interface AppHistoryEntry : EventTarget
     attribute @@toStringTag
     getter id
+    getter index
     getter key
     getter sameDocument
     getter url
@@ -307,6 +308,13 @@
     method getOutputTimestamp
     method resume
     method suspend
+interface AudioData
+    attribute @@toStringTag
+    getter buffer
+    getter timestamp
+    method clone
+    method close
+    method constructor
 interface AudioDecoder
     static method isConfigSupported
     attribute @@toStringTag
@@ -333,13 +341,6 @@
     method encode
     method flush
     method reset
-interface AudioFrame
-    attribute @@toStringTag
-    getter buffer
-    getter timestamp
-    method clone
-    method close
-    method constructor
 interface AudioListener
     attribute @@toStringTag
     getter forwardX
diff --git a/third_party/blink/web_tests/wpt_internal/app-history/app-history-entry/index-not-in-entries.html b/third_party/blink/web_tests/wpt_internal/app-history/app-history-entry/index-not-in-entries.html
new file mode 100644
index 0000000..f29a7d4
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/app-history/app-history-entry/index-not-in-entries.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe id="i" src="/common/blank.html"></iframe>
+<script>
+async_test(t => {
+  // t.step_timeout because blink doesn't create history entries for
+  // navigations if onload has not yet completed.
+  window.onload = () => t.step_timeout(t.step_func_done(() => {
+    // Remove the entry by replacing it.
+    let replaced_entry = appHistory.current;
+    assert_equals(replaced_entry.index, 0);
+    appHistory.navigate("#0", { replace: true });
+    assert_equals(replaced_entry.index, -1);
+
+    // Remove the entry by detaching its window.
+    let iframe_entry = i.contentWindow.appHistory.current;
+    assert_equals(iframe_entry.index, 0);
+    i.remove();
+    assert_equals(iframe_entry.index, -1);
+    t.done();
+  }), 0);
+}, "AppHistoryEntry.index should return -1 when not in AppHistory.entries");
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/app-history/app-history-entry/key-navigate-back-same-document.html b/third_party/blink/web_tests/wpt_internal/app-history/app-history-entry/key-navigate-back-same-document.html
index 2c24671b..9ceb6b20 100644
--- a/third_party/blink/web_tests/wpt_internal/app-history/app-history-entry/key-navigate-back-same-document.html
+++ b/third_party/blink/web_tests/wpt_internal/app-history/app-history-entry/key-navigate-back-same-document.html
@@ -12,13 +12,13 @@
     assert_not_equals(key, appHistory.current.key);
     assert_not_equals(id, appHistory.current.id);
     assert_equals(appHistory.entries().length, 2);
-    assert_equals(appHistory.entries()[1], appHistory.current);
+    assert_equals(appHistory.current.index, 1);
 
     window.onpopstate = t.step_func_done(() => {
       assert_equals(key, appHistory.current.key);
       assert_equals(id, appHistory.current.id);
       assert_equals(appHistory.entries().length, 2);
-      assert_equals(appHistory.entries()[0], appHistory.current);
+    assert_equals(appHistory.current.index, 0);
     });
     history.back();
   });
diff --git a/third_party/blink/web_tests/wpt_internal/app-history/app-history-entry/resources/key-navigate-back-cross-document-helper.html b/third_party/blink/web_tests/wpt_internal/app-history/app-history-entry/resources/key-navigate-back-cross-document-helper.html
index 984dcb0c..f5c6e963 100644
--- a/third_party/blink/web_tests/wpt_internal/app-history/app-history-entry/resources/key-navigate-back-cross-document-helper.html
+++ b/third_party/blink/web_tests/wpt_internal/app-history/app-history-entry/resources/key-navigate-back-cross-document-helper.html
@@ -7,14 +7,14 @@
 window.onload = () => { setTimeout(() => {
   if (location.search == "?go-back") {
     assert_equals(appHistory.entries().length, 2);
-    assert_equals(appHistory.entries()[1], appHistory.current);
+    assert_equals(appHistory.current.index, 1);
     // Step 2: Navigate back.
     history.back();
     return;
   }
   if (top.start_key) {
     assert_equals(appHistory.entries().length, 2);
-    assert_equals(appHistory.entries()[0], appHistory.current);
+    assert_equals(appHistory.current.index, 0);
     // Step 3: Notify parent, which will ensure the same key is used after back navigation.
     top.finish(appHistory.current.key, appHistory.current.id);
     return;
diff --git a/third_party/blink/web_tests/wpt_internal/app-history/navigate/state/navigate-state-cross-document-location-navigate.html b/third_party/blink/web_tests/wpt_internal/app-history/navigate/state/navigate-state-cross-document-location-navigate.html
index 5732fd4..384d8d9 100644
--- a/third_party/blink/web_tests/wpt_internal/app-history/navigate/state/navigate-state-cross-document-location-navigate.html
+++ b/third_party/blink/web_tests/wpt_internal/app-history/navigate/state/navigate-state-cross-document-location-navigate.html
@@ -12,7 +12,7 @@
     i.contentWindow.location.href = "?1";
     i.onload = t.step_func_done(() => {
       assert_equals(i.contentWindow.appHistory.entries().length, 2);
-      assert_equals(i.contentWindow.appHistory.current, i.contentWindow.appHistory.entries()[1]);
+      assert_equals(i.contentWindow.appHistory.current.index, 1);
       assert_equals(i.contentWindow.appHistory.current.getState(), undefined);
     });
   });
diff --git a/third_party/blink/web_tests/wpt_internal/app-history/navigate/state/navigate-state-cross-document-restore.html b/third_party/blink/web_tests/wpt_internal/app-history/navigate/state/navigate-state-cross-document-restore.html
index 3622f4f..e1f70dc2 100644
--- a/third_party/blink/web_tests/wpt_internal/app-history/navigate/state/navigate-state-cross-document-restore.html
+++ b/third_party/blink/web_tests/wpt_internal/app-history/navigate/state/navigate-state-cross-document-restore.html
@@ -15,7 +15,7 @@
       if (navigated_back) {
         let back_entry = i.contentWindow.appHistory.current;
         assert_equals(i.contentWindow.appHistory.entries().length, 2);
-        assert_equals(back_entry, i.contentWindow.appHistory.entries()[0]);
+        assert_equals(back_entry.index, 0);
         assert_equals(back_entry.getState().data, "value");
         t.done();
       } else {
diff --git a/third_party/blink/web_tests/wpt_internal/js-self-profiling/max-buffer-size.https.html b/third_party/blink/web_tests/wpt_internal/js-self-profiling/max-buffer-size.https.html
index af9fdc12..34c7859 100644
--- a/third_party/blink/web_tests/wpt_internal/js-self-profiling/max-buffer-size.https.html
+++ b/third_party/blink/web_tests/wpt_internal/js-self-profiling/max-buffer-size.https.html
@@ -24,12 +24,20 @@
     }, 'max buffer size is not exceeded');
 
     promise_test(async t => {
-      const profiler = await performance.profile({
-        sampleInterval: 10,
-        maxBufferSize: 1,
-      });
+      const pf = [];
+      pf[0] = await performance.profile({ sampleInterval: 10 });
+      pf[1] = await performance.profile({ sampleInterval: 10,  maxBufferSize: 1 });
 
-      const watcher = new EventWatcher(t, profiler, ['samplebufferfull']);
+      const watcher = new EventWatcher(t, pf[1], ['samplebufferfull']);
+      pf[0].addEventListener("samplebufferfull", ()=>{
+        assert_unreached("samplebufferfull invoked on wrong profiler");
+      });
+      pf[1].addEventListener("samplebufferfull", async ()=>{
+        console.log("samplebufferfull");
+        pf[0].stop();
+        pf[1].stop();
+        assertTrue(true);
+      });
 
       for (let i = 0; i < 10; i++) {
         ProfileUtils.forceSample();
diff --git a/third_party/crashpad/DEPS b/third_party/crashpad/DEPS
index 64022c3..687dab6 100644
--- a/third_party/crashpad/DEPS
+++ b/third_party/crashpad/DEPS
@@ -1,4 +1,4 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
diff --git a/third_party/metrics_proto/README.chromium b/third_party/metrics_proto/README.chromium
index 9a1c748..ece8e55 100644
--- a/third_party/metrics_proto/README.chromium
+++ b/third_party/metrics_proto/README.chromium
@@ -1,8 +1,8 @@
 Name: Metrics Protos
 Short Name: metrics_proto
 URL: This is the canonical public repository
-Version: 373260948
-Date: 2021/05/11 UTC
+Version: 373621737
+Date: 2021/05/13 UTC
 License: BSD
 Security Critical: Yes
 
diff --git a/third_party/metrics_proto/omnibox_event.proto b/third_party/metrics_proto/omnibox_event.proto
index 7dbaae4..c1f1d38 100644
--- a/third_party/metrics_proto/omnibox_event.proto
+++ b/third_party/metrics_proto/omnibox_event.proto
@@ -215,6 +215,8 @@
     // Only used by Android Chrome. Represents a suggestion showing query tiles
     // that users can tap on for bulding queries.
     QUERY_TILE = 19;
+    // Clusters generated on-device from the user's Chrome history.
+    HISTORY_CLUSTER = 20;
   }
 
   // The result set displayed on the completion popup
@@ -291,6 +293,12 @@
       CLIPBOARD_IMAGE = 29;        // An image based on the clipboard.
       TILE_SUGGESTION = 30;        // A search query from Chrome Query Tiles
                                    // feature. Only used by Android.
+      HISTORY_CLUSTER = 31;        // A past page that is a member of a cluster
+                                   // (an aggregation of related searches and
+                                   // URLs from the user's history) that
+                                   // contains the input (the input might or
+                                   // might not also match the title or URL of
+                                   // this page).
     }
     optional ResultType result_type = 2;
 
diff --git a/third_party/webgpu-cts/scripts/regenerate_internal_cts_html.py b/third_party/webgpu-cts/scripts/regenerate_internal_cts_html.py
index d3309b253..1ee3e4ad 100755
--- a/third_party/webgpu-cts/scripts/regenerate_internal_cts_html.py
+++ b/third_party/webgpu-cts/scripts/regenerate_internal_cts_html.py
@@ -11,6 +11,7 @@
 import shutil
 import subprocess
 import sys
+import logging
 
 third_party_dir = os.path.dirname(
     os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
@@ -36,7 +37,7 @@
     js_out_dir = tempfile.mkdtemp()
     contents = None
     try:
-        print('WebGPU CTS: Extracting expectation names...')
+        logging.info('WebGPU CTS: Extracting expectation names...')
         old_sys_path = sys.path
         try:
             sys.path = old_sys_path + [
@@ -53,7 +54,7 @@
             web_test_expectations = split_cts_expectations_and_web_test_expectations(
                 f.read())['web_test_expectations']['expectations']
 
-        print('WebGPU CTS: Reading manual test splits...')
+        logging.info('WebGPU CTS: Reading manual test splits...')
         with open(
                 os.path.join(third_party_dir, 'blink', 'web_tests', 'webgpu',
                              'internal_cts_test_splits.pyl')) as f:
@@ -66,7 +67,7 @@
             for test in manual_splits:
                 split_list_out.write('%s\n' % test)
 
-        print('WebGPU CTS: Transpiling tools...')
+        logging.info('WebGPU CTS: Transpiling tools...')
         compile_src_for_node(js_out_dir)
 
         old_sys_path = sys.path
@@ -76,7 +77,7 @@
         finally:
             sys.path = old_sys_path
 
-        print('WebGPU CTS: Generating cts.html...')
+        logging.info('WebGPU CTS: Generating cts.html...')
         cmd = [
             os.path.join(js_out_dir,
                          'common/tools/gen_wpt_cts_html.js'), cts_html_fname,
@@ -86,7 +87,7 @@
                          'argsprefixes.txt'), split_list_fname,
             'wpt_internal/webgpu/cts.html', 'webgpu'
         ]
-        print(RunNode(cmd))
+        logging.info(RunNode(cmd))
 
         with open(cts_html_fname, 'rb') as f:
             contents = f.read()
@@ -117,7 +118,7 @@
 
         if not check:
             shutil.rmtree(wpt_internal_dir)
-        print('WebGPU CTS: Generating HTML tests from %s...' % html_search_dir)
+        logging.info('WebGPU CTS: Generating HTML tests from %s...' % html_search_dir)
         for root, dirnames, filenames in os.walk(html_search_dir):
             for filename in filenames:
                 if filename.endswith('.html'):
diff --git a/third_party/webgpu-cts/scripts/run_webgpu_cts.py b/third_party/webgpu-cts/scripts/run_webgpu_cts.py
index 089eaa1..7099f71 100644
--- a/third_party/webgpu-cts/scripts/run_webgpu_cts.py
+++ b/third_party/webgpu-cts/scripts/run_webgpu_cts.py
@@ -10,6 +10,7 @@
 from tempfile import mkstemp
 import threading
 import os
+import logging
 
 # This script is run via //third_party/blink/tools/run_webgpu_cts.py which
 # adds blinkpy to the Python path.
@@ -78,7 +79,7 @@
                     'http://%s:%d/_start' %
                     (self.server_address[0], self.server_address[1])).read()
             except IOError as e:
-                print(e)
+                logging.warning(e)
                 continue
             return
 
@@ -90,7 +91,7 @@
                 'http://%s:%d/_stop' %
                 (self.server_address[0], self.server_address[1])).read()
         except IOError as e:
-            print(e)
+            logging.warning(e)
         self._thread.join()
         self._thread = None
 
@@ -241,14 +242,14 @@
     server = ExpectationsServer(split_result['cts_expectations_js'],
                                 ('127.0.0.1', 3000))
 
-    print('Starting expectations server...')
+    logging.info('Starting expectations server...')
     server.start()
 
     try:
         run_web_tests.main(forwarded_args, stderr)
 
     finally:
-        print('Stopping expectations server...')
+        logging.info('Stopping expectations server...')
         server.stop()
         os.close(web_test_expectations_fd)
 
diff --git a/third_party/zlib/OWNERS b/third_party/zlib/OWNERS
index 632b3f9..0bfa9fb 100644
--- a/third_party/zlib/OWNERS
+++ b/third_party/zlib/OWNERS
@@ -2,4 +2,5 @@
 cavalcantii@chromium.org
 cblume@chromium.org
 mtklein@google.com
+noel@chromium.org
 scroggo@google.com
diff --git a/tools/auto-nav.py b/tools/auto-nav.py
index 6238c39..17b61b68 100644
--- a/tools/auto-nav.py
+++ b/tools/auto-nav.py
@@ -5,7 +5,7 @@
 This script runs Chrome and automatically navigates through the given list of
 URLs the specified number of times.
 
-Usage: vpython auto-nav.py <chrome dir> <number of navigations> <url> <url> ...
+Usage: vpython3 auto-nav.py <chrome dir> <number of navigations> <url> <url> ...
 
 Optional flags:
 * --interval <seconds>, -i <seconds>: specify a number of seconds to wait
@@ -26,7 +26,7 @@
 """
 
 # [VPYTHON:BEGIN]
-# python_version: "2.7"
+# python_version: "3.8"
 # wheel: <
 #   name: "infra/python/wheels/selenium-py2_py3"
 #   version: "version:3.14.0"
@@ -37,7 +37,7 @@
 # >
 # wheel: <
 #   name: "infra/python/wheels/psutil/${vpython_platform}"
-#   version: "version:5.6.2"
+#   version: "version:5.7.2"
 # >
 # [VPYTHON:END]
 
@@ -46,16 +46,17 @@
 import subprocess
 import sys
 import time
+import urllib
 
 try:
   import psutil
   from selenium import webdriver
 except ImportError:
-  print('Error importing required modules. Run with vpython instead of python.')
+  print('Error importing required modules. Run with vpython3 instead of python.')
   sys.exit(1)
 
 DEFAULT_INTERVAL = 1
-
+EXIT_CODE_ERROR = 1
 
 # Splits list |positional_args| into two lists: |urls| and |chrome_args|, where
 # arguments starting with '-' are treated as chrome args, and the rest as URLs.
@@ -115,7 +116,12 @@
   if not args.url:
     parser.print_usage()
     print(os.path.basename(__file__) + ': error: missing URL argument')
-    exit(1)
+    exit(EXIT_CODE_ERROR)
+  for url in args.url:
+    if not urllib.parse.urlparse(url).scheme:
+      print(os.path.basename(__file__) +
+            ': error: URL is missing required scheme (e.g., "https://"): ' + url)
+      exit(EXIT_CODE_ERROR)
   return [args, chrome_args]
 
 
@@ -126,7 +132,7 @@
     print('File not found: {}.'.format(path))
     if error_message:
       print(error_message)
-    exit()
+    exit(EXIT_CODE_ERROR)
 
 
 def main():
@@ -152,7 +158,7 @@
 
   if args.start_prompt:
     driver.get(args.url[0])
-    raw_input('Press Enter to begin navigation...')
+    input('Press Enter to begin navigation...')
 
   # Start IdleWakeups, if using, passing the browser process's ID as its target.
   # IdleWakeups will monitor the browser process and its children. Other running
@@ -179,7 +185,7 @@
       time.sleep(interval)
 
   if args.exit_prompt:
-    raw_input('Press Enter to exit...')
+    input('Press Enter to exit...')
   driver.quit()
 
   # Print IdleWakeups' output, if using.
diff --git a/tools/autotest.py b/tools/autotest.py
index 90294ffd..558434b 100755
--- a/tools/autotest.py
+++ b/tools/autotest.py
@@ -53,7 +53,8 @@
 ]
 
 _TEST_TARGET_REGEX = re.compile(
-    r'(_browsertests|_junit_tests|_perftests|_test_.*apk|_unittests)$')
+    r'(_browsertests|_junit_tests|_perftests|_test_.*apk|_unittests|' +
+    r'_wpr_tests)$')
 
 TEST_FILE_NAME_REGEX = re.compile(r'(.*Test\.java)|(.*_[a-z]*test\.cc)')
 
diff --git a/tools/grit/preprocess_if_expr.gni b/tools/grit/preprocess_if_expr.gni
index 71c1cc1..64d21f9 100644
--- a/tools/grit/preprocess_if_expr.gni
+++ b/tools/grit/preprocess_if_expr.gni
@@ -2,12 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/config/python.gni")
 import("//tools/grit/grit_defines.gni")
 
 template("preprocess_if_expr") {
-  # TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
-  python2_action(target_name) {
+  action(target_name) {
     script = "//tools/grit/preprocess_if_expr.py"
 
     if (defined(invoker.deps)) {
diff --git a/tools/grit/preprocess_if_expr.py b/tools/grit/preprocess_if_expr.py
index b06735fd..b8f09da4 100644
--- a/tools/grit/preprocess_if_expr.py
+++ b/tools/grit/preprocess_if_expr.py
@@ -101,8 +101,9 @@
     manifest_data = {}
     manifest_data['base_dir'] = '%s' % args.out_folder
     manifest_data['files'] = args.in_files
-    manifest_file = open(
-        os.path.normpath(os.path.join(_CWD, args.out_manifest)), 'wb')
+    manifest_file = io.open(
+        os.path.normpath(os.path.join(_CWD, args.out_manifest)), 'w',
+        encoding='utf-8', newline='\n')
     json.dump(manifest_data, manifest_file)
   return
 
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index d81229f..e5f42ae 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -1003,7 +1003,6 @@
       'linux-clang-tidy-rel': 'release_trybot',
       'linux-dcheck-off-rel': 'release_trybot_dcheck_off',
       'linux-example-builder': 'release_trybot',
-      'linux-experimental-next-rel': 'gpu_tests_release_trybot_no_symbols_use_dummy_lastchange_code_coverage',
       'linux-extended-tracing-rel': 'release_trybot_extended_tracing',
       'linux-inverse-fieldtrials-fyi-rel': 'gpu_tests_release_trybot_no_symbols_use_dummy_lastchange_invert_fieldtrials',
       'linux-gcc-rel': 'release_bot_x86_minimal_symbols_no_clang_cxx11',
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.linux.json b/tools/mb/mb_config_expectations/tryserver.chromium.linux.json
index b69f1d90..f60cf63a 100644
--- a/tools/mb/mb_config_expectations/tryserver.chromium.linux.json
+++ b/tools/mb/mb_config_expectations/tryserver.chromium.linux.json
@@ -505,20 +505,6 @@
       "use_goma": true
     }
   },
-  "linux-experimental-next-rel": {
-    "gn_args": {
-      "coverage_instrumentation_input_file": "//.code-coverage/files_to_instrument.txt",
-      "dcheck_always_on": true,
-      "ffmpeg_branding": "Chrome",
-      "is_component_build": false,
-      "is_debug": false,
-      "proprietary_codecs": true,
-      "symbol_level": 0,
-      "use_clang_coverage": true,
-      "use_dummy_lastchange": true,
-      "use_goma": true
-    }
-  },
   "linux-extended-tracing-rel": {
     "gn_args": {
       "dcheck_always_on": true,
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index d964003..7a98865 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -3234,13 +3234,15 @@
   <int value="34" label="LaCrOS"/>
   <int value="35" label="Remote App"/>
   <int value="36" label="Borealis App"/>
-  <int value="37" label="Help App"/>
+  <int value="37" label="Help App (default or help)"/>
   <int value="38" label="Omnibox, Search Suggest Entity"/>
   <int value="39" label="Omnibox, Navsuggest"/>
   <int value="40" label="Omnibox Rich Entity, Answer"/>
   <int value="41" label="Omnibox Rich Entity, Image Entity"/>
   <int value="42" label="Local file search"/>
   <int value="43" label="Drive file search"/>
+  <int value="44" label="Help App (Updates page)"/>
+  <int value="45" label="Help App (Discover page)"/>
 </enum>
 
 <enum name="AppListSearchResultDisplayType">
@@ -40395,14 +40397,6 @@
   <int value="3" label="pointerup"/>
 </enum>
 
-<enum name="InputMethodApiOperation">
-  <int value="0" label="Unknown"/>
-  <int value="1" label="CommitText_MoveCursorAfterText"/>
-  <int value="2" label="CommitText_MoveCursorBeforeText"/>
-  <int value="3" label="SetCompositionText"/>
-  <int value="4" label="DeleteSurroundingText"/>
-</enum>
-
 <enum name="InputMethodCategory">
   <int value="0" label="Unkown"/>
   <int value="1" label="XKB">XKeyboard</int>
@@ -46998,6 +46992,7 @@
   <int value="75237697" label="ash-enable-new-overview-ui"/>
   <int value="75747474" label="disable-webview-signin-flow"/>
   <int value="77886794" label="AllowRepeatedUpdates:enabled"/>
+  <int value="77946316" label="PrefixWebAppWindowsWithAppName:disabled"/>
   <int value="78998551" label="disable-hosted-app-shim-creation"/>
   <int value="79094339" label="VrLaunchIntents:enabled"/>
   <int value="79503461" label="disable-account-consistency"/>
@@ -48937,6 +48932,7 @@
   <int value="1786386775" label="TranslateCompactUI:disabled"/>
   <int value="1786692012"
       label="AssistantEnableMediaSessionIntegration:disabled"/>
+  <int value="1787572807" label="PrefixWebAppWindowsWithAppName:enabled"/>
   <int value="1789517771" label="MacV2Sandbox:enabled"/>
   <int value="1789793147" label="HTTPSServerPreviewsUsingURLLoader:disabled"/>
   <int value="1789795039"
@@ -51120,6 +51116,11 @@
   <int value="3" label="Low and High confidence."/>
 </enum>
 
+<enum name="MBOSupport">
+  <int value="0" label="Unsupported"/>
+  <int value="1" label="Supported"/>
+</enum>
+
 <enum name="MdnsResponderServiceError">
   <int value="0" label="Fail to start manager"/>
   <int value="1" label="Fail to create responder"/>
diff --git a/tools/metrics/histograms/histograms_xml/android/histograms.xml b/tools/metrics/histograms/histograms_xml/android/histograms.xml
index ce4d542..21521c2 100644
--- a/tools/metrics/histograms/histograms_xml/android/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/android/histograms.xml
@@ -1823,6 +1823,27 @@
   </summary>
 </histogram>
 
+<histogram name="Android.Omnibox.UsedSuggestionFromCache" enum="Boolean"
+    expires_after="2021-10-04">
+  <owner>ender@chromium.org</owner>
+  <owner>jdonnelly@chromium.org</owner>
+  <owner>mpearson@chromium.org</owner>
+  <summary>
+    Records whether users interacted with suggestion originating from Java
+    cache.
+
+    Android presents the Cached suggestions for a brief time before the Native
+    libraries become available, replacing these with a fresh content as soon as
+    Autocomplete subsystem serves them. This histogram records all the events
+    where the cached suggestions were shown for an extended period of time -
+    long enough for the User to identify and interact with a suggestion of their
+    choice.
+
+    Recorded every time the User initiates navigation using the Omnibox or the
+    Suggestions list, regardless of context.
+  </summary>
+</histogram>
+
 <histogram name="Android.OmniboxFocusReason" enum="OmniboxFocusReason"
     expires_after="2021-12-01">
   <owner>mdjones@chromium.org</owner>
@@ -3289,7 +3310,7 @@
 </histogram>
 
 <histogram name="Android.WebView.SupportLibrary.ClientIsCompat"
-    enum="WebViewClientTypeEnum" expires_after="2021-05-05">
+    enum="WebViewClientTypeEnum" expires_after="2021-11-13">
   <owner>laisminchillo@chromium.org</owner>
   <owner>ntfschr@chromium.org</owner>
   <owner>src/android_webview/OWNERS</owner>
diff --git a/tools/metrics/histograms/histograms_xml/blink/histograms.xml b/tools/metrics/histograms/histograms_xml/blink/histograms.xml
index d5a3e3a..3abcc6e 100644
--- a/tools/metrics/histograms/histograms_xml/blink/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/blink/histograms.xml
@@ -483,6 +483,37 @@
   </summary>
 </histogram>
 
+<histogram name="Blink.Canvas.WebGPUMaxRecycledResourcesCount"
+    units="Recyclable resources" expires_after="2021-11-06">
+  <owner>magchen@chromium.org</owner>
+  <owner>enga@chromium.org</owner>
+  <summary>
+    The maximum number of total unused recyclable WebGPU resources since last
+    clean-up. Logged in the WebGPU recyclable resouce clean-up timer function.
+  </summary>
+</histogram>
+
+<histogram name="Blink.Canvas.WebGPUMaxRecycledResourcesInKB" units="KB"
+    expires_after="2021-11-06">
+  <owner>magchen@chromium.org</owner>
+  <owner>enga@chromium.org</owner>
+  <summary>
+    The maximum size of total unused recyclable WebGPU resources in KB since
+    last clean-up. Logged in the WebGPU recyclable resouce clean-up timer
+    function.
+  </summary>
+</histogram>
+
+<histogram name="Blink.Canvas.WebGPUStaleResourceCount"
+    units="recyclable resources" expires_after="2021-11-06">
+  <owner>magchen@chromium.org</owner>
+  <owner>enga@chromium.org</owner>
+  <summary>
+    The number of stale recyclable WebGPU canvas resources released and logged
+    in the WebGPU recyclable resouce clean-up timer function.
+  </summary>
+</histogram>
+
 <histogram name="Blink.Canvas.WillReadFrequently"
     enum="BooleanWillReadFrequently" expires_after="2021-01-31">
   <owner>fserb@chromium.org</owner>
@@ -2883,6 +2914,18 @@
   </details>
 </histogram>
 
+<histogram name="Blink.UseCounter.PermissionsPolicy.Violation.Enforce"
+    enum="FeaturePolicyFeature" expires_after="2021-10-31">
+  <owner>iclelland@chromium.org</owner>
+  <owner>feature-control@chromium.org</owner>
+  <summary>
+    Counts the actual enforced permissions policy violation. The metrics is
+    triggered when ExecutionContext::IsFeatureEnabled with
+    ReportOptions::ReportOnFailure as param returns false, at most once per page
+    visit.
+  </summary>
+</histogram>
+
 <histogram base="true" name="Blink.UserDrivenDocumentUpdate.UpdateTime"
     units="microseconds" expires_after="2021-11-07">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimePreFCPSuffixes" -->
diff --git a/tools/metrics/histograms/histograms_xml/network/histograms.xml b/tools/metrics/histograms/histograms_xml/network/histograms.xml
index 035d080..2e437116 100644
--- a/tools/metrics/histograms/histograms_xml/network/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/network/histograms.xml
@@ -1756,6 +1756,17 @@
   </summary>
 </histogram>
 
+<histogram name="Network.Shill.WiFi.MBOSupport" enum="MBOSupport"
+    expires_after="2021-12-01">
+  <owner>matthewmwang@google.com</owner>
+  <owner>cros-network-metrics@google.com</owner>
+  <summary>
+    Chrome OS network metric that tracks the Multi-Band Operation (MBO) support
+    of access points that devices connect to. Results are recorded every time a
+    device connects to an access point.
+  </summary>
+</histogram>
+
 <histogram name="Network.Shill.Wifi.NeighborLinkMonitorFailure"
     enum="NeighborLinkMonitorFailureType" expires_after="2021-12-01">
   <owner>jiejiang@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/others/histograms.xml b/tools/metrics/histograms/histograms_xml/others/histograms.xml
index 84899b2..dfd0a856 100644
--- a/tools/metrics/histograms/histograms_xml/others/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/others/histograms.xml
@@ -8445,6 +8445,18 @@
   </summary>
 </histogram>
 
+<histogram name="LanguageUsage.UI.Android.OverrideLanguage"
+    enum="CLD3LanguageCode" expires_after="2021-12-01">
+  <owner>perrier@chromium.org</owner>
+  <owner>chrome-language@google.com</owner>
+  <summary>
+    The ISO-639 language code for the Android override language. If no override
+    is set the empty string is recorded.
+
+    Reported once per application start on Android.
+  </summary>
+</histogram>
+
 <histogram name="Launch.FlagsAtStartup" enum="LoginCustomFlags"
     expires_after="never">
 <!-- expires-never: monitors use of all flags. -->
diff --git a/tools/metrics/histograms/histograms_xml/stability/histograms.xml b/tools/metrics/histograms/histograms_xml/stability/histograms.xml
index ef1a891..ed26a019 100644
--- a/tools/metrics/histograms/histograms_xml/stability/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/stability/histograms.xml
@@ -556,7 +556,7 @@
 </histogram>
 
 <histogram name="Stability.iOS.UTE.MobileSessionOOMShutdownHint"
-    enum="OOMShutdownHint" expires_after="2021-06-22">
+    enum="OOMShutdownHint" expires_after="2022-05-11">
   <owner>olivierrobin@chromium.org</owner>
   <owner>sdefresne@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/subresource/histograms.xml b/tools/metrics/histograms/histograms_xml/subresource/histograms.xml
index 66d2a1b8..1cf9a3a 100644
--- a/tools/metrics/histograms/histograms_xml/subresource/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/subresource/histograms.xml
@@ -647,7 +647,7 @@
 </histogram>
 
 <histogram name="SubresourceRedirect.Blink.Ineligibility"
-    enum="BlinkSubresourceRedirectIneligibility" expires_after="2021-10-10">
+    enum="BlinkSubresourceRedirectIneligibility" expires_after="M96">
   <owner>rajendrant@chromium.org</owner>
   <owner>mcrouse@chromium.org</owner>
   <summary>
@@ -657,7 +657,7 @@
 </histogram>
 
 <histogram name="SubresourceRedirect.BypassDuration" units="ms"
-    expires_after="M92">
+    expires_after="M96">
   <owner>rajendrant@chromium.org</owner>
   <owner>mcrouse@chromium.org</owner>
   <summary>
@@ -670,7 +670,7 @@
 </histogram>
 
 <histogram name="SubresourceRedirect.CompressionAttempt.ResponseCode"
-    enum="HttpResponseCode" expires_after="2021-10-25">
+    enum="HttpResponseCode" expires_after="M96">
   <owner>robertogden@chromium.org</owner>
   <owner>tbansal@chromium.org</owner>
   <summary>
@@ -682,7 +682,7 @@
 </histogram>
 
 <histogram name="SubresourceRedirect.CompressionAttempt.ServerResponded"
-    enum="Boolean" expires_after="M92">
+    enum="Boolean" expires_after="M96">
   <owner>robertogden@chromium.org</owner>
   <owner>tbansal@chromium.org</owner>
   <summary>
@@ -693,7 +693,7 @@
 </histogram>
 
 <histogram name="SubresourceRedirect.CompressionFetchTimeout" enum="Boolean"
-    expires_after="M92">
+    expires_after="M96">
   <owner>rajendrant@chromium.org</owner>
   <owner>mcrouse@chromium.org</owner>
   <summary>
@@ -703,7 +703,7 @@
 </histogram>
 
 <histogram name="SubresourceRedirect.DidCompress.BytesSaved" units="bytes"
-    expires_after="2021-10-10">
+    expires_after="M96">
   <owner>robertogden@chromium.org</owner>
   <owner>tbansal@chromium.org</owner>
   <summary>
@@ -713,7 +713,7 @@
 </histogram>
 
 <histogram name="SubresourceRedirect.DidCompress.CompressionPercent" units="%"
-    expires_after="2021-10-10">
+    expires_after="M96">
   <owner>robertogden@chromium.org</owner>
   <owner>tbansal@chromium.org</owner>
   <summary>
@@ -723,7 +723,7 @@
 </histogram>
 
 <histogram name="SubresourceRedirect.ImageCompressionNotificationInfoBar"
-    enum="HttpsImageCompressionInfoBarAction" expires_after="2021-10-25">
+    enum="HttpsImageCompressionInfoBarAction" expires_after="M96">
   <owner>rajendrant@chromium.org</owner>
   <owner>src/components/data_reduction_proxy/OWNERS</owner>
   <summary>
@@ -733,7 +733,7 @@
 </histogram>
 
 <histogram name="SubresourceRedirect.LitePagesService.BypassResult"
-    enum="Boolean" expires_after="M92">
+    enum="Boolean" expires_after="M96">
   <owner>rajendrant@chromium.org</owner>
   <owner>mcrouse@chromium.org</owner>
   <summary>
@@ -744,7 +744,7 @@
 </histogram>
 
 <histogram name="SubresourceRedirect.LoginRobotsDeciderAgent.RedirectResult"
-    enum="SubresourceRedirectRedirectResult" expires_after="M92">
+    enum="SubresourceRedirectRedirectResult" expires_after="M96">
   <owner>rajendrant@chromium.org</owner>
   <owner>mcrouse@chromium.org</owner>
   <summary>
@@ -755,7 +755,7 @@
 </histogram>
 
 <histogram name="SubresourceRedirect.PageLoad.BypassResult" enum="Boolean"
-    expires_after="M92">
+    expires_after="M96">
   <obsolete>
     Replaced by SubresourceRedirect.LitePagesService.BypassResult on 11/2020
   </obsolete>
@@ -768,7 +768,7 @@
 </histogram>
 
 <histogram name="SubresourceRedirect.RobotRulesDecider.ApplyDuration"
-    units="ms" expires_after="M92">
+    units="ms" expires_after="M96">
   <owner>rajendrant@chromium.org</owner>
   <owner>mcrouse@chromium.org</owner>
   <summary>
@@ -780,7 +780,7 @@
 </histogram>
 
 <histogram name="SubresourceRedirect.RobotRulesDecider.Count" units="count"
-    expires_after="M92">
+    expires_after="M96">
   <owner>rajendrant@chromium.org</owner>
   <owner>mcrouse@chromium.org</owner>
   <summary>
@@ -791,7 +791,7 @@
 </histogram>
 
 <histogram name="SubresourceRedirect.RobotRulesDecider.ReceiveResult"
-    enum="SubresourceRedirectRobotsRulesReceiveResult" expires_after="M92">
+    enum="SubresourceRedirectRobotsRulesReceiveResult" expires_after="M96">
   <owner>rajendrant@chromium.org</owner>
   <owner>mcrouse@chromium.org</owner>
   <summary>
@@ -802,7 +802,7 @@
 </histogram>
 
 <histogram name="SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit"
-    units="BooleanCacheHit" expires_after="M92">
+    units="BooleanCacheHit" expires_after="M96">
   <owner>rajendrant@chromium.org</owner>
   <owner>mcrouse@chromium.org</owner>
   <summary>
@@ -813,7 +813,7 @@
 </histogram>
 
 <histogram name="SubresourceRedirect.RobotsRulesFetcher.CacheHit" units="ms"
-    expires_after="M92">
+    expires_after="M96">
   <owner>rajendrant@chromium.org</owner>
   <owner>mcrouse@chromium.org</owner>
   <summary>
@@ -823,7 +823,7 @@
 </histogram>
 
 <histogram name="SubresourceRedirect.RobotsRulesFetcher.NetErrorCode"
-    enum="NetErrorCodes" expires_after="M92">
+    enum="NetErrorCodes" expires_after="M96">
   <owner>rajendrant@chromium.org</owner>
   <owner>mcrouse@chromium.org</owner>
   <summary>
@@ -833,7 +833,7 @@
 </histogram>
 
 <histogram name="SubresourceRedirect.RobotsRulesFetcher.ResponseCode"
-    units="HttpResponseCode" expires_after="M92">
+    units="HttpResponseCode" expires_after="M96">
   <owner>rajendrant@chromium.org</owner>
   <owner>mcrouse@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index 988bacf0..68b537c 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -7375,29 +7375,6 @@
   </metric>
 </event>
 
-<event name="InputMethod.NonCompliantApi">
-  <owner>shend@chromium.org</owner>
-  <summary>
-    Metrics indicating what Input Method Editor (IME) operations are behaving
-    incorrectly on an input field. This event is recorded whenever an IME
-    operation is executed on the input field but the result does not match the
-    IME's expectations (e.g. IME wants to insert 'a' but the input field
-    inserted 'b' instead).
-  </summary>
-  <metric name="NonCompliantOperation" enum="InputMethodApiOperation">
-    <summary>
-      The operation that behaved incorrectly.
-    </summary>
-    <aggregation>
-      <history>
-        <statistics>
-          <enumeration/>
-        </statistics>
-      </history>
-    </aggregation>
-  </metric>
-</event>
-
 <event name="InstalledRelatedApps">
   <owner>rayankans@chromium.org</owner>
   <owner>peter@chromium.org</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 78b6bb22..a828be97 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -1,12 +1,12 @@
 {
     "trace_processor_shell": {
         "win": {
-            "hash": "59d3a55b90b81f37cdbe4ffaee5a8d2962540ed8",
-            "remote_path": "perfetto_binaries/trace_processor_shell/win/022251faee35ed4b87d88a0e6afa9b99f97dfded/trace_processor_shell.exe"
+            "hash": "0b862ab5462ce76e070e5cc8da2bfef9657fec01",
+            "remote_path": "perfetto_binaries/trace_processor_shell/win/5e76bff1ab36ae7b07baa0ee2cad749954312590/trace_processor_shell.exe"
         },
         "mac": {
-            "hash": "34396bae5611f54e0b3559df1f579ac2372d2b59",
-            "remote_path": "perfetto_binaries/trace_processor_shell/mac/022251faee35ed4b87d88a0e6afa9b99f97dfded/trace_processor_shell"
+            "hash": "a46eed3a514ac383ab1120c55a2bf90dcd3ba99b",
+            "remote_path": "perfetto_binaries/trace_processor_shell/mac/5e76bff1ab36ae7b07baa0ee2cad749954312590/trace_processor_shell"
         },
         "linux": {
             "hash": "7c885e2fe6c6803c01bfa03fa68b5af7da0a3f01",
diff --git a/tools/win/IdleWakeups/README.md b/tools/win/IdleWakeups/README.md
index ffde021..32093fd 100644
--- a/tools/win/IdleWakeups/README.md
+++ b/tools/win/IdleWakeups/README.md
@@ -23,7 +23,7 @@
 the parameter is numeric and a valid process ID, it is treated as a process ID.
 
 When the tool starts it begins gathering and aggregating CPU usage, private
-working set size, number of context switches / sec, and power usage for all
+commit, number of context switches / sec, power usage, and handle counts for all
 matched processes. Hit Ctrl-C to stop the measurements and print average and
 median values over the entire measurement interval.
 
diff --git a/tools/win/IdleWakeups/idle_wakeups.cpp b/tools/win/IdleWakeups/idle_wakeups.cpp
index defab31d6..5549eb4a 100644
--- a/tools/win/IdleWakeups/idle_wakeups.cpp
+++ b/tools/win/IdleWakeups/idle_wakeups.cpp
@@ -22,7 +22,7 @@
   DWORD handle_count;
   double cpu_usage_percent;
   double cpu_usage_seconds;
-  ULONGLONG working_set;
+  ULONGLONG memory;  // Private commit
   double power;
 };
 
@@ -41,8 +41,8 @@
 double GetCpuUsageSeconds(const Result& r) {
   return r.cpu_usage_seconds;
 }
-ULONGLONG GetWorkingSet(const Result& r) {
-  return r.working_set;
+ULONGLONG GetMemory(const Result& r) {
+  return r.memory;
 }
 double GetPower(const Result& r) {
   return r.power;
@@ -214,7 +214,7 @@
                                   const ProcessDataSnapshot& snapshot) {
   ULONG idle_wakeups_delta = 0;
   ULONGLONG cpu_usage_delta = 0;
-  ULONGLONG total_working_set = 0;
+  ULONGLONG total_memory = 0;
   DWORD total_handle_count = 0;
 
   ProcessDataMap::const_iterator prev_it = prev_snapshot.processes.begin();
@@ -257,7 +257,7 @@
     }
 
     cpu_usage_delta += process_data.cpu_time - prev_process_cpu_time;
-    total_working_set += process_data.working_set / 1024;
+    total_memory += process_data.memory / 1024;
     total_handle_count += process_data.handle_count;
   }
 
@@ -268,7 +268,7 @@
   result.cpu_usage_percent =
       (double)cpu_usage_delta * 100 / (time_delta * kTicksPerSecond);
   result.cpu_usage_seconds = (double)cpu_usage_delta / kTicksPerSecond;
-  result.working_set = total_working_set;
+  result.memory = total_memory;
   result.handle_count = total_handle_count;
 
   return result;
@@ -293,9 +293,8 @@
       "------------------------------------------------------------------------"
       "--------------------\n");
   printf(
-      "                                                            Private\n"
-      "                       Context switches/sec    CPU usage    Working set "
-      "     Power   Handles\n");
+      "                       Context switches/sec    CPU usage   Private "
+      "Commit    Power   Handles\n");
   printf(
       "------------------------------------------------------------------------"
       "--------------------\n");
@@ -385,7 +384,7 @@
              result.idle_wakeups_per_sec,
              cpu_usage_in_seconds ? result.cpu_usage_seconds
                                   : result.cpu_usage_percent,
-             cpu_usage_unit, result.working_set / 1024.0, result.power,
+             cpu_usage_unit, result.memory / 1024.0, result.power,
              result.handle_count);
     }
 
@@ -410,7 +409,7 @@
       GetAverage(results, GetIdleWakeupsPerSec);
   average_result.cpu_usage_percent = GetAverage(results, GetCpuUsagePercent);
   average_result.cpu_usage_seconds = GetAverage(results, GetCpuUsageSeconds);
-  average_result.working_set = GetAverage(results, GetWorkingSet);
+  average_result.memory = GetAverage(results, GetMemory);
   average_result.power = GetAverage(results, GetPower);
   average_result.handle_count = GetAverage(results, GetHandleCount);
 
@@ -422,13 +421,13 @@
     printf(
         "Processes created\tProcesses destroyed\t"
         "Context switches/sec, average\tCPU usage (%%), average\t"
-        "CPU usage (s)\tPrivate working set (MiB), average\t"
+        "CPU usage (s)\tPrivate commit (MiB), average\t"
         "Power (W), average\n");
     printf("%zu\t%zu\t%20lu\t%8.2f\t%8.2f\t%7.2f\t%5.2f\n",
            cumulative_processes_created, cumulative_processes_destroyed,
            average_result.idle_wakeups_per_sec,
            average_result.cpu_usage_percent, cumulative_cpu_usage_seconds,
-           average_result.working_set / 1024.0, average_result.power);
+           average_result.memory / 1024.0, average_result.power);
     return 0;
   }
 
@@ -438,15 +437,15 @@
          average_result.idle_wakeups_per_sec,
          cpu_usage_in_seconds ? average_result.cpu_usage_seconds
                               : average_result.cpu_usage_percent,
-         cpu_usage_unit, average_result.working_set / 1024.0,
-         average_result.power, average_result.handle_count);
+         cpu_usage_unit, average_result.memory / 1024.0, average_result.power,
+         average_result.handle_count);
 
   Result median_result;
   median_result.idle_wakeups_per_sec =
       GetMedian(&results, GetIdleWakeupsPerSec);
   median_result.cpu_usage_percent = GetMedian(&results, GetCpuUsagePercent);
   median_result.cpu_usage_seconds = GetMedian(&results, GetCpuUsageSeconds);
-  median_result.working_set = GetMedian(&results, GetWorkingSet);
+  median_result.memory = GetMedian(&results, GetMemory);
   median_result.power = GetMedian(&results, GetPower);
   median_result.handle_count = GetMedian(&results, GetHandleCount);
 
@@ -454,8 +453,8 @@
          median_result.idle_wakeups_per_sec,
          cpu_usage_in_seconds ? median_result.cpu_usage_seconds
                               : median_result.cpu_usage_percent,
-         cpu_usage_unit, median_result.working_set / 1024.0,
-         median_result.power, median_result.handle_count);
+         cpu_usage_unit, median_result.memory / 1024.0, median_result.power,
+         median_result.handle_count);
 
   if (cpu_usage_in_seconds) {
     printf("                Sum    %32.2f%c\n", cumulative_cpu_usage_seconds,
diff --git a/tools/win/IdleWakeups/system_information_sampler.cpp b/tools/win/IdleWakeups/system_information_sampler.cpp
index 8db4e47..8d67a1e 100644
--- a/tools/win/IdleWakeups/system_information_sampler.cpp
+++ b/tools/win/IdleWakeups/system_information_sampler.cpp
@@ -239,7 +239,14 @@
 ProcessData GetProcessData(const SYSTEM_PROCESS_INFORMATION* const pi) {
   ProcessData process_data;
   process_data.cpu_time = pi->KernelTime + pi->UserTime;
-  process_data.working_set = pi->WorkingSetPrivateSize;
+  // The PagefileUsage member measures Private Commit. Presumably the name was
+  // chosen because all private commit has to be backed by either memory or the
+  // page file. Private Commit is the standard measure for memory in Chromium,
+  // including in the Memory footprint column in Chrome's task manager.
+  // Private Commit is a much more stable and meaningful number than private
+  // working set which can be affected by memory pressure or other factors that
+  // cause Windows to drain the working set and page out or compress the memory.
+  process_data.memory = pi->VirtualMemoryCounters.PagefileUsage;
   process_data.handle_count = pi->HandleCount;
 
   // Iterate over threads and store each thread's ID and number of context
@@ -306,8 +313,8 @@
       if (target_process_id_ > 0) {
         // If |pi| or its parent has the targeted process ID, add its data to
         // the snapshot.
-        if (reinterpret_cast<DWORD>(pi->ProcessId) == target_process_id_ ||
-            reinterpret_cast<DWORD>(pi->ParentProcessId) ==
+        if (reinterpret_cast<uintptr_t>(pi->ProcessId) == target_process_id_ ||
+            reinterpret_cast<uintptr_t>(pi->ParentProcessId) ==
                 target_process_id_) {
           snapshot->processes.insert(
               std::make_pair(pi->ProcessId, GetProcessData(pi)));
diff --git a/tools/win/IdleWakeups/system_information_sampler.h b/tools/win/IdleWakeups/system_information_sampler.h
index b1b1a3fc..148464e 100644
--- a/tools/win/IdleWakeups/system_information_sampler.h
+++ b/tools/win/IdleWakeups/system_information_sampler.h
@@ -27,7 +27,7 @@
 // Contains per process data stored in each data snapshot.
 struct ProcessData {
   ULONGLONG cpu_time;
-  ULONGLONG working_set;
+  ULONGLONG memory;  // Private commit
   DWORD handle_count;
   ThreadsVector threads;
 };
diff --git a/ui/accelerated_widget_mac/ca_transaction_observer.mm b/ui/accelerated_widget_mac/ca_transaction_observer.mm
index af02cc2..03bdf5f 100644
--- a/ui/accelerated_widget_mac/ca_transaction_observer.mm
+++ b/ui/accelerated_widget_mac/ca_transaction_observer.mm
@@ -13,11 +13,11 @@
 #import <CoreFoundation/CoreFoundation.h>
 #import <QuartzCore/QuartzCore.h>
 
-typedef enum {
+typedef NS_ENUM(unsigned int, CATransactionPhase) {
   kCATransactionPhasePreLayout,
   kCATransactionPhasePreCommit,
   kCATransactionPhasePostCommit,
-} CATransactionPhase;
+};
 
 @interface CATransaction ()
 + (void)addCommitHandler:(void (^)(void))block
diff --git a/ui/base/idle/idle_linux.cc b/ui/base/idle/idle_linux.cc
index a5d92d0..a9c1faf 100644
--- a/ui/base/idle/idle_linux.cc
+++ b/ui/base/idle/idle_linux.cc
@@ -18,7 +18,7 @@
 
 #if defined(USE_X11)
 #include "ui/base/x/x11_idle_query.h"
-#include "ui/base/x/x11_screensaver_window_finder.h"
+#include "ui/base/x/x11_screensaver.h"
 #else
 #include "base/notreached.h"
 #endif
@@ -202,7 +202,7 @@
 #endif
 #if defined(USE_X11)
   // Usually the screensaver is used to lock the screen.
-  return ScreensaverWindowFinder::ScreensaverWindowExists();
+  return IsXScreensaverActive();
 #else
   NOTIMPLEMENTED_LOG_ONCE();
   return false;
diff --git a/ui/base/ime/chromeos/BUILD.gn b/ui/base/ime/chromeos/BUILD.gn
index 76365cb..5bc36430 100644
--- a/ui/base/ime/chromeos/BUILD.gn
+++ b/ui/base/ime/chromeos/BUILD.gn
@@ -54,8 +54,6 @@
     "input_method_descriptor.h",
     "input_method_manager.cc",
     "input_method_manager.h",
-    "input_method_ukm.cc",
-    "input_method_ukm.h",
     "input_method_util.cc",
     "input_method_util.h",
   ]
@@ -73,10 +71,8 @@
     "//build:branding_buildflags",
     "//chromeos/services/ime/public/mojom",
     "//chromeos/system",
-    "//services/metrics/public/cpp:ukm_builders",
     "//third_party/icu",
     "//ui/base",
-    "//ui/base",
     "//ui/chromeos/strings",
     "//ui/ozone:ozone_base",
   ]
diff --git a/ui/base/ime/chromeos/ime_input_context_handler_interface.h b/ui/base/ime/chromeos/ime_input_context_handler_interface.h
index 59c64f54..7664456 100644
--- a/ui/base/ime/chromeos/ime_input_context_handler_interface.h
+++ b/ui/base/ime/chromeos/ime_input_context_handler_interface.h
@@ -83,9 +83,6 @@
 
   // Returns true if there is any composition text.
   virtual bool HasCompositionText() = 0;
-
-  // Returns the ukm::SourceId that identifies the currently focused client.
-  virtual ukm::SourceId GetClientSourceForMetrics() = 0;
 };
 
 }  // namespace ui
diff --git a/ui/base/ime/chromeos/input_method_chromeos.cc b/ui/base/ime/chromeos/input_method_chromeos.cc
index 9a0556c..297e5fe 100644
--- a/ui/base/ime/chromeos/input_method_chromeos.cc
+++ b/ui/base/ime/chromeos/input_method_chromeos.cc
@@ -912,11 +912,6 @@
   return client && client->HasCompositionText();
 }
 
-ukm::SourceId InputMethodChromeOS::GetClientSourceForMetrics() {
-  TextInputClient* client = GetTextInputClient();
-  return client ? client->GetClientSourceForMetrics() : ukm::kInvalidSourceId;
-}
-
 InputMethod* InputMethodChromeOS::GetInputMethod() {
   return this;
 }
diff --git a/ui/base/ime/chromeos/input_method_chromeos.h b/ui/base/ime/chromeos/input_method_chromeos.h
index 5881d00f..787a5bca 100644
--- a/ui/base/ime/chromeos/input_method_chromeos.h
+++ b/ui/base/ime/chromeos/input_method_chromeos.h
@@ -80,7 +80,6 @@
   InputMethod* GetInputMethod() override;
   void ConfirmCompositionText(bool reset_engine, bool keep_selection) override;
   bool HasCompositionText() override;
-  ukm::SourceId GetClientSourceForMetrics() override;
 
  protected:
   // Converts |text| into CompositionText.
diff --git a/ui/base/ime/chromeos/input_method_ukm.cc b/ui/base/ime/chromeos/input_method_ukm.cc
deleted file mode 100644
index 2ff9a22..0000000
--- a/ui/base/ime/chromeos/input_method_ukm.cc
+++ /dev/null
@@ -1,21 +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 "ui/base/ime/chromeos/input_method_ukm.h"
-
-#include "services/metrics/public/cpp/ukm_builders.h"
-#include "ui/base/ui_base_features.h"
-
-namespace ui {
-
-void RecordUkmNonCompliantApi(ukm::SourceId source, const int64_t operation) {
-  if (source == ukm::kInvalidSourceId)
-    return;
-
-  ukm::builders::InputMethod_NonCompliantApi(source)
-      .SetNonCompliantOperation(operation)
-      .Record(ukm::UkmRecorder::Get());
-}
-
-}  // namespace ui
diff --git a/ui/base/ime/chromeos/input_method_ukm.h b/ui/base/ime/chromeos/input_method_ukm.h
deleted file mode 100644
index b44d3033..0000000
--- a/ui/base/ime/chromeos/input_method_ukm.h
+++ /dev/null
@@ -1,23 +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 UI_BASE_IME_CHROMEOS_INPUT_METHOD_UKM_H_
-#define UI_BASE_IME_CHROMEOS_INPUT_METHOD_UKM_H_
-
-#include "base/component_export.h"
-#include "services/metrics/public/cpp/ukm_source_id.h"
-#include "ui/base/ime/text_input_type.h"
-
-namespace ui {
-
-// Records an event in UKM, under the InputMethod.NonCompliantApi metric.
-// Ignores invalid sources.
-// `operation` is a value in the chromeos.ime.mojom.InputMethodApiOperation
-// enum.
-COMPONENT_EXPORT(UI_BASE_IME_CHROMEOS)
-void RecordUkmNonCompliantApi(ukm::SourceId source, int64_t operation);
-
-}  // namespace ui
-
-#endif  // UI_BASE_IME_CHROMEOS_INPUT_METHOD_UKM_H_
diff --git a/ui/base/ime/chromeos/mock_ime_input_context_handler.cc b/ui/base/ime/chromeos/mock_ime_input_context_handler.cc
index 534084d..45d14e9 100644
--- a/ui/base/ime/chromeos/mock_ime_input_context_handler.cc
+++ b/ui/base/ime/chromeos/mock_ime_input_context_handler.cc
@@ -136,8 +136,4 @@
   return !last_update_composition_arg_.composition_text.text.empty();
 }
 
-ukm::SourceId MockIMEInputContextHandler::GetClientSourceForMetrics() {
-  return ukm::kInvalidSourceId;
-}
-
 }  // namespace ui
diff --git a/ui/base/ime/chromeos/mock_ime_input_context_handler.h b/ui/base/ime/chromeos/mock_ime_input_context_handler.h
index ed481d5..f5b5b88 100644
--- a/ui/base/ime/chromeos/mock_ime_input_context_handler.h
+++ b/ui/base/ime/chromeos/mock_ime_input_context_handler.h
@@ -63,7 +63,6 @@
   InputMethod* GetInputMethod() override;
   void ConfirmCompositionText(bool reset_engine, bool keep_selection) override;
   bool HasCompositionText() override;
-  ukm::SourceId GetClientSourceForMetrics() override;
 
   std::vector<GrammarFragment> get_grammar_fragments() const {
     return grammar_fragments_;
diff --git a/ui/base/ime/fake_text_input_client.cc b/ui/base/ime/fake_text_input_client.cc
index 72be51d..d0657fc20 100644
--- a/ui/base/ime/fake_text_input_client.cc
+++ b/ui/base/ime/fake_text_input_client.cc
@@ -20,10 +20,6 @@
   text_input_type_ = text_input_type;
 }
 
-void FakeTextInputClient::set_source_id(ukm::SourceId source_id) {
-  source_id_ = source_id;
-}
-
 void FakeTextInputClient::SetTextAndSelection(const std::u16string& text,
                                               gfx::Range selection) {
   DCHECK_LE(selection_.end(), text.length());
@@ -148,7 +144,7 @@
     TextEditCommand command) {}
 
 ukm::SourceId FakeTextInputClient::GetClientSourceForMetrics() const {
-  return source_id_;
+  return {};
 }
 
 bool FakeTextInputClient::ShouldDoLearning() {
diff --git a/ui/base/ime/fake_text_input_client.h b/ui/base/ime/fake_text_input_client.h
index 14ca9be5..b68baab 100644
--- a/ui/base/ime/fake_text_input_client.h
+++ b/ui/base/ime/fake_text_input_client.h
@@ -25,7 +25,6 @@
   ~FakeTextInputClient() override;
 
   void set_text_input_type(TextInputType text_input_type);
-  void set_source_id(ukm::SourceId source_id);
   void SetTextAndSelection(const std::u16string& text, gfx::Range selection);
 
   const std::u16string& text() const { return text_; }
@@ -97,7 +96,6 @@
   gfx::Range composition_range_;
   std::vector<ui::ImeTextSpan> ime_text_spans_;
   gfx::Range autocorrect_range_;
-  ukm::SourceId source_id_;
 };
 
 }  // namespace ui
diff --git a/ui/base/x/BUILD.gn b/ui/base/x/BUILD.gn
index 8dd502b..5f90ba68 100644
--- a/ui/base/x/BUILD.gn
+++ b/ui/base/x/BUILD.gn
@@ -44,8 +44,8 @@
     "x11_move_loop_delegate.h",
     "x11_pointer_grab.cc",
     "x11_pointer_grab.h",
-    "x11_screensaver_window_finder.cc",
-    "x11_screensaver_window_finder.h",
+    "x11_screensaver.cc",
+    "x11_screensaver.h",
     "x11_shm_image_pool.cc",
     "x11_shm_image_pool.h",
     "x11_software_bitmap_presenter.cc",
diff --git a/ui/base/x/x11_screensaver.cc b/ui/base/x/x11_screensaver.cc
new file mode 100644
index 0000000..32d74ff
--- /dev/null
+++ b/ui/base/x/x11_screensaver.cc
@@ -0,0 +1,99 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/x/x11_screensaver.h"
+
+#include <memory>
+
+#include "base/command_line.h"
+#include "base/no_destructor.h"
+#include "base/notreached.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/gfx/switches.h"
+#include "ui/gfx/x/connection.h"
+#include "ui/gfx/x/property_cache.h"
+#include "ui/gfx/x/screensaver.h"
+#include "ui/gfx/x/x11_atom_cache.h"
+#include "ui/gfx/x/xproto_util.h"
+
+namespace ui {
+
+namespace {
+
+bool IsMitScreensaverActive(x11::ScreenSaver::State state) {
+  switch (state) {
+    case x11::ScreenSaver::State::Off:
+    case x11::ScreenSaver::State::Disabled:
+      return false;
+    case x11::ScreenSaver::State::On:
+    case x11::ScreenSaver::State::Cycle:
+      return true;
+  }
+  NOTREACHED();
+  return false;
+}
+
+class ScreensaverStatusWatcher : public x11::EventObserver {
+ public:
+  ScreensaverStatusWatcher() {
+    auto* connection = x11::Connection::Get();
+
+    x_screensaver_status_ = std::make_unique<x11::PropertyCache>(
+        connection, connection->default_root(),
+        std::vector<x11::Atom>{x11::GetAtom("_SCREENSAVER_STATUS")});
+
+    // Let the server know the client version before making any requests.
+    connection->screensaver().QueryVersion(
+        {x11::ScreenSaver::major_version, x11::ScreenSaver::minor_version});
+
+    connection->AddEventObserver(this);
+    connection->screensaver().SelectInput(connection->default_root(),
+                                          x11::ScreenSaver::Event::NotifyMask);
+
+    auto reply =
+        connection->screensaver().QueryInfo(connection->default_root()).Sync();
+    if (reply) {
+      mit_screensaver_active_ = IsMitScreensaverActive(
+          static_cast<x11::ScreenSaver::State>(reply->state));
+    }
+  }
+
+  ScreensaverStatusWatcher(const ScreensaverStatusWatcher&) = delete;
+  ScreensaverStatusWatcher& operator=(const ScreensaverStatusWatcher&) = delete;
+
+  ~ScreensaverStatusWatcher() override = default;
+
+  bool ScreensaverActive() {
+    if (mit_screensaver_active_)
+      return true;
+
+    // Ironically, xscreensaver does not use the MIT-SCREENSAVER extension,
+    // so add a special check for xscreensaver.
+    auto* status = x_screensaver_status_->GetAs<x11::Atom>(
+        x11::GetAtom("_SCREENSAVER_STATUS"));
+    return status && *status == x11::GetAtom("LOCK");
+  }
+
+ private:
+  void OnEvent(const x11::Event& event) override {
+    if (auto* notify = event.As<x11::ScreenSaver::NotifyEvent>())
+      mit_screensaver_active_ = IsMitScreensaverActive(notify->state);
+  }
+
+  std::unique_ptr<x11::PropertyCache> x_screensaver_status_;
+  bool mit_screensaver_active_ = false;
+};
+
+}  // namespace
+
+bool IsXScreensaverActive() {
+  // Avoid calling into potentially missing X11 APIs in headless mode.
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kHeadless))
+    return false;
+
+  static base::NoDestructor<ScreensaverStatusWatcher> watcher;
+  return watcher->ScreensaverActive();
+}
+
+}  // namespace ui
diff --git a/ui/base/x/x11_screensaver.h b/ui/base/x/x11_screensaver.h
new file mode 100644
index 0000000..cb67abd
--- /dev/null
+++ b/ui/base/x/x11_screensaver.h
@@ -0,0 +1,16 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_X_X11_SCREENSAVER_H_
+#define UI_BASE_X_X11_SCREENSAVER_H_
+
+#include "base/component_export.h"
+
+namespace ui {
+
+COMPONENT_EXPORT(UI_BASE_X) bool IsXScreensaverActive();
+
+}  // namespace ui
+
+#endif  // UI_BASE_X_X11_SCREENSAVER_H_
diff --git a/ui/base/x/x11_screensaver_window_finder.cc b/ui/base/x/x11_screensaver_window_finder.cc
deleted file mode 100644
index accaf07..0000000
--- a/ui/base/x/x11_screensaver_window_finder.cc
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/x/x11_screensaver_window_finder.h"
-
-#include "base/command_line.h"
-#include "base/strings/string_piece_forward.h"
-#include "ui/base/x/x11_util.h"
-#include "ui/gfx/switches.h"
-#include "ui/gfx/x/connection.h"
-#include "ui/gfx/x/scoped_ignore_errors.h"
-#include "ui/gfx/x/screensaver.h"
-#include "ui/gfx/x/x11_atom_cache.h"
-#include "ui/gfx/x/xproto_util.h"
-
-namespace ui {
-
-ScreensaverWindowFinder::ScreensaverWindowFinder() : exists_(false) {}
-
-// static
-bool ScreensaverWindowFinder::ScreensaverWindowExists() {
-  // Avoid calling into potentially missing X11 APIs in headless mode.
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kHeadless))
-    return false;
-
-  auto* connection = x11::Connection::Get();
-
-  // Let the server know the client version before making any requests.
-  connection->screensaver().QueryVersion(
-      {x11::ScreenSaver::major_version, x11::ScreenSaver::minor_version});
-
-  auto reply =
-      connection->screensaver().QueryInfo(connection->default_root()).Sync();
-  if (reply && static_cast<x11::ScreenSaver::State>(reply->state) ==
-                   x11::ScreenSaver::State::On) {
-    return true;
-  }
-
-  // Ironically, xscreensaver does not conform to the XScreenSaver protocol, so
-  // info.state == ScreenSaverOff or info.state == ScreenSaverDisabled does not
-  // necessarily mean that a screensaver is not active, so add a special check
-  // for xscreensaver.
-  x11::Atom lock_atom = x11::GetAtom("LOCK");
-  std::vector<x11::Atom> atom_properties;
-  if (GetArrayProperty(GetX11RootWindow(), x11::GetAtom("_SCREENSAVER_STATUS"),
-                       &atom_properties) &&
-      atom_properties.size() > 0) {
-    if (atom_properties[0] == lock_atom)
-      return true;
-  }
-
-  // Also check the top level windows to see if any of them are screensavers.
-  x11::ScopedIgnoreErrors ignore_errors(connection);
-  ScreensaverWindowFinder finder;
-  ui::EnumerateTopLevelWindows(&finder);
-  return finder.exists_;
-}
-
-bool ScreensaverWindowFinder::ShouldStopIterating(x11::Window window) {
-  if (!ui::IsWindowVisible(window) || !IsScreensaverWindow(window))
-    return false;
-  exists_ = true;
-  return true;
-}
-
-bool ScreensaverWindowFinder::IsScreensaverWindow(x11::Window window) const {
-  // It should occupy the full screen.
-  if (!ui::IsX11WindowFullScreen(window))
-    return false;
-
-  // For xscreensaver, the window should have _SCREENSAVER_VERSION property.
-  if (ui::PropertyExists(window, x11::GetAtom("_SCREENSAVER_VERSION")))
-    return true;
-
-  // For all others, like gnome-screensaver, the window's WM_CLASS property
-  // should contain "screensaver".
-  std::vector<char> value;
-  if (!GetArrayProperty(window, x11::Atom::WM_CLASS, &value))
-    return false;
-
-  return base::StringPiece(value.data(), value.size()).find("screensaver") !=
-         base::StringPiece::npos;
-}
-
-}  // namespace ui
diff --git a/ui/base/x/x11_screensaver_window_finder.h b/ui/base/x/x11_screensaver_window_finder.h
deleted file mode 100644
index 147099a6..0000000
--- a/ui/base/x/x11_screensaver_window_finder.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_X_X11_SCREENSAVER_WINDOW_FINDER_H_
-#define UI_BASE_X_X11_SCREENSAVER_WINDOW_FINDER_H_
-
-#include "base/component_export.h"
-#include "base/macros.h"
-#include "ui/base/x/x11_util.h"
-
-namespace ui {
-
-class COMPONENT_EXPORT(UI_BASE_X) ScreensaverWindowFinder
-    : public ui::EnumerateWindowsDelegate {
- public:
-  static bool ScreensaverWindowExists();
-
- protected:
-  bool ShouldStopIterating(x11::Window window) override;
-
- private:
-  ScreensaverWindowFinder();
-
-  bool IsScreensaverWindow(x11::Window window) const;
-
-  bool exists_;
-
-  DISALLOW_COPY_AND_ASSIGN(ScreensaverWindowFinder);
-};
-
-}  // namespace ui
-
-#endif  // UI_BASE_X_X11_SCREENSAVER_WINDOW_FINDER_H_
diff --git a/ui/base/x/x11_util.cc b/ui/base/x/x11_util.cc
index c4b92b7..ff558ea 100644
--- a/ui/base/x/x11_util.cc
+++ b/ui/base/x/x11_util.cc
@@ -706,82 +706,6 @@
   return GetProperty(window, x11::GetAtom("_NET_WM_DESKTOP"), desktop);
 }
 
-// Returns true if |window| is a named window.
-bool IsWindowNamed(x11::Window window) {
-  return PropertyExists(window, x11::Atom::WM_NAME);
-}
-
-bool EnumerateChildren(EnumerateWindowsDelegate* delegate,
-                       x11::Window window,
-                       const int max_depth,
-                       int depth) {
-  if (depth > max_depth)
-    return false;
-
-  std::vector<x11::Window> windows;
-  if (depth == 0) {
-    XMenuList::GetInstance()->InsertMenuWindows(&windows);
-    // Enumerate the menus first.
-    std::vector<x11::Window>::iterator iter;
-    for (iter = windows.begin(); iter != windows.end(); iter++) {
-      if (delegate->ShouldStopIterating(*iter))
-        return true;
-    }
-    windows.clear();
-  }
-
-  auto query_tree = x11::Connection::Get()->QueryTree({window}).Sync();
-  if (!query_tree)
-    return false;
-  windows = std::move(query_tree->children);
-
-  // XQueryTree returns the children of |window| in bottom-to-top order, so
-  // reverse-iterate the list to check the windows from top-to-bottom.
-  std::vector<x11::Window>::reverse_iterator iter;
-  for (iter = windows.rbegin(); iter != windows.rend(); iter++) {
-    if (IsWindowNamed(*iter) && delegate->ShouldStopIterating(*iter))
-      return true;
-  }
-
-  // If we're at this point, we didn't find the window we're looking for at the
-  // current level, so we need to recurse to the next level.  We use a second
-  // loop because the recursion and call to XQueryTree are expensive and is only
-  // needed for a small number of cases.
-  if (++depth <= max_depth) {
-    for (iter = windows.rbegin(); iter != windows.rend(); iter++) {
-      if (EnumerateChildren(delegate, *iter, max_depth, depth))
-        return true;
-    }
-  }
-
-  return false;
-}
-
-bool EnumerateAllWindows(EnumerateWindowsDelegate* delegate, int max_depth) {
-  x11::Window root = GetX11RootWindow();
-  return EnumerateChildren(delegate, root, max_depth, 0);
-}
-
-void EnumerateTopLevelWindows(ui::EnumerateWindowsDelegate* delegate) {
-  std::vector<x11::Window> stack;
-  if (!ui::GetXWindowStack(ui::GetX11RootWindow(), &stack)) {
-    // Window Manager doesn't support _NET_CLIENT_LIST_STACKING, so fall back
-    // to old school enumeration of all X windows.  Some WMs parent 'top-level'
-    // windows in unnamed actual top-level windows (ion WM), so extend the
-    // search depth to all children of top-level windows.
-    const int kMaxSearchDepth = 1;
-    ui::EnumerateAllWindows(delegate, kMaxSearchDepth);
-    return;
-  }
-  XMenuList::GetInstance()->InsertMenuWindows(&stack);
-
-  std::vector<x11::Window>::iterator iter;
-  for (iter = stack.begin(); iter != stack.end(); iter++) {
-    if (delegate->ShouldStopIterating(*iter))
-      return;
-  }
-}
-
 bool GetXWindowStack(x11::Window window, std::vector<x11::Window>* windows) {
   if (!GetArrayProperty(window, x11::GetAtom("_NET_CLIENT_LIST_STACKING"),
                         windows)) {
diff --git a/ui/base/x/x11_util.h b/ui/base/x/x11_util.h
index fc3f2d9..5b70f39 100644
--- a/ui/base/x/x11_util.h
+++ b/ui/base/x/x11_util.h
@@ -288,27 +288,6 @@
 COMPONENT_EXPORT(UI_BASE_X)
 bool GetWindowDesktop(x11::Window window, int32_t* desktop);
 
-// Implementers of this interface receive a notification for every X window of
-// the main display.
-class EnumerateWindowsDelegate {
- public:
-  // |window| is the X Window ID of the enumerated window.  Return true to stop
-  // further iteration.
-  virtual bool ShouldStopIterating(x11::Window window) = 0;
-
- protected:
-  virtual ~EnumerateWindowsDelegate() = default;
-};
-
-// Enumerates all windows in the current display.  Will recurse into child
-// windows up to a depth of |max_depth|.
-COMPONENT_EXPORT(UI_BASE_X)
-bool EnumerateAllWindows(EnumerateWindowsDelegate* delegate, int max_depth);
-
-// Enumerates the top-level windows of the current display.
-COMPONENT_EXPORT(UI_BASE_X)
-void EnumerateTopLevelWindows(ui::EnumerateWindowsDelegate* delegate);
-
 // Returns all children windows of a given window in top-to-bottom stacking
 // order.
 COMPONENT_EXPORT(UI_BASE_X)
diff --git a/ui/compositor/test/test_compositor_host_mac.mm b/ui/compositor/test/test_compositor_host_mac.mm
index 82f246a..a161b73 100644
--- a/ui/compositor/test/test_compositor_host_mac.mm
+++ b/ui/compositor/test/test_compositor_host_mac.mm
@@ -29,12 +29,12 @@
   ui::Compositor* _compositor;
 }
 // Designated initializer.
-- (id)init;
+- (instancetype)init;
 - (void)setCompositor:(ui::Compositor*)compositor;
 @end
 
 @implementation AcceleratedTestView
-- (id)init {
+- (instancetype)init {
   // The frame will be resized when reparented into the window's view hierarchy.
   if ((self = [super initWithFrame:NSZeroRect])) {
     [self setWantsLayer:YES];
diff --git a/ui/display/mac/screen_mac.mm b/ui/display/mac/screen_mac.mm
index 00415aa..4d4ed7e 100644
--- a/ui/display/mac/screen_mac.mm
+++ b/ui/display/mac/screen_mac.mm
@@ -58,8 +58,8 @@
   TRACE_EVENT0("ui", "BuildDisplayForScreen");
   NSRect frame = [screen frame];
 
-  CGDirectDisplayID display_id = [[[screen deviceDescription]
-      objectForKey:@"NSScreenNumber"] unsignedIntValue];
+  CGDirectDisplayID display_id =
+      [[screen deviceDescription][@"NSScreenNumber"] unsignedIntValue];
 
   Display display(display_id, gfx::Rect(NSRectToCGRect(frame)));
   NSRect visible_frame = [screen visibleFrame];
@@ -175,8 +175,8 @@
   ScreenIdsToScreensMap screen_ids_to_screens;
   for (NSScreen* screen in [NSScreen screens]) {
     NSDictionary* screen_device_description = [screen deviceDescription];
-    int64_t screen_id = [[screen_device_description
-        objectForKey:@"NSScreenNumber"] unsignedIntValue];
+    int64_t screen_id =
+        [screen_device_description[@"NSScreenNumber"] unsignedIntValue];
     screen_ids_to_screens[screen_id] = screen;
   }
 
@@ -328,7 +328,7 @@
       return GetPrimaryDisplay();
 
     NSPoint ns_point = NSPointFromCGPoint(point.ToCGPoint());
-    NSScreen* primary = [screens objectAtIndex:0];
+    NSScreen* primary = screens[0];
     ns_point.y = NSMaxY([primary frame]) - ns_point.y;
     for (NSScreen* screen in screens) {
       if (NSMouseInRect(ns_point, [screen frame], NO))
@@ -379,8 +379,8 @@
 
  private:
   Display GetCachedDisplayForScreen(NSScreen* screen) const {
-    const CGDirectDisplayID display_id = [[[screen deviceDescription]
-        objectForKey:@"NSScreenNumber"] unsignedIntValue];
+    const CGDirectDisplayID display_id =
+        [[screen deviceDescription][@"NSScreenNumber"] unsignedIntValue];
     for (const Display& display : displays_) {
       if (display_id == display.id())
         return display;
diff --git a/ui/events/devices/BUILD.gn b/ui/events/devices/BUILD.gn
index c8c06e7..bcd753d 100644
--- a/ui/events/devices/BUILD.gn
+++ b/ui/events/devices/BUILD.gn
@@ -18,6 +18,8 @@
     "input_device.cc",
     "input_device.h",
     "input_device_event_observer.h",
+    "microphone_mute_switch_monitor.cc",
+    "microphone_mute_switch_monitor.h",
     "stylus_state.h",
     "touch_device_transform.cc",
     "touch_device_transform.h",
diff --git a/ui/events/devices/microphone_mute_switch_monitor.cc b/ui/events/devices/microphone_mute_switch_monitor.cc
new file mode 100644
index 0000000..fc53f98
--- /dev/null
+++ b/ui/events/devices/microphone_mute_switch_monitor.cc
@@ -0,0 +1,37 @@
+// 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 "ui/events/devices/microphone_mute_switch_monitor.h"
+
+#include "base/no_destructor.h"
+
+namespace ui {
+
+MicrophoneMuteSwitchMonitor::MicrophoneMuteSwitchMonitor() = default;
+
+MicrophoneMuteSwitchMonitor::~MicrophoneMuteSwitchMonitor() = default;
+
+// static
+MicrophoneMuteSwitchMonitor* MicrophoneMuteSwitchMonitor::Get() {
+  static base::NoDestructor<MicrophoneMuteSwitchMonitor> instance;
+  return instance.get();
+}
+
+void MicrophoneMuteSwitchMonitor::AddObserver(Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void MicrophoneMuteSwitchMonitor::RemoveObserver(Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+void MicrophoneMuteSwitchMonitor::SetMicrophoneMuteSwitchValue(bool switch_on) {
+  if (microphone_mute_switch_on_ == switch_on)
+    return;
+  microphone_mute_switch_on_ = switch_on;
+  for (auto& observer : observers_)
+    observer.OnMicrophoneMuteSwitchValueChanged(microphone_mute_switch_on_);
+}
+
+}  // namespace ui
diff --git a/ui/events/devices/microphone_mute_switch_monitor.h b/ui/events/devices/microphone_mute_switch_monitor.h
new file mode 100644
index 0000000..3b25f6d
--- /dev/null
+++ b/ui/events/devices/microphone_mute_switch_monitor.h
@@ -0,0 +1,62 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_EVENTS_DEVICES_MICROPHONE_MUTE_SWITCH_MONITOR_H_
+#define UI_EVENTS_DEVICES_MICROPHONE_MUTE_SWITCH_MONITOR_H_
+
+#include "base/no_destructor.h"
+#include "base/observer_list.h"
+#include "base/observer_list_types.h"
+#include "ui/events/devices/events_devices_export.h"
+
+namespace ui {
+
+// Monitors the state of the Microphone mute switch device - Chrome OS devices
+// may have a hardware toggle that disables audio input. The toggle state is
+// exposed using the SW_MUTE_DEVICE event on an input device.
+// MicrophoneMuteSwitchMonitor can be used to track the state of the microphone
+// mute switch. The switch state will be updated by the input device's event
+// converter, and can be observed using the Observer interface exposed by the
+// MicrophoneMuteSwitchMonitor.
+//
+// NOTE: The mute switch state will be monitored only on Chrome OS with ozone.
+class EVENTS_DEVICES_EXPORT MicrophoneMuteSwitchMonitor {
+ public:
+  class Observer : public base::CheckedObserver {
+   public:
+    // Called when the microphone mute switch value changes.
+    virtual void OnMicrophoneMuteSwitchValueChanged(bool muted) = 0;
+  };
+
+  MicrophoneMuteSwitchMonitor();
+  ~MicrophoneMuteSwitchMonitor();
+  MicrophoneMuteSwitchMonitor(const MicrophoneMuteSwitchMonitor&) = delete;
+  MicrophoneMuteSwitchMonitor& operator=(const MicrophoneMuteSwitchMonitor&) =
+      delete;
+
+  static MicrophoneMuteSwitchMonitor* Get();
+
+  void AddObserver(Observer* observer);
+  void RemoveObserver(Observer* observer);
+
+  bool microphone_mute_switch_on() const { return microphone_mute_switch_on_; }
+
+  // Updates the microphone mute switch value. Set in response to a
+  // SW_MUTE_DEVICE event on the input device associated with the microphone
+  // mute switch.
+  void SetMicrophoneMuteSwitchValue(bool switch_on);
+
+ private:
+  friend class base::NoDestructor<MicrophoneMuteSwitchMonitor>;
+
+  // Whether the microphone mute switch was toggled to on, in which case the
+  // internal microphone will be muted.
+  bool microphone_mute_switch_on_ = false;
+
+  base::ObserverList<MicrophoneMuteSwitchMonitor::Observer> observers_;
+};
+
+}  // namespace ui
+
+#endif  // UI_EVENTS_DEVICES_MICROPHONE_MUTE_SWITCH_MONITOR_H_
diff --git a/ui/events/devices/touchscreen_device.cc b/ui/events/devices/touchscreen_device.cc
index 61238d2..7ae0eaf 100644
--- a/ui/events/devices/touchscreen_device.cc
+++ b/ui/events/devices/touchscreen_device.cc
@@ -17,20 +17,24 @@
                                      const std::string& name,
                                      const gfx::Size& size,
                                      int touch_points,
-                                     bool has_stylus)
+                                     bool has_stylus,
+                                     bool has_stylus_garage_switch)
     : InputDevice(id, type, name),
       size(size),
       touch_points(touch_points),
-      has_stylus(has_stylus) {}
+      has_stylus(has_stylus),
+      has_stylus_garage_switch(has_stylus_garage_switch) {}
 
 TouchscreenDevice::TouchscreenDevice(const InputDevice& input_device,
                                      const gfx::Size& size,
                                      int touch_points,
-                                     bool has_stylus)
+                                     bool has_stylus,
+                                     bool has_stylus_garage_switch)
     : InputDevice(input_device),
       size(size),
       touch_points(touch_points),
-      has_stylus(has_stylus) {}
+      has_stylus(has_stylus),
+      has_stylus_garage_switch(has_stylus_garage_switch) {}
 
 TouchscreenDevice::TouchscreenDevice(const TouchscreenDevice& other) = default;
 
diff --git a/ui/events/devices/touchscreen_device.h b/ui/events/devices/touchscreen_device.h
index f786bda..5c4a5bb 100644
--- a/ui/events/devices/touchscreen_device.h
+++ b/ui/events/devices/touchscreen_device.h
@@ -26,12 +26,14 @@
                     const std::string& name,
                     const gfx::Size& size,
                     int touch_points,
-                    bool has_stylus = false);
+                    bool has_stylus = false,
+                    bool has_stylus_garage_switch = false);
 
   TouchscreenDevice(const InputDevice& input_device,
                     const gfx::Size& size,
                     int touch_points,
-                    bool has_stylus = false);
+                    bool has_stylus = false,
+                    bool has_stylus_garage_switch = false);
 
   TouchscreenDevice(const TouchscreenDevice& other);
 
@@ -42,6 +44,9 @@
   int touch_points = 0;
   // True if the specified touchscreen device is stylus capable.
   bool has_stylus = false;
+  // True if there is a garage/dock switch associated with the stylus.
+  bool has_stylus_garage_switch = false;
+
   // Id of the display the touch device targets.
   // NOTE: when obtaining TouchscreenDevice from DeviceDataManager this value
   // may not have been updated. See
diff --git a/ui/events/ozone/evdev/BUILD.gn b/ui/events/ozone/evdev/BUILD.gn
index 39ca5f7..966c4721 100644
--- a/ui/events/ozone/evdev/BUILD.gn
+++ b/ui/events/ozone/evdev/BUILD.gn
@@ -61,10 +61,14 @@
     "input_injector_evdev.h",
     "keyboard_evdev.cc",
     "keyboard_evdev.h",
+    "microphone_mute_switch_event_converter_evdev.cc",
+    "microphone_mute_switch_event_converter_evdev.h",
     "mouse_button_map_evdev.cc",
     "mouse_button_map_evdev.h",
     "stylus_button_event_converter_evdev.cc",
     "stylus_button_event_converter_evdev.h",
+    "switches.cc",
+    "switches.h",
     "tablet_event_converter_evdev.cc",
     "tablet_event_converter_evdev.h",
     "touch_evdev_debug_buffer.cc",
@@ -214,6 +218,10 @@
     "touch_filter/palm_detection_filter_factory_unittest.cc",
   ]
 
+  if (is_chromeos_ash) {
+    sources += [ "microphone_mute_switch_event_converter_evdev_unittest.cc" ]
+  }
+
   deps = [
     ":evdev",
     ":event_device_info",
diff --git a/ui/events/ozone/evdev/device_event_dispatcher_evdev.h b/ui/events/ozone/evdev/device_event_dispatcher_evdev.h
index 5b778ca7..f542ef0e 100644
--- a/ui/events/ozone/evdev/device_event_dispatcher_evdev.h
+++ b/ui/events/ozone/evdev/device_event_dispatcher_evdev.h
@@ -192,6 +192,7 @@
   virtual void DispatchScrollEvent(const ScrollEventParams& params) = 0;
   virtual void DispatchTouchEvent(const TouchEventParams& params) = 0;
   virtual void DispatchGamepadEvent(const GamepadEvent& event) = 0;
+  virtual void DispatchMicrophoneMuteSwitchValueChanged(bool muted) = 0;
 
   // Device lifecycle events.
   virtual void DispatchKeyboardDevicesUpdated(
diff --git a/ui/events/ozone/evdev/event_converter_evdev.cc b/ui/events/ozone/evdev/event_converter_evdev.cc
index 75e85ad2..1daf7ba 100644
--- a/ui/events/ozone/evdev/event_converter_evdev.cc
+++ b/ui/events/ozone/evdev/event_converter_evdev.cc
@@ -15,6 +15,7 @@
 #include "ui/events/base_event_utils.h"
 #include "ui/events/devices/device_util_linux.h"
 #include "ui/events/devices/input_device.h"
+#include "ui/events/devices/stylus_state.h"
 #include "ui/events/event_utils.h"
 
 #ifndef input_event_sec
@@ -128,6 +129,15 @@
   return false;
 }
 
+bool EventConverterEvdev::HasStylusSwitch() const {
+  return false;
+}
+
+ui::StylusState EventConverterEvdev::GetStylusSwitchState() {
+  NOTREACHED();
+  return ui::StylusState::REMOVED;
+}
+
 gfx::Size EventConverterEvdev::GetTouchscreenSize() const {
   NOTREACHED();
   return gfx::Size();
diff --git a/ui/events/ozone/evdev/event_converter_evdev.h b/ui/events/ozone/evdev/event_converter_evdev.h
index 2d18481..94200288 100644
--- a/ui/events/ozone/evdev/event_converter_evdev.h
+++ b/ui/events/ozone/evdev/event_converter_evdev.h
@@ -17,6 +17,7 @@
 #include "base/task/current_thread.h"
 #include "ui/events/devices/gamepad_device.h"
 #include "ui/events/devices/input_device.h"
+#include "ui/events/devices/stylus_state.h"
 #include "ui/events/ozone/evdev/event_dispatch_callback.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -97,6 +98,15 @@
   // Returns true if the converter is used for a device with a caps lock LED.
   virtual bool HasCapsLockLed() const;
 
+  // Returns true if the converter is used for a device with a stylus switch
+  // (also known as garage or dock sensor, not buttons on a stylus).
+  virtual bool HasStylusSwitch() const;
+
+  // Returns the current state of the stylus garage switch, indicating whether a
+  // stylus is inserted in (or attached) to a stylus dock or garage, or has been
+  // removed.
+  virtual ui::StylusState GetStylusSwitchState();
+
   // Returns the size of the touchscreen device if the converter is used for a
   // touchscreen device.
   virtual gfx::Size GetTouchscreenSize() const;
diff --git a/ui/events/ozone/evdev/event_converter_evdev_impl.cc b/ui/events/ozone/evdev/event_converter_evdev_impl.cc
index c54eebe..6b879e29 100644
--- a/ui/events/ozone/evdev/event_converter_evdev_impl.cc
+++ b/ui/events/ozone/evdev/event_converter_evdev_impl.cc
@@ -15,6 +15,7 @@
 #include "ui/events/event_utils.h"
 #include "ui/events/keycodes/dom/keycode_converter.h"
 #include "ui/events/ozone/evdev/device_event_dispatcher_evdev.h"
+#include "ui/events/ozone/evdev/event_device_util.h"
 
 namespace ui {
 
@@ -48,6 +49,7 @@
       input_device_fd_(std::move(fd)),
       has_keyboard_(devinfo.HasKeyboard()),
       has_touchpad_(devinfo.HasTouchpad()),
+      has_stylus_switch_(devinfo.HasStylusSwitch()),
       has_caps_lock_led_(devinfo.HasLedEvent(LED_CAPSL)),
       controller_(FROM_HERE),
       cursor_(cursor),
@@ -90,6 +92,10 @@
   return has_caps_lock_led_;
 }
 
+bool EventConverterEvdevImpl::HasStylusSwitch() const {
+  return has_stylus_switch_;
+}
+
 void EventConverterEvdevImpl::SetKeyFilter(bool enable_filter,
                                            std::vector<DomCode> allowed_keys) {
   if (!enable_filter) {
@@ -115,6 +121,22 @@
   ReleaseMouseButtons();
 }
 
+ui::StylusState EventConverterEvdevImpl::GetStylusSwitchState() {
+  if (!HasStylusSwitch()) {
+    return ui::StylusState::REMOVED;
+  }
+
+  // Prepare storage for SW_MAX bits
+  unsigned long array[EVDEV_BITS_TO_LONGS(SW_MAX)] = {0};
+  int result = ioctl(input_device_fd_.get(), EVIOCGSW(SW_MAX), array);
+  if (result == -1) {
+    return ui::StylusState::REMOVED;
+  }
+
+  return EvdevBitIsSet(array, kSwitchStylusInserted) ? ui::StylusState::INSERTED
+                                                     : ui::StylusState::REMOVED;
+}
+
 void EventConverterEvdevImpl::ProcessEvents(const input_event* inputs,
                                             int count) {
   for (int i = 0; i < count; ++i) {
diff --git a/ui/events/ozone/evdev/event_converter_evdev_impl.h b/ui/events/ozone/evdev/event_converter_evdev_impl.h
index 63c5218..f7e9a90 100644
--- a/ui/events/ozone/evdev/event_converter_evdev_impl.h
+++ b/ui/events/ozone/evdev/event_converter_evdev_impl.h
@@ -13,6 +13,7 @@
 #include "base/macros.h"
 #include "base/message_loop/message_pump_libevent.h"
 #include "ui/events/devices/input_device.h"
+#include "ui/events/devices/stylus_state.h"
 #include "ui/events/event.h"
 #include "ui/events/event_modifiers.h"
 #include "ui/events/ozone/evdev/cursor_delegate_evdev.h"
@@ -20,6 +21,7 @@
 #include "ui/events/ozone/evdev/event_device_info.h"
 #include "ui/events/ozone/evdev/keyboard_evdev.h"
 #include "ui/events/ozone/evdev/mouse_button_map_evdev.h"
+#include "ui/ozone/public/input_controller.h"
 
 struct input_event;
 
@@ -43,6 +45,8 @@
   bool HasKeyboard() const override;
   bool HasTouchpad() const override;
   bool HasCapsLockLed() const override;
+  bool HasStylusSwitch() const override;
+  ui::StylusState GetStylusSwitchState() override;
   void SetKeyFilter(bool enable_filter,
                     std::vector<DomCode> allowed_keys) override;
   void OnDisabled() override;
@@ -71,6 +75,7 @@
   // Input modalities for this device.
   bool has_keyboard_;
   bool has_touchpad_;
+  bool has_stylus_switch_;
 
   // LEDs for this device.
   bool has_caps_lock_led_;
@@ -111,4 +116,3 @@
 }  // namespace ui
 
 #endif  // UI_EVENTS_OZONE_EVDEV_EVENT_CONVERTER_EVDEV_IMPL_H_
-
diff --git a/ui/events/ozone/evdev/event_converter_test_util.cc b/ui/events/ozone/evdev/event_converter_test_util.cc
index a60136c..176bec2 100644
--- a/ui/events/ozone/evdev/event_converter_test_util.cc
+++ b/ui/events/ozone/evdev/event_converter_test_util.cc
@@ -62,6 +62,10 @@
     event_factory_evdev_->DispatchTouchEvent(params);
   }
 
+  void DispatchMicrophoneMuteSwitchValueChanged(bool muted) override {
+    event_factory_evdev_->DispatchMicrophoneMuteSwitchValueChanged(muted);
+  }
+
   void DispatchKeyboardDevicesUpdated(
       const std::vector<InputDevice>& devices) override {
     event_factory_evdev_->DispatchKeyboardDevicesUpdated(devices);
diff --git a/ui/events/ozone/evdev/event_device_info.cc b/ui/events/ozone/evdev/event_device_info.cc
index 69eaa50..e43b103b 100644
--- a/ui/events/ozone/evdev/event_device_info.cc
+++ b/ui/events/ozone/evdev/event_device_info.cc
@@ -9,7 +9,6 @@
 #include <cstring>
 
 #include "base/files/file_path.h"
-#include "base/logging.h"
 #include "base/notreached.h"
 #include "base/stl_util.h"
 #include "base/threading/thread_restrictions.h"
@@ -498,6 +497,15 @@
   return false;
 }
 
+bool EventDeviceInfo::IsMicrophoneMuteSwitchDevice() const {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  return HasSwEvent(SW_MUTE_DEVICE) && (device_type_ == INPUT_DEVICE_UNKNOWN ||
+                                        device_type_ == INPUT_DEVICE_INTERNAL);
+#else
+  return false;
+#endif
+}
+
 bool IsInKeyboardBlockList(input_id input_id_) {
   for (const auto& blocklist_id : kKeyboardBlocklist) {
     if (input_id_.vendor == blocklist_id.vendor &&
@@ -545,6 +553,11 @@
   return HasAbsXY() && HasDirect();
 }
 
+bool EventDeviceInfo::HasStylusSwitch() const {
+  return HasSwEvent(SW_PEN_INSERTED) && (device_type_ == INPUT_DEVICE_UNKNOWN ||
+                                         device_type_ == INPUT_DEVICE_INTERNAL);
+}
+
 bool EventDeviceInfo::HasGamepad() const {
   if (!HasEventType(EV_KEY))
     return false;
diff --git a/ui/events/ozone/evdev/event_device_info.h b/ui/events/ozone/evdev/event_device_info.h
index 4b73534..e71d2e16 100644
--- a/ui/events/ozone/evdev/event_device_info.h
+++ b/ui/events/ozone/evdev/event_device_info.h
@@ -152,6 +152,9 @@
   // Determine whether there's a touchscreen on this device.
   bool HasTouchscreen() const;
 
+  // Determine whether there's a stylus garage switch on this device.
+  bool HasStylusSwitch() const;
+
   // Determine whether there's a gamepad on this device.
   bool HasGamepad() const;
 
@@ -161,6 +164,11 @@
   // Determine if this is a dedicated device for a stylus button.
   bool IsStylusButtonDevice() const;
 
+  // Determine whether this is a dedicated device for microphone mute hw switch
+  // on Chrome OS. The switch disables the internal microphone feed. The input
+  // device is used to track the mute switch state.
+  bool IsMicrophoneMuteSwitchDevice() const;
+
   // The device type (internal or external.)
   InputDeviceType device_type() const { return device_type_; }
 
diff --git a/ui/events/ozone/evdev/event_device_info_unittest.cc b/ui/events/ozone/evdev/event_device_info_unittest.cc
index 51f1e60..ba704e6 100644
--- a/ui/events/ozone/evdev/event_device_info_unittest.cc
+++ b/ui/events/ozone/evdev/event_device_info_unittest.cc
@@ -25,6 +25,8 @@
   EXPECT_FALSE(devinfo.HasTouchscreen());
   EXPECT_FALSE(devinfo.HasTablet());
   EXPECT_TRUE(devinfo.HasGamepad());
+  EXPECT_FALSE(devinfo.IsStylusButtonDevice());
+  EXPECT_FALSE(devinfo.HasStylusSwitch());
 
   EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_USB, devinfo.device_type());
 }
@@ -55,6 +57,8 @@
   EXPECT_FALSE(devinfo.HasTouchscreen());
   EXPECT_FALSE(devinfo.HasTablet());
   EXPECT_FALSE(devinfo.HasGamepad());
+  EXPECT_FALSE(devinfo.IsStylusButtonDevice());
+  EXPECT_FALSE(devinfo.HasStylusSwitch());
 }
 
 TEST(EventDeviceInfoTest, BasicCrosTouchscreen) {
@@ -68,6 +72,8 @@
   EXPECT_TRUE(devinfo.HasTouchscreen());
   EXPECT_FALSE(devinfo.HasTablet());
   EXPECT_FALSE(devinfo.HasGamepad());
+  EXPECT_FALSE(devinfo.IsStylusButtonDevice());
+  EXPECT_FALSE(devinfo.HasStylusSwitch());
 
   EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_INTERNAL, devinfo.device_type());
 }
@@ -83,6 +89,8 @@
   EXPECT_FALSE(devinfo.HasTouchscreen());
   EXPECT_FALSE(devinfo.HasTablet());
   EXPECT_FALSE(devinfo.HasGamepad());
+  EXPECT_FALSE(devinfo.IsStylusButtonDevice());
+  EXPECT_FALSE(devinfo.HasStylusSwitch());
 
   EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_INTERNAL, devinfo.device_type());
 }
@@ -113,6 +121,8 @@
   EXPECT_FALSE(devinfo.HasTouchscreen());
   EXPECT_FALSE(devinfo.HasTablet());
   EXPECT_FALSE(devinfo.HasGamepad());
+  EXPECT_FALSE(devinfo.IsStylusButtonDevice());
+  EXPECT_FALSE(devinfo.HasStylusSwitch());
 
   EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_USB, devinfo.device_type());
 }
@@ -128,6 +138,8 @@
   EXPECT_FALSE(devinfo.HasTouchscreen());
   EXPECT_FALSE(devinfo.HasTablet());
   EXPECT_FALSE(devinfo.HasGamepad());
+  EXPECT_FALSE(devinfo.IsStylusButtonDevice());
+  EXPECT_FALSE(devinfo.HasStylusSwitch());
 
   EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_USB, devinfo.device_type());
 }
@@ -158,6 +170,8 @@
   EXPECT_TRUE(devinfo.HasTouchscreen());
   EXPECT_FALSE(devinfo.HasTablet());
   EXPECT_FALSE(devinfo.HasGamepad());
+  EXPECT_FALSE(devinfo.IsStylusButtonDevice());
+  EXPECT_FALSE(devinfo.HasStylusSwitch());
 
   EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_USB, devinfo.device_type());
 }
@@ -173,6 +187,8 @@
   EXPECT_FALSE(devinfo.HasTouchscreen());
   EXPECT_TRUE(devinfo.HasTablet());
   EXPECT_FALSE(devinfo.HasGamepad());
+  EXPECT_FALSE(devinfo.IsStylusButtonDevice());
+  EXPECT_FALSE(devinfo.HasStylusSwitch());
 
   EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_USB, devinfo.device_type());
 }
@@ -204,6 +220,8 @@
   EXPECT_FALSE(devinfo.HasTouchscreen());
   EXPECT_FALSE(devinfo.HasTablet());
   EXPECT_FALSE(devinfo.HasGamepad());
+  EXPECT_FALSE(devinfo.IsStylusButtonDevice());
+  EXPECT_FALSE(devinfo.HasStylusSwitch());
 }
 
 TEST(EventDeviceInfoTest, AbsoluteMouseTouchscreen) {
@@ -218,6 +236,8 @@
   EXPECT_TRUE(devinfo.HasTouchscreen());
   EXPECT_FALSE(devinfo.HasTablet());
   EXPECT_FALSE(devinfo.HasGamepad());
+  EXPECT_FALSE(devinfo.IsStylusButtonDevice());
+  EXPECT_FALSE(devinfo.HasStylusSwitch());
 
   EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_USB, devinfo.device_type());
 }
@@ -233,6 +253,8 @@
   EXPECT_TRUE(devinfo.HasTouchscreen());
   EXPECT_FALSE(devinfo.HasTablet());
   EXPECT_FALSE(devinfo.HasGamepad());
+  EXPECT_FALSE(devinfo.IsStylusButtonDevice());
+  EXPECT_FALSE(devinfo.HasStylusSwitch());
 
   EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_INTERNAL, devinfo.device_type());
 }
@@ -248,6 +270,8 @@
   EXPECT_FALSE(devinfo.HasTouchscreen());
   EXPECT_FALSE(devinfo.HasTablet());
   EXPECT_FALSE(devinfo.HasGamepad());
+  EXPECT_FALSE(devinfo.IsStylusButtonDevice());
+  EXPECT_FALSE(devinfo.HasStylusSwitch());
 
   EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_INTERNAL, devinfo.device_type());
 }
@@ -263,6 +287,8 @@
   EXPECT_FALSE(devinfo.HasTouchscreen());
   EXPECT_FALSE(devinfo.HasTablet());
   EXPECT_FALSE(devinfo.HasGamepad());
+  EXPECT_FALSE(devinfo.IsStylusButtonDevice());
+  EXPECT_FALSE(devinfo.HasStylusSwitch());
 
   EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_INTERNAL, devinfo.device_type());
 }
@@ -278,6 +304,8 @@
   EXPECT_FALSE(devinfo.HasTouchscreen());
   EXPECT_FALSE(devinfo.HasTablet());
   EXPECT_FALSE(devinfo.HasGamepad());
+  EXPECT_FALSE(devinfo.IsStylusButtonDevice());
+  EXPECT_FALSE(devinfo.HasStylusSwitch());
 
   EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_USB, devinfo.device_type());
 }
@@ -293,6 +321,8 @@
   EXPECT_TRUE(devinfo.HasTouchscreen());
   EXPECT_FALSE(devinfo.HasTablet());
   EXPECT_FALSE(devinfo.HasGamepad());
+  EXPECT_FALSE(devinfo.IsStylusButtonDevice());
+  EXPECT_FALSE(devinfo.HasStylusSwitch());
 
   EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_USB, devinfo.device_type());
 }
@@ -315,6 +345,8 @@
   EXPECT_FALSE(devinfo.HasTouchscreen());
   EXPECT_FALSE(devinfo.HasTablet());
   EXPECT_TRUE(devinfo.HasGamepad());
+  EXPECT_FALSE(devinfo.IsStylusButtonDevice());
+  EXPECT_FALSE(devinfo.HasStylusSwitch());
 
   EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_BLUETOOTH, devinfo.device_type());
 }
@@ -331,8 +363,26 @@
   EXPECT_FALSE(devinfo.HasTablet());
   EXPECT_FALSE(devinfo.HasGamepad());
   EXPECT_TRUE(devinfo.IsStylusButtonDevice());
+  EXPECT_FALSE(devinfo.HasStylusSwitch());
 
   EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_BLUETOOTH, devinfo.device_type());
 }
 
+TEST(EventDeviceInfoTest, BasicStylusGarageSwitch) {
+  EventDeviceInfo devinfo;
+  EXPECT_TRUE(CapabilitiesToDeviceInfo(kDrawciaStylusGarage, &devinfo));
+
+  EXPECT_FALSE(devinfo.HasKeyboard());
+  EXPECT_FALSE(devinfo.HasMouse());
+  EXPECT_FALSE(devinfo.HasPointingStick());
+  EXPECT_FALSE(devinfo.HasTouchpad());
+  EXPECT_FALSE(devinfo.HasTouchscreen());
+  EXPECT_FALSE(devinfo.HasTablet());
+  EXPECT_FALSE(devinfo.HasGamepad());
+  EXPECT_FALSE(devinfo.IsStylusButtonDevice());
+  EXPECT_TRUE(devinfo.HasStylusSwitch());
+
+  EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_UNKNOWN, devinfo.device_type());
+}
+
 }  // namespace ui
diff --git a/ui/events/ozone/evdev/event_device_test_util.cc b/ui/events/ozone/evdev/event_device_test_util.cc
index 63f4b53..ab801fb 100644
--- a/ui/events/ozone/evdev/event_device_test_util.cc
+++ b/ui/events/ozone/evdev/event_device_test_util.cc
@@ -1068,6 +1068,47 @@
     base::size(kDrallionStylusAxes),
 };
 
+const DeviceCapabilities kPuffMicrophoneMuteSwitch = {
+    /* path */
+    "/sys/devices/pci0000:00/0000:00:19.0/PRP0001:00/input/input3/event3",
+    /* name */ "PRP0001:00",
+    /* phys */ "gpio-keys/input0",
+    /* uniq */ "",
+    /* bustype */ "0019",
+    /* vendor */ "0001",
+    /* product */ "0001",
+    /* version */ "0100",
+    /* prop */ "0",
+    /* ev */ "21",
+    /* key */ "0",
+    /* rel */ "0",
+    /* abs */ "0",
+    /* msc */ "0",
+    /* sw */ "4000",
+    /* led */ "0",
+    /* ff */ "0",
+};
+
+const DeviceCapabilities kDrawciaStylusGarage = {
+    /* path */
+    "/sys/devices/pci0000:00/0000:00:15.2/PRP0001:00/input/input4/event4",
+    /* name */ "PRP0001:00",
+    /* phys */ "gpio-keys/input0",
+    /* uniq */ "",
+    /* bustype */ "0019",
+    /* vendor */ "0001",
+    /* product */ "0001",
+    /* version */ "0100",
+    /* prop */ "0",
+    /* ev */ "21",
+    /* key */ "0",
+    /* rel */ "0",
+    /* abs */ "0",
+    /* msc */ "0",
+    /* sw */ "8000",
+    /* led */ "0",
+    /* ff */ "0",
+};
 // NB: Please use the capture_device_capabilities.py script to add more
 // test data here. This will help ensure the data matches what the kernel
 // reports for a real device and is entered correctly.
@@ -1100,6 +1141,11 @@
     return false;
   devinfo->SetAbsEvents(&abs_bits[0], abs_bits.size());
 
+  std::vector<unsigned long> sw_bits;
+  if (!ParseBitfield(capabilities.sw, SW_CNT, &sw_bits))
+    return false;
+  devinfo->SetSwEvents(&sw_bits[0], sw_bits.size());
+
   std::vector<unsigned long> msc_bits;
   if (!ParseBitfield(capabilities.msc, MSC_CNT, &msc_bits))
     return false;
diff --git a/ui/events/ozone/evdev/event_device_test_util.h b/ui/events/ozone/evdev/event_device_test_util.h
index b6c0b7c0..91d12066 100644
--- a/ui/events/ozone/evdev/event_device_test_util.h
+++ b/ui/events/ozone/evdev/event_device_test_util.h
@@ -91,6 +91,8 @@
 extern const DeviceCapabilities kXboxElite;
 extern const DeviceCapabilities kDrallionStylus;
 extern const DeviceCapabilities kDellActivePenButton;
+extern const DeviceCapabilities kPuffMicrophoneMuteSwitch;
+extern const DeviceCapabilities kDrawciaStylusGarage;
 }  // namspace ui
 
 #endif  // UI_EVENTS_OZONE_EVDEV_EVENT_DEVICE_TEST_UTIL_H_
diff --git a/ui/events/ozone/evdev/event_factory_evdev.cc b/ui/events/ozone/evdev/event_factory_evdev.cc
index 519cadd..364355e 100644
--- a/ui/events/ozone/evdev/event_factory_evdev.cc
+++ b/ui/events/ozone/evdev/event_factory_evdev.cc
@@ -15,6 +15,7 @@
 #include "base/trace_event/trace_event.h"
 #include "ui/events/devices/device_data_manager.h"
 #include "ui/events/devices/input_device.h"
+#include "ui/events/devices/microphone_mute_switch_monitor.h"
 #include "ui/events/event_utils.h"
 #include "ui/events/ozone/device/device_event.h"
 #include "ui/events/ozone/device/device_manager.h"
@@ -136,6 +137,14 @@
                        event_factory_evdev_, stylus_state));
   }
 
+  void DispatchMicrophoneMuteSwitchValueChanged(bool muted) override {
+    ui_thread_runner_->PostTask(
+        FROM_HERE,
+        base::BindOnce(
+            &EventFactoryEvdev::DispatchMicrophoneMuteSwitchValueChanged,
+            event_factory_evdev_, muted));
+  }
+
   void DispatchGamepadDevicesUpdated(
       const std::vector<GamepadDevice>& devices) override {
     ui_thread_runner_->PostTask(
@@ -433,6 +442,12 @@
   observer->OnStylusStateChanged(stylus_state);
 }
 
+void EventFactoryEvdev::DispatchMicrophoneMuteSwitchValueChanged(bool muted) {
+  TRACE_EVENT0("evdev",
+               "EventFactoryEvdev::DispatchMicrophoneMuteSwitchValueChanged");
+  MicrophoneMuteSwitchMonitor::Get()->SetMicrophoneMuteSwitchValue(muted);
+}
+
 void EventFactoryEvdev::DispatchUncategorizedDevicesUpdated(
     const std::vector<InputDevice>& devices) {
   TRACE_EVENT0("evdev",
diff --git a/ui/events/ozone/evdev/event_factory_evdev.h b/ui/events/ozone/evdev/event_factory_evdev.h
index b316454..e40eea4d 100644
--- a/ui/events/ozone/evdev/event_factory_evdev.h
+++ b/ui/events/ozone/evdev/event_factory_evdev.h
@@ -86,6 +86,7 @@
       const std::vector<InputDevice>& devices);
   void DispatchDeviceListsComplete();
   void DispatchStylusStateChanged(StylusState stylus_state);
+  void DispatchMicrophoneMuteSwitchValueChanged(bool muted);
 
   // Gamepad event and gamepad device event. These events are dispatched to
   // GamepadObserver through GamepadProviderOzone.
diff --git a/ui/events/ozone/evdev/input_controller_evdev.cc b/ui/events/ozone/evdev/input_controller_evdev.cc
index a039ca6..70c15bf 100644
--- a/ui/events/ozone/evdev/input_controller_evdev.cc
+++ b/ui/events/ozone/evdev/input_controller_evdev.cc
@@ -14,6 +14,7 @@
 #include "base/callback.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "ui/events/devices/device_data_manager.h"
+#include "ui/events/devices/stylus_state.h"
 #include "ui/events/ozone/evdev/input_device_factory_evdev_proxy.h"
 #include "ui/events/ozone/evdev/keyboard_evdev.h"
 #include "ui/events/ozone/evdev/mouse_button_map_evdev.h"
@@ -248,6 +249,14 @@
   ScheduleUpdateDeviceSettings();
 }
 
+void InputControllerEvdev::GetStylusSwitchState(
+    GetStylusSwitchStateReply reply) {
+  if (input_device_factory_)
+    input_device_factory_->GetStylusSwitchState(std::move(reply));
+  else
+    std::move(reply).Run(ui::StylusState::REMOVED);
+}
+
 void InputControllerEvdev::GetTouchDeviceStatus(
     GetTouchDeviceStatusReply reply) {
   if (input_device_factory_)
diff --git a/ui/events/ozone/evdev/input_controller_evdev.h b/ui/events/ozone/evdev/input_controller_evdev.h
index 49ece6de..16e53e579 100644
--- a/ui/events/ozone/evdev/input_controller_evdev.h
+++ b/ui/events/ozone/evdev/input_controller_evdev.h
@@ -11,6 +11,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "ui/events/devices/stylus_state.h"
 #include "ui/events/ozone/evdev/input_device_settings_evdev.h"
 #include "ui/ozone/public/input_controller.h"
 
@@ -77,6 +78,7 @@
   void GetTouchDeviceStatus(GetTouchDeviceStatusReply reply) override;
   void GetTouchEventLog(const base::FilePath& out_dir,
                         GetTouchEventLogReply reply) override;
+  void GetStylusSwitchState(GetStylusSwitchStateReply reply) override;
   void SetInternalTouchpadEnabled(bool enabled) override;
   bool IsInternalTouchpadEnabled() const override;
   void SetTouchscreensEnabled(bool enabled) override;
diff --git a/ui/events/ozone/evdev/input_device_factory_evdev.cc b/ui/events/ozone/evdev/input_device_factory_evdev.cc
index c75707b..0228268 100644
--- a/ui/events/ozone/evdev/input_device_factory_evdev.cc
+++ b/ui/events/ozone/evdev/input_device_factory_evdev.cc
@@ -11,6 +11,7 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/command_line.h"
 #include "base/feature_list.h"
 #include "base/files/scoped_file.h"
 #include "base/memory/ptr_util.h"
@@ -19,11 +20,14 @@
 #include "base/trace_event/trace_event.h"
 #include "ui/events/devices/device_data_manager.h"
 #include "ui/events/devices/device_util_linux.h"
+#include "ui/events/devices/stylus_state.h"
 #include "ui/events/ozone/evdev/device_event_dispatcher_evdev.h"
 #include "ui/events/ozone/evdev/event_converter_evdev_impl.h"
 #include "ui/events/ozone/evdev/event_device_info.h"
 #include "ui/events/ozone/evdev/gamepad_event_converter_evdev.h"
+#include "ui/events/ozone/evdev/microphone_mute_switch_event_converter_evdev.h"
 #include "ui/events/ozone/evdev/stylus_button_event_converter_evdev.h"
+#include "ui/events/ozone/evdev/switches.h"
 #include "ui/events/ozone/evdev/tablet_event_converter_evdev.h"
 #include "ui/events/ozone/evdev/touch_event_converter_evdev.h"
 #include "ui/events/ozone/features.h"
@@ -131,6 +135,14 @@
             std::move(fd), params.path, params.id, devinfo, params.dispatcher));
   }
 
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          kEnableMicrophoneMuteSwitchDeviceSwitch) &&
+      devinfo.IsMicrophoneMuteSwitchDevice()) {
+    return base::WrapUnique<EventConverterEvdev>(
+        new MicrophoneMuteSwitchEventConverterEvdev(
+            std::move(fd), params.path, params.id, devinfo, params.dispatcher));
+  }
+
   // Everything else: use EventConverterEvdevImpl.
   return base::WrapUnique<EventConverterEvdevImpl>(
       new EventConverterEvdevImpl(std::move(fd), params.path, params.id,
@@ -275,6 +287,18 @@
   }
 }
 
+void InputDeviceFactoryEvdev::GetStylusSwitchState(
+    InputController::GetStylusSwitchStateReply reply) {
+  for (const auto& it : converters_) {
+    if (it.second->HasStylusSwitch()) {
+      auto result = it.second->GetStylusSwitchState();
+      std::move(reply).Run(result);
+      return;
+    }
+  }
+  std::move(reply).Run(ui::StylusState::REMOVED);
+}
+
 void InputDeviceFactoryEvdev::SetCapsLockLed(bool enabled) {
   caps_lock_led_enabled_ = enabled;
   ApplyCapsLockLed();
@@ -494,11 +518,27 @@
 
 void InputDeviceFactoryEvdev::NotifyTouchscreensUpdated() {
   std::vector<TouchscreenDevice> touchscreens;
-  for (auto it = converters_.begin(); it != converters_.end(); ++it) {
-    if (it->second->HasTouchscreen()) {
+  bool has_stylus_switch = false;
+
+  // Check if there is a stylus garage/dock presence detection switch
+  // among the devices. The internal touchscreen controller is not currently
+  // responsible for exposing this device, it usually is a gpio-keys
+  // device only containing the single switch.
+
+  for (const auto& it : converters_) {
+    if (it.second->HasStylusSwitch()) {
+      has_stylus_switch = true;
+      break;
+    }
+  }
+
+  for (const auto& it : converters_) {
+    if (it.second->HasTouchscreen()) {
       touchscreens.emplace_back(
-          it->second->input_device(), it->second->GetTouchscreenSize(),
-          it->second->GetTouchPoints(), it->second->HasPen());
+          it.second->input_device(), it.second->GetTouchscreenSize(),
+          it.second->GetTouchPoints(), it.second->HasPen(),
+          it.second->type() == ui::InputDeviceType::INPUT_DEVICE_INTERNAL &&
+              has_stylus_switch);
     }
   }
 
diff --git a/ui/events/ozone/evdev/input_device_factory_evdev.h b/ui/events/ozone/evdev/input_device_factory_evdev.h
index 1cd73a73..9b39da1 100644
--- a/ui/events/ozone/evdev/input_device_factory_evdev.h
+++ b/ui/events/ozone/evdev/input_device_factory_evdev.h
@@ -62,6 +62,8 @@
   // LED state.
   void SetCapsLockLed(bool enabled);
 
+  void GetStylusSwitchState(InputController::GetStylusSwitchStateReply reply);
+
   // Handle gamepad force feedback effects.
   void PlayVibrationEffect(int id, uint8_t amplitude, uint16_t duration_millis);
   void StopVibration(int id);
diff --git a/ui/events/ozone/evdev/input_device_factory_evdev_proxy.cc b/ui/events/ozone/evdev/input_device_factory_evdev_proxy.cc
index 9767cbdf..d7ea386c 100644
--- a/ui/events/ozone/evdev/input_device_factory_evdev_proxy.cc
+++ b/ui/events/ozone/evdev/input_device_factory_evdev_proxy.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "ui/events/devices/stylus_state.h"
 #include "ui/events/ozone/evdev/input_device_factory_evdev.h"
 
 namespace ui {
@@ -32,6 +33,14 @@
                          base::BindOnce(std::move(reply), log_paths));
 }
 
+void ForwardGetStylusSwitchStateReply(
+    scoped_refptr<base::SingleThreadTaskRunner> reply_runner,
+    InputController::GetStylusSwitchStateReply reply,
+    ui::StylusState state) {
+  // Thread hop back to UI for reply.
+  reply_runner->PostTask(FROM_HERE, base::BindOnce(std::move(reply), state));
+}
+
 }  // namespace
 
 InputDeviceFactoryEvdevProxy::InputDeviceFactoryEvdevProxy(
@@ -69,6 +78,17 @@
                                 input_device_factory_, enabled));
 }
 
+void InputDeviceFactoryEvdevProxy::GetStylusSwitchState(
+    InputController::GetStylusSwitchStateReply reply) {
+  task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&InputDeviceFactoryEvdev::GetStylusSwitchState,
+                     input_device_factory_,
+                     base::BindOnce(&ForwardGetStylusSwitchStateReply,
+                                    base::ThreadTaskRunnerHandle::Get(),
+                                    std::move(reply))));
+}
+
 void InputDeviceFactoryEvdevProxy::UpdateInputDeviceSettings(
     const InputDeviceSettingsEvdev& settings) {
   task_runner_->PostTask(
diff --git a/ui/events/ozone/evdev/input_device_factory_evdev_proxy.h b/ui/events/ozone/evdev/input_device_factory_evdev_proxy.h
index 1e35ff9..bbf3c9f 100644
--- a/ui/events/ozone/evdev/input_device_factory_evdev_proxy.h
+++ b/ui/events/ozone/evdev/input_device_factory_evdev_proxy.h
@@ -39,6 +39,7 @@
   void RemoveInputDevice(const base::FilePath& path);
   void OnStartupScanComplete();
   void SetCapsLockLed(bool enabled);
+  void GetStylusSwitchState(InputController::GetStylusSwitchStateReply reply);
   void SetTouchEventLoggingEnabled(bool enabled);
   void UpdateInputDeviceSettings(const InputDeviceSettingsEvdev& settings);
   void GetTouchDeviceStatus(InputController::GetTouchDeviceStatusReply reply);
diff --git a/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.cc b/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.cc
index 110850f..748c914 100644
--- a/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.cc
+++ b/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.cc
@@ -46,6 +46,7 @@
       has_mouse_(devinfo.HasMouse()),
       has_pointing_stick_(devinfo.HasPointingStick()),
       has_touchpad_(devinfo.HasTouchpad()),
+      has_stylus_switch_(devinfo.HasSwEvent(SW_PEN_INSERTED)),
       has_caps_lock_led_(devinfo.HasLedEvent(LED_CAPSL)),
       delegate_(std::move(delegate)) {
   // This class assumes it does not deal with internal keyboards.
@@ -108,6 +109,10 @@
   return has_caps_lock_led_;
 }
 
+bool EventReaderLibevdevCros::HasStylusSwitch() const {
+  return has_stylus_switch_;
+}
+
 void EventReaderLibevdevCros::OnDisabled() {
   delegate_->OnLibEvdevCrosStopped(&evdev_, &evstate_);
 }
diff --git a/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.h b/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.h
index 722e465..b2759bd 100644
--- a/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.h
+++ b/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.h
@@ -56,6 +56,7 @@
   bool HasPointingStick() const override;
   bool HasTouchpad() const override;
   bool HasCapsLockLed() const override;
+  bool HasStylusSwitch() const override;
   void OnDisabled() override;
 
  private:
@@ -69,6 +70,7 @@
   bool has_mouse_;
   bool has_pointing_stick_;
   bool has_touchpad_;
+  bool has_stylus_switch_;
 
   // LEDs for this device.
   bool has_caps_lock_led_;
diff --git a/ui/events/ozone/evdev/microphone_mute_switch_event_converter_evdev.cc b/ui/events/ozone/evdev/microphone_mute_switch_event_converter_evdev.cc
new file mode 100644
index 0000000..66d2db7
--- /dev/null
+++ b/ui/events/ozone/evdev/microphone_mute_switch_event_converter_evdev.cc
@@ -0,0 +1,95 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/events/ozone/evdev/microphone_mute_switch_event_converter_evdev.h"
+
+#include <errno.h>
+#include <linux/input.h>
+
+#include "base/logging.h"
+#include "base/trace_event/trace_event.h"
+#include "ui/events/event_utils.h"
+#include "ui/events/ozone/evdev/device_event_dispatcher_evdev.h"
+#include "ui/events/ozone/evdev/event_device_util.h"
+
+namespace ui {
+
+namespace {
+
+int32_t GetSwValue(int fd, unsigned int code) {
+  unsigned long bitmask[EVDEV_BITS_TO_LONGS(SW_MAX)] = {0};
+  if (ioctl(fd, EVIOCGSW(sizeof(bitmask)), bitmask) < 0) {
+    PLOG(ERROR) << "Failed EVIOCGSW";
+    return 0;
+  }
+  return EvdevBitIsSet(bitmask, code);
+}
+
+}  // namespace
+
+MicrophoneMuteSwitchEventConverterEvdev::
+    MicrophoneMuteSwitchEventConverterEvdev(
+        base::ScopedFD fd,
+        base::FilePath path,
+        int id,
+        const EventDeviceInfo& devinfo,
+        DeviceEventDispatcherEvdev* dispatcher)
+    : EventConverterEvdev(fd.get(),
+                          path,
+                          id,
+                          devinfo.device_type(),
+                          devinfo.name(),
+                          devinfo.phys(),
+                          devinfo.vendor_id(),
+                          devinfo.product_id(),
+                          devinfo.version()),
+      input_device_fd_(std::move(fd)),
+      dispatcher_(dispatcher) {
+  DCHECK(devinfo.IsMicrophoneMuteSwitchDevice());
+}
+
+MicrophoneMuteSwitchEventConverterEvdev::
+    ~MicrophoneMuteSwitchEventConverterEvdev() = default;
+
+void MicrophoneMuteSwitchEventConverterEvdev::OnDisabled() {
+  dispatcher_->DispatchMicrophoneMuteSwitchValueChanged(false);
+}
+
+void MicrophoneMuteSwitchEventConverterEvdev::OnEnabled() {
+  // Send out the initial switch state, as clients (e.g. system UI) depend on
+  // the current mute switch state.
+  dispatcher_->DispatchMicrophoneMuteSwitchValueChanged(
+      GetSwValue(input_device_fd_.get(), SW_MUTE_DEVICE));
+}
+
+void MicrophoneMuteSwitchEventConverterEvdev::OnFileCanReadWithoutBlocking(
+    int fd) {
+  TRACE_EVENT1(
+      "evdev",
+      "MicrophoneMuteSwitchEventConverterEvdev::OnFileCanReadWithoutBlocking",
+      "fd", fd);
+
+  while (true) {
+    input_event input;
+    ssize_t read_size = read(fd, &input, sizeof(input));
+    if (read_size != sizeof(input)) {
+      if (errno == EINTR || errno == EAGAIN)
+        return;
+      if (errno != ENODEV)
+        PLOG(ERROR) << "error reading device " << path_.value();
+      Stop();
+      return;
+    }
+
+    ProcessEvent(input);
+  }
+}
+
+void MicrophoneMuteSwitchEventConverterEvdev::ProcessEvent(
+    const input_event& input) {
+  if (input.type == EV_SW && input.code == SW_MUTE_DEVICE)
+    dispatcher_->DispatchMicrophoneMuteSwitchValueChanged(input.value);
+}
+
+}  // namespace ui
diff --git a/ui/events/ozone/evdev/microphone_mute_switch_event_converter_evdev.h b/ui/events/ozone/evdev/microphone_mute_switch_event_converter_evdev.h
new file mode 100644
index 0000000..476ebb4
--- /dev/null
+++ b/ui/events/ozone/evdev/microphone_mute_switch_event_converter_evdev.h
@@ -0,0 +1,51 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_EVENTS_OZONE_EVDEV_MICROPHONE_MUTE_SWITCH_EVENT_CONVERTER_EVDEV_H_
+#define UI_EVENTS_OZONE_EVDEV_MICROPHONE_MUTE_SWITCH_EVENT_CONVERTER_EVDEV_H_
+
+#include "base/component_export.h"
+#include "base/files/file_path.h"
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+#include "ui/events/ozone/evdev/event_converter_evdev.h"
+#include "ui/events/ozone/evdev/event_device_info.h"
+
+namespace ui {
+
+class DeviceEventDispatcherEvdev;
+
+class COMPONENT_EXPORT(EVDEV) MicrophoneMuteSwitchEventConverterEvdev
+    : public EventConverterEvdev {
+ public:
+  MicrophoneMuteSwitchEventConverterEvdev(
+      base::ScopedFD fd,
+      base::FilePath path,
+      int id,
+      const EventDeviceInfo& devinfo,
+      DeviceEventDispatcherEvdev* dispatcher);
+  MicrophoneMuteSwitchEventConverterEvdev(
+      const MicrophoneMuteSwitchEventConverterEvdev&) = delete;
+  MicrophoneMuteSwitchEventConverterEvdev& operator=(
+      const MicrophoneMuteSwitchEventConverterEvdev&) = delete;
+  ~MicrophoneMuteSwitchEventConverterEvdev() override;
+
+  // EventConverterEvdev
+  void OnDisabled() override;
+  void OnEnabled() override;
+  void OnFileCanReadWithoutBlocking(int fd) override;
+
+  void ProcessEvent(const struct input_event& input);
+
+ private:
+  // Input device file descriptor.
+  const base::ScopedFD input_device_fd_;
+
+  // Callbacks for dispatching events.
+  DeviceEventDispatcherEvdev* const dispatcher_;
+};
+
+}  // namespace ui
+
+#endif  // UI_EVENTS_OZONE_EVDEV_MICROPHONE_MUTE_SWITCH_EVENT_CONVERTER_EVDEV_H_
diff --git a/ui/events/ozone/evdev/microphone_mute_switch_event_converter_evdev_unittest.cc b/ui/events/ozone/evdev/microphone_mute_switch_event_converter_evdev_unittest.cc
new file mode 100644
index 0000000..554c998
--- /dev/null
+++ b/ui/events/ozone/evdev/microphone_mute_switch_event_converter_evdev_unittest.cc
@@ -0,0 +1,137 @@
+// 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 "ui/events/ozone/evdev/microphone_mute_switch_event_converter_evdev.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/input.h>
+#include <unistd.h>
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/files/scoped_file.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/devices/microphone_mute_switch_monitor.h"
+#include "ui/events/ozone/device/device_manager.h"
+#include "ui/events/ozone/evdev/event_converter_test_util.h"
+#include "ui/events/ozone/evdev/event_device_test_util.h"
+#include "ui/events/ozone/evdev/event_factory_evdev.h"
+#include "ui/events/ozone/layout/stub/stub_keyboard_layout_engine.h"
+
+namespace {
+
+const char kTestDevicePath[] = "/dev/input/test-device";
+
+class TestMicrophoneMuteObserver
+    : public ui::MicrophoneMuteSwitchMonitor::Observer {
+ public:
+  TestMicrophoneMuteObserver() {
+    ui::MicrophoneMuteSwitchMonitor::Get()->AddObserver(this);
+  }
+  TestMicrophoneMuteObserver(const TestMicrophoneMuteObserver&) = delete;
+  TestMicrophoneMuteObserver& operator=(const TestMicrophoneMuteObserver&) =
+      delete;
+  ~TestMicrophoneMuteObserver() override {
+    ui::MicrophoneMuteSwitchMonitor::Get()->RemoveObserver(this);
+  }
+
+  void OnMicrophoneMuteSwitchValueChanged(bool muted) override {
+    observed_values_.push_back(muted);
+  }
+
+  std::vector<bool> GetAndResetObservedValues() {
+    std::vector<bool> result;
+    result.swap(observed_values_);
+    return result;
+  }
+
+ private:
+  std::vector<bool> observed_values_;
+};
+
+}  // namespace
+
+class MicrophoneMuteSwitchEventConverterEvdevTest : public testing::Test {
+ public:
+  MicrophoneMuteSwitchEventConverterEvdevTest() = default;
+  ~MicrophoneMuteSwitchEventConverterEvdevTest() override = default;
+
+  // Overridden from testing::Test:
+  void SetUp() override {
+    device_manager_ = ui::CreateDeviceManagerForTest();
+    keyboard_layout_engine_ = std::make_unique<ui::StubKeyboardLayoutEngine>();
+    event_factory_ = ui::CreateEventFactoryEvdevForTest(
+        nullptr, device_manager_.get(), keyboard_layout_engine_.get(),
+        base::BindRepeating([](ui::Event* event) {
+          ADD_FAILURE() << "Unexpected event dispatch " << event->ToString();
+        }));
+    dispatcher_ =
+        ui::CreateDeviceEventDispatcherEvdevForTest(event_factory_.get());
+  }
+  void TearDown() override {
+    // Reset any switch value that might have been changed during the test.
+    ui::MicrophoneMuteSwitchMonitor::Get()->SetMicrophoneMuteSwitchValue(false);
+  }
+
+  std::unique_ptr<ui::MicrophoneMuteSwitchEventConverterEvdev> CreateDevice(
+      const ui::DeviceCapabilities& caps) {
+    int evdev_io[2];
+    if (pipe(evdev_io))
+      PLOG(FATAL) << "failed pipe";
+    base::ScopedFD events_in(evdev_io[0]);
+    events_out_.reset(evdev_io[1]);
+
+    ui::EventDeviceInfo devinfo;
+    CapabilitiesToDeviceInfo(caps, &devinfo);
+    return std::make_unique<ui::MicrophoneMuteSwitchEventConverterEvdev>(
+        std::move(events_in), base::FilePath(kTestDevicePath), 1, devinfo,
+        dispatcher_.get());
+  }
+
+ private:
+  std::unique_ptr<ui::DeviceManager> device_manager_;
+  std::unique_ptr<ui::KeyboardLayoutEngine> keyboard_layout_engine_;
+  std::unique_ptr<ui::EventFactoryEvdev> event_factory_;
+  std::unique_ptr<ui::DeviceEventDispatcherEvdev> dispatcher_;
+
+  std::vector<std::unique_ptr<ui::Event>> dispatched_events_;
+
+  base::ScopedFD events_out_;
+};
+
+TEST_F(MicrophoneMuteSwitchEventConverterEvdevTest, MuteChangeEvents) {
+  TestMicrophoneMuteObserver test_observer;
+
+  std::unique_ptr<ui::MicrophoneMuteSwitchEventConverterEvdev> dev =
+      CreateDevice(ui::kPuffMicrophoneMuteSwitch);
+
+  EXPECT_FALSE(
+      ui::MicrophoneMuteSwitchMonitor::Get()->microphone_mute_switch_on());
+
+  struct input_event mock_mute_kernel_queue[] = {
+      {{0, 0}, EV_SW, SW_MUTE_DEVICE, 1},
+      {{0, 0}, EV_SYN, SYN_REPORT, 0},
+  };
+
+  for (auto& event : mock_mute_kernel_queue)
+    dev->ProcessEvent(event);
+
+  EXPECT_TRUE(
+      ui::MicrophoneMuteSwitchMonitor::Get()->microphone_mute_switch_on());
+  EXPECT_EQ(std::vector<bool>{true}, test_observer.GetAndResetObservedValues());
+
+  struct input_event mock_unmute_kernel_queue[] = {
+      {{0, 0}, EV_SW, SW_MUTE_DEVICE, 0},
+      {{0, 0}, EV_SYN, SYN_REPORT, 0},
+  };
+
+  for (auto& event : mock_unmute_kernel_queue)
+    dev->ProcessEvent(event);
+
+  EXPECT_EQ(std::vector<bool>{false},
+            test_observer.GetAndResetObservedValues());
+}
diff --git a/ui/events/ozone/evdev/switches.cc b/ui/events/ozone/evdev/switches.cc
new file mode 100644
index 0000000..a83cb0c7
--- /dev/null
+++ b/ui/events/ozone/evdev/switches.cc
@@ -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.
+
+#include "ui/events/ozone/evdev/switches.h"
+
+namespace ui {
+
+// Enables logic to detect microphone mute switch device state, which disables
+// internal audio input when toggled.
+constexpr char kEnableMicrophoneMuteSwitchDeviceSwitch[] =
+    "enable-microphone-mute-switch-device";
+
+}  // namespace ui
diff --git a/ui/events/ozone/evdev/switches.h b/ui/events/ozone/evdev/switches.h
new file mode 100644
index 0000000..40965055
--- /dev/null
+++ b/ui/events/ozone/evdev/switches.h
@@ -0,0 +1,17 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_EVENTS_OZONE_EVDEV_SWITCHES_H_
+#define UI_EVENTS_OZONE_EVDEV_SWITCHES_H_
+
+#include "base/component_export.h"
+
+namespace ui {
+
+COMPONENT_EXPORT(EVDEV)
+extern const char kEnableMicrophoneMuteSwitchDeviceSwitch[];
+
+}  // namespace ui
+
+#endif  // UI_EVENTS_OZONE_EVDEV_SWITCHES_H_
diff --git a/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc b/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc
index 136c38a..2c3f6b575 100644
--- a/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc
+++ b/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc
@@ -159,6 +159,7 @@
     generic.touch = params;
     callback_.Run(generic);
   }
+  void DispatchMicrophoneMuteSwitchValueChanged(bool muted) override {}
 
   void DispatchKeyboardDevicesUpdated(
       const std::vector<InputDevice>& devices) override {}
diff --git a/ui/ozone/BUILD.gn b/ui/ozone/BUILD.gn
index ebeb863..73ddfd5 100644
--- a/ui/ozone/BUILD.gn
+++ b/ui/ozone/BUILD.gn
@@ -127,6 +127,7 @@
     "//ui/display/util",
     "//ui/events",
     "//ui/events:dom_keycode_converter",
+    "//ui/events/devices:devices",
     "//ui/gfx",
     "//ui/gfx/geometry",
     "//ui/gfx/ipc",
diff --git a/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc b/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
index 9cc4d27..e24805a27 100644
--- a/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
+++ b/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
@@ -218,7 +218,7 @@
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
   return window_unique_id_;
 #else
-  return std::string();
+  return wm_class_class_;
 #endif
 }
 
diff --git a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
index 3ee1a0c..326acb3 100644
--- a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
@@ -2611,7 +2611,7 @@
   auto* mock_xdg_toplevel = mock_surface->xdg_surface()->xdg_toplevel();
 
   // Only app id must be set now.
-  EXPECT_EQ(std::string(kAppId), mock_xdg_toplevel->app_id());
+  EXPECT_EQ(window->GetWindowUniqueId(), mock_xdg_toplevel->app_id());
   EXPECT_TRUE(mock_xdg_toplevel->title().empty());
   EXPECT_TRUE(mock_xdg_toplevel->min_size().IsEmpty());
   EXPECT_TRUE(mock_xdg_toplevel->max_size().IsEmpty());
@@ -2653,7 +2653,7 @@
   // restore them on Show().
   EXPECT_EQ(mock_xdg_toplevel->min_size(), min_size.value());
   EXPECT_EQ(mock_xdg_toplevel->max_size(), max_size.value());
-  EXPECT_EQ(std::string(kAppId), mock_xdg_toplevel->app_id());
+  EXPECT_EQ(window->GetWindowUniqueId(), mock_xdg_toplevel->app_id());
   EXPECT_EQ(mock_xdg_toplevel->title(), base::UTF16ToUTF8(kTitle));
 }
 
diff --git a/ui/ozone/platform/x11/x11_screen_ozone.cc b/ui/ozone/platform/x11/x11_screen_ozone.cc
index 5e708231..05a4fbf 100644
--- a/ui/ozone/platform/x11/x11_screen_ozone.cc
+++ b/ui/ozone/platform/x11/x11_screen_ozone.cc
@@ -6,7 +6,7 @@
 
 #include "ui/base/linux/linux_desktop.h"
 #include "ui/base/x/x11_idle_query.h"
-#include "ui/base/x/x11_screensaver_window_finder.h"
+#include "ui/base/x/x11_screensaver.h"
 #include "ui/base/x/x11_util.h"
 #include "ui/display/display_finder.h"
 #include "ui/display/util/display_util.h"
@@ -111,7 +111,7 @@
 
 bool X11ScreenOzone::IsScreenSaverActive() const {
   // Usually the screensaver is used to lock the screen.
-  return ScreensaverWindowFinder::ScreensaverWindowExists();
+  return IsXScreensaverActive();
 }
 
 base::TimeDelta X11ScreenOzone::CalculateIdleTime() const {
diff --git a/ui/ozone/public/input_controller.cc b/ui/ozone/public/input_controller.cc
index 35fdf8c..e6e3e43 100644
--- a/ui/ozone/public/input_controller.cc
+++ b/ui/ozone/public/input_controller.cc
@@ -9,6 +9,7 @@
 #include "base/callback.h"
 #include "base/logging.h"
 #include "base/macros.h"
+#include "ui/events/devices/stylus_state.h"
 
 namespace ui {
 
@@ -66,6 +67,9 @@
   void SetInternalTouchpadEnabled(bool enabled) override {}
   bool IsInternalTouchpadEnabled() const override { return false; }
   void SetTouchscreensEnabled(bool enabled) override {}
+  void GetStylusSwitchState(GetStylusSwitchStateReply reply) override {
+    std::move(reply).Run(ui::StylusState::REMOVED);
+  }
   void SetInternalKeyboardFilter(bool enable_filter,
                                  std::vector<DomCode> allowed_keys) override {}
   void GetGesturePropertiesService(
diff --git a/ui/ozone/public/input_controller.h b/ui/ozone/public/input_controller.h
index c18ba9c..eb4e575 100644
--- a/ui/ozone/public/input_controller.h
+++ b/ui/ozone/public/input_controller.h
@@ -22,6 +22,10 @@
 }
 
 namespace ui {
+enum class StylusState;
+}  // namespace ui
+
+namespace ui {
 
 enum class DomCode;
 
@@ -37,6 +41,7 @@
   // TODO(sky): convert this to value once mojo supports move for vectors.
   using GetTouchEventLogReply =
       base::OnceCallback<void(const std::vector<base::FilePath>&)>;
+  using GetStylusSwitchStateReply = base::OnceCallback<void(ui::StylusState)>;
 
   InputController() {}
   virtual ~InputController() {}
@@ -105,6 +110,11 @@
 
   virtual void SetTouchscreensEnabled(bool enabled) = 0;
 
+  // Find out whether stylus is in its garage; may trigger callback
+  // immediately on platforms where this cannot exist, otherwise
+  // this is be an async reply.
+  virtual void GetStylusSwitchState(GetStylusSwitchStateReply reply) = 0;
+
   // Controls vibration for the gamepad device with the corresponding |id|.
   // |amplitude| determines the strength of the vibration, where 0 is no
   // vibration and 255 is maximum vibration, and |duration_millis|
diff --git a/ui/platform_window/x11/x11_topmost_window_finder.cc b/ui/platform_window/x11/x11_topmost_window_finder.cc
index 2b8edfc..891f7d2 100644
--- a/ui/platform_window/x11/x11_topmost_window_finder.cc
+++ b/ui/platform_window/x11/x11_topmost_window_finder.cc
@@ -8,12 +8,100 @@
 
 #include <vector>
 
+#include "base/bind.h"
+#include "ui/base/x/x11_menu_list.h"
 #include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/x/x11_atom_cache.h"
+#include "ui/gfx/x/xproto_util.h"
 #include "ui/platform_window/x11/x11_window.h"
 #include "ui/platform_window/x11/x11_window_manager.h"
 
 namespace ui {
 
+namespace {
+
+using ShouldStopIteratingCallback = base::RepeatingCallback<bool(x11::Window)>;
+
+// Returns true if |window| is a named window.
+bool IsWindowNamed(x11::Window window) {
+  return PropertyExists(window, x11::Atom::WM_NAME);
+}
+
+bool EnumerateChildren(ShouldStopIteratingCallback should_stop_iterating,
+                       x11::Window window,
+                       const int max_depth,
+                       int depth) {
+  if (depth > max_depth)
+    return false;
+
+  std::vector<x11::Window> windows;
+  if (depth == 0) {
+    XMenuList::GetInstance()->InsertMenuWindows(&windows);
+    // Enumerate the menus first.
+    std::vector<x11::Window>::iterator iter;
+    for (iter = windows.begin(); iter != windows.end(); iter++) {
+      if (should_stop_iterating.Run(*iter))
+        return true;
+    }
+    windows.clear();
+  }
+
+  auto query_tree = x11::Connection::Get()->QueryTree({window}).Sync();
+  if (!query_tree)
+    return false;
+  windows = std::move(query_tree->children);
+
+  // XQueryTree returns the children of |window| in bottom-to-top order, so
+  // reverse-iterate the list to check the windows from top-to-bottom.
+  std::vector<x11::Window>::reverse_iterator iter;
+  for (iter = windows.rbegin(); iter != windows.rend(); iter++) {
+    if (IsWindowNamed(*iter) && should_stop_iterating.Run(*iter))
+      return true;
+  }
+
+  // If we're at this point, we didn't find the window we're looking for at the
+  // current level, so we need to recurse to the next level.  We use a second
+  // loop because the recursion and call to XQueryTree are expensive and is only
+  // needed for a small number of cases.
+  if (++depth <= max_depth) {
+    for (iter = windows.rbegin(); iter != windows.rend(); iter++) {
+      if (EnumerateChildren(should_stop_iterating, *iter, max_depth, depth))
+        return true;
+    }
+  }
+
+  return false;
+}
+
+bool EnumerateAllWindows(ShouldStopIteratingCallback should_stop_iterating,
+                         int max_depth) {
+  x11::Window root = GetX11RootWindow();
+  return EnumerateChildren(should_stop_iterating, root, max_depth, 0);
+}
+
+void EnumerateTopLevelWindows(
+    ui::ShouldStopIteratingCallback should_stop_iterating) {
+  std::vector<x11::Window> stack;
+  if (!ui::GetXWindowStack(ui::GetX11RootWindow(), &stack)) {
+    // Window Manager doesn't support _NET_CLIENT_LIST_STACKING, so fall back
+    // to old school enumeration of all X windows.  Some WMs parent 'top-level'
+    // windows in unnamed actual top-level windows (ion WM), so extend the
+    // search depth to all children of top-level windows.
+    const int kMaxSearchDepth = 1;
+    ui::EnumerateAllWindows(should_stop_iterating, kMaxSearchDepth);
+    return;
+  }
+  XMenuList::GetInstance()->InsertMenuWindows(&stack);
+
+  std::vector<x11::Window>::iterator iter;
+  for (iter = stack.begin(); iter != stack.end(); iter++) {
+    if (should_stop_iterating.Run(*iter))
+      return;
+  }
+}
+
+}  // namespace
+
 X11TopmostWindowFinder::X11TopmostWindowFinder() = default;
 
 X11TopmostWindowFinder::~X11TopmostWindowFinder() = default;
@@ -33,14 +121,16 @@
     return x11::Window::None;
   }
 
-  EnumerateTopLevelWindows(this);
+  EnumerateTopLevelWindows(base::BindRepeating(
+      &X11TopmostWindowFinder::ShouldStopIterating, base::Unretained(this)));
   return toplevel_;
 }
 
 x11::Window X11TopmostWindowFinder::FindWindowAt(
     const gfx::Point& screen_loc_in_pixels) {
   screen_loc_in_pixels_ = screen_loc_in_pixels;
-  EnumerateTopLevelWindows(this);
+  EnumerateTopLevelWindows(base::BindRepeating(
+      &X11TopmostWindowFinder::ShouldStopIterating, base::Unretained(this)));
   return toplevel_;
 }
 
diff --git a/ui/platform_window/x11/x11_topmost_window_finder.h b/ui/platform_window/x11/x11_topmost_window_finder.h
index 3b6f08ea..8bd4077 100644
--- a/ui/platform_window/x11/x11_topmost_window_finder.h
+++ b/ui/platform_window/x11/x11_topmost_window_finder.h
@@ -20,8 +20,7 @@
 
 // Utility class for finding the topmost window at a given screen position.
 class X11_WINDOW_EXPORT X11TopmostWindowFinder
-    : public ui::EnumerateWindowsDelegate,
-      public ui::XTopmostWindowFinder {
+    : public ui::XTopmostWindowFinder {
  public:
   X11TopmostWindowFinder();
   ~X11TopmostWindowFinder() override;
@@ -37,8 +36,7 @@
   x11::Window FindWindowAt(const gfx::Point& screen_loc_in_pixels) override;
 
  private:
-  // ui::EnumerateWindowsDelegate:
-  bool ShouldStopIterating(x11::Window window) override;
+  bool ShouldStopIterating(x11::Window window);
 
   // Returns true if |window| does not not belong to |ignore|, is visible and
   // contains |screen_loc_|.
diff --git a/ui/views/controls/button/toggle_button.cc b/ui/views/controls/button/toggle_button.cc
index 22292b19..fb9715e 100644
--- a/ui/views/controls/button/toggle_button.cc
+++ b/ui/views/controls/button/toggle_button.cc
@@ -43,7 +43,10 @@
 // Class representing the thumb (the circle that slides horizontally).
 class ToggleButton::ThumbView : public View {
  public:
-  ThumbView() { views::InstallEmptyHighlightPathGenerator(this); }
+  ThumbView() {
+    // Make the thumb behave as part of the parent for event handling.
+    SetCanProcessEventsWithinSubtree(false);
+  }
   ThumbView(const ThumbView&) = delete;
   ThumbView& operator=(const ThumbView&) = delete;
   ~ThumbView() override = default;
@@ -69,13 +72,6 @@
     return is_on ? thumb_on_color_ : thumb_off_color_;
   }
 
- protected:
-  // views::View:
-  bool GetCanProcessEventsWithinSubtree() const override {
-    // Make the thumb behave as part of the parent for event handling.
-    return false;
-  }
-
  private:
   static constexpr int kShadowOffsetX = 0;
   static constexpr int kShadowOffsetY = 1;
@@ -128,10 +124,11 @@
   slide_animation_.SetTweenType(gfx::Tween::LINEAR);
   thumb_view_ = AddChildView(std::make_unique<ThumbView>());
   ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON);
-  // TODO(pbos): Update the highlight-path shape so that a FocusRing can be used
-  // on top of it to increase contrast. Disabling it for now addresses a
-  // regression in crbug.com/1031983, but a matching FocusRing would probably be
-  // desirable.
+  // Do not set a clip, allow the ink drop to burst out.
+  // TODO(pbos): Consider an explicit InkDrop API to not use a clip rect / mask.
+  views::InstallEmptyHighlightPathGenerator(this);
+  // TODO(pbos): Update the focus-ring path shape so that one can be used on top
+  // of this control (circling the ThumbView) to increase contrast.
   SetInstallFocusRingOnFocus(false);
   SetHasInkDropActionOnClick(true);
   views::InkDrop::UseInkDropForSquareRipple(ink_drop(),
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index 892a476..7c5a325 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -763,19 +763,9 @@
 }
 
 void Textfield::OnGestureEvent(ui::GestureEvent* event) {
-  static const bool kTakeFocusOnTapUp =
-      base::FeatureList::IsEnabled(features::kTextfieldFocusOnTapUp);
-
   switch (event->type()) {
-    case ui::ET_GESTURE_TAP_DOWN:
-      if (!kTakeFocusOnTapUp) {
-        RequestFocusForGesture(event->details());
-        event->SetHandled();
-      }
-      break;
     case ui::ET_GESTURE_TAP:
-      if (kTakeFocusOnTapUp)
-        RequestFocusForGesture(event->details());
+      RequestFocusForGesture(event->details());
       if (controller_ && controller_->HandleGestureEvent(this, *event)) {
         event->SetHandled();
         return;
diff --git a/ui/views/controls/textfield/textfield_unittest.cc b/ui/views/controls/textfield/textfield_unittest.cc
index b64d595..182a40fa 100644
--- a/ui/views/controls/textfield/textfield_unittest.cc
+++ b/ui/views/controls/textfield/textfield_unittest.cc
@@ -80,11 +80,6 @@
 namespace views {
 namespace test {
 
-const ui::EventType kFocusEvent =
-    base::FeatureList::IsEnabled(features::kTextfieldFocusOnTapUp)
-        ? ui::ET_GESTURE_TAP
-        : ui::ET_GESTURE_TAP_DOWN;
-
 const char16_t kHebrewLetterSamekh = 0x05E1;
 
 // Convenience to make constructing a GestureEvent simpler.
diff --git a/ui/views/examples/animation_example.cc b/ui/views/examples/animation_example.cc
index 9ee5532..21dce5a1 100644
--- a/ui/views/examples/animation_example.cc
+++ b/ui/views/examples/animation_example.cc
@@ -11,7 +11,12 @@
 #include "ui/compositor/layer_animation_element.h"
 #include "ui/compositor/layer_animation_sequence.h"
 #include "ui/compositor/layer_animator.h"
+#include "ui/compositor/layer_delegate.h"
+#include "ui/compositor/paint_recorder.h"
+#include "ui/gfx/color_utils.h"
 #include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/views/background.h"
 #include "ui/views/layout/animating_layout_manager.h"
@@ -25,20 +30,63 @@
 
 AnimationExample::~AnimationExample() = default;
 
+class SquareLayerPainter : public ui::LayerDelegate {
+ public:
+  SquareLayerPainter(View* container, int index);
+  ~SquareLayerPainter() override = default;
+
+  // ui::LayerDelegate:
+  void OnPaintLayer(const ui::PaintContext& context) override;
+  void OnDeviceScaleFactorChanged(float old_device_scale_factor,
+                                  float new_device_scale_factor) override {}
+
+ private:
+  int index_;
+  View* container_;
+};
+
+SquareLayerPainter::SquareLayerPainter(View* container, int index)
+    : index_(index), container_(container) {}
+
+void SquareLayerPainter::OnPaintLayer(const ui::PaintContext& context) {
+  const SkColor color = SkColorSetRGB((5 - index_) * 51, 0, index_ * 51);
+  const SkColor colors[2] = {color,
+                             color_utils::HSLShift(color, {-1.0, -1.0, 0.75})};
+  cc::PaintFlags flags;
+  gfx::Rect local_bounds = gfx::Rect(container_->layer()->size());
+  ui::PaintRecorder recorder(context, local_bounds.size());
+  gfx::Canvas* canvas = recorder.canvas();
+  const float dsf = canvas->UndoDeviceScaleFactor();
+  gfx::RectF local_bounds_f = gfx::RectF(local_bounds);
+  local_bounds_f.Scale(dsf);
+  SkRect bounds = gfx::RectToSkRect(gfx::ToEnclosingRect(local_bounds_f));
+  flags.setAntiAlias(true);
+  flags.setShader(cc::PaintShader::MakeRadialGradient(
+      SkPoint::Make(bounds.centerX(), bounds.centerY()), bounds.width() / 2,
+      colors, nullptr, 2, SkTileMode::kClamp));
+  canvas->DrawRect(gfx::ToEnclosingRect(local_bounds_f), flags);
+}
+
 class AnimatingSquare : public View {
  public:
   explicit AnimatingSquare(size_t index);
   AnimatingSquare(const AnimatingSquare&) = delete;
   AnimatingSquare& operator=(const AnimatingSquare&) = delete;
   ~AnimatingSquare() override = default;
+
+ private:
+  SquareLayerPainter painter_;
 };
 
-AnimatingSquare::AnimatingSquare(size_t index) {
-  SetBackground(
-      CreateSolidBackground(SkColorSetRGB((5 - index) * 51, 0, index * 51)));
-
+AnimatingSquare::AnimatingSquare(size_t index) : painter_({this, index}) {
   SetPaintToLayer();
   layer()->SetFillsBoundsOpaquely(false);
+  layer()->SetFillsBoundsCompletely(false);
+  layer()->set_delegate(&painter_);
+  layer()->SetAnimator(new ui::LayerAnimator(base::TimeDelta::FromSeconds(1)));
+  layer()->GetAnimator()->set_tween_type(gfx::Tween::EASE_IN_OUT);
+  layer()->GetAnimator()->set_preemption_strategy(
+      ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
 
   auto opacity_sequence = std::make_unique<ui::LayerAnimationSequence>();
   opacity_sequence->set_is_repeating(true);
@@ -102,10 +150,7 @@
   container->layer()->SetMasksToBounds(true);
   container->layer()->SetFillsBoundsOpaquely(true);
 
-  container->SetLayoutManager(std::make_unique<AnimatingLayoutManager>())
-      ->SetAnimationDuration(base::TimeDelta::FromSeconds(1))
-      .SetTweenType(gfx::Tween::EASE_IN_OUT)
-      .SetTargetLayoutManager(std::make_unique<SquaresLayoutManager>());
+  container->SetLayoutManager(std::make_unique<SquaresLayoutManager>());
   for (size_t i = 0; i < 5; ++i)
     container->AddChildView(std::make_unique<AnimatingSquare>(i));
 }
diff --git a/ui/views/views_features.cc b/ui/views/views_features.cc
index 4d9b2ce..9acbbd6 100644
--- a/ui/views/views_features.cc
+++ b/ui/views/views_features.cc
@@ -27,10 +27,5 @@
 const base::Feature kInheritNativeThemeFromParentWidget{
     "InheritNativeThemeFromParentWidget", base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Change views::Textfield to take focus on a completed tap, rather than
-// immediately on tap down. This only affects touch input.
-const base::Feature kTextfieldFocusOnTapUp{"TextfieldFocusOnTapUp",
-                                           base::FEATURE_ENABLED_BY_DEFAULT};
-
 }  // namespace features
 }  // namespace views
diff --git a/ui/views/views_features.h b/ui/views/views_features.h
index 10e307c..f2dc4b6 100644
--- a/ui/views/views_features.h
+++ b/ui/views/views_features.h
@@ -16,7 +16,6 @@
 VIEWS_EXPORT extern const base::Feature kEnablePlatformHighContrastInkDrop;
 VIEWS_EXPORT extern const base::Feature kEnableViewPaintOptimization;
 VIEWS_EXPORT extern const base::Feature kInheritNativeThemeFromParentWidget;
-VIEWS_EXPORT extern const base::Feature kTextfieldFocusOnTapUp;
 
 }  // namespace features
 }  // namespace views
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_dialog.html b/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_dialog.html
index f1c09ceb..a20ab4e 100644
--- a/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_dialog.html
+++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_dialog.html
@@ -10,7 +10,9 @@
   <template>
     <style include="cr-shared-style iron-flex">
       :host {
-        --cr-dialog-width: 324px;
+        --cr-dialog-width: 320px;
+        --cr-dialog-title-slot-padding-bottom: 12px;
+        --cr-dialog-title-font-size: calc(16 / 13 * 100%);
       }
 
       .cellular-network-list-header {
@@ -29,11 +31,12 @@
       }
 
       #qrCodeCanvas {
-        width: 100%;
+        display: block;
+        margin: 20px auto 16px auto;
       }
 
       #eid {
-        margin-top: 15px;
+        margin-top: 16px;
       }
     </style>
     <cr-dialog id="eidDialog" show-on-attach>
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_dialog.js b/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_dialog.js
index deb4b91..f6a23de6 100644
--- a/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_dialog.js
+++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_dialog.js
@@ -8,8 +8,6 @@
 
 // The size of each tile in pixels.
 const QR_CODE_TILE_SIZE = 5;
-// Amount of padding around the QR code in pixels.
-const QR_CODE_PADDING = 4 * QR_CODE_TILE_SIZE;
 // Styling for filled tiles in the QR code.
 const QR_CODE_FILL_STYLE = '#000000';
 
@@ -63,8 +61,7 @@
     if (!response || !response.qrCode) {
       return;
     }
-    this.canvasSize_ =
-        response.qrCode.size * QR_CODE_TILE_SIZE + 2 * QR_CODE_PADDING;
+    this.canvasSize_ = response.qrCode.size * QR_CODE_TILE_SIZE;
     Polymer.dom.flush();
     const context = this.getCanvasContext_();
     context.clearRect(0, 0, this.canvasSize_, this.canvasSize_);
@@ -74,8 +71,7 @@
       for (let y = 0; y < response.qrCode.size; y++) {
         if (response.qrCode.data[index]) {
           context.fillRect(
-              x * QR_CODE_TILE_SIZE + QR_CODE_PADDING,
-              y * QR_CODE_TILE_SIZE + QR_CODE_PADDING, QR_CODE_TILE_SIZE,
+              x * QR_CODE_TILE_SIZE, y * QR_CODE_TILE_SIZE, QR_CODE_TILE_SIZE,
               QR_CODE_TILE_SIZE);
         }
         index++;
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.js b/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.js
index a58cf71..215120b 100644
--- a/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.js
+++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.js
@@ -452,7 +452,7 @@
           this.forwardButtonLabel = this.i18n('next');
           buttonState = {
             backward: cellularSetup.ButtonState.HIDDEN,
-            cancel: cancelButtonStateIfDisabled,
+            cancel: cancelButtonStateIfEnabled,
             forward: cellularSetup.ButtonState.DISABLED,
           };
           break;
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_list_item.js b/ui/webui/resources/cr_components/chromeos/network/network_list_item.js
index 4d851ea..20eaf25b 100644
--- a/ui/webui/resources/cr_components/chromeos/network/network_list_item.js
+++ b/ui/webui/resources/cr_components/chromeos/network/network_list_item.js
@@ -240,6 +240,10 @@
       return;
     }
 
+    // Clear subtitle to ensure that stale values are not displayed when this
+    // component is recycled for a case without subtitles.
+    this.subtitle_ = '';
+
     // Show service provider subtext only when networkState is an eSIM cellular
     // network.
     if (!this.networkState ||
diff --git a/weblayer/public/java/org/chromium/weblayer/Browser.java b/weblayer/public/java/org/chromium/weblayer/Browser.java
index c73c002..333b14d6 100644
--- a/weblayer/public/java/org/chromium/weblayer/Browser.java
+++ b/weblayer/public/java/org/chromium/weblayer/Browser.java
@@ -32,6 +32,7 @@
     // Set to null once destroyed (or for tests).
     private IBrowser mImpl;
     // The Fragment the Browser is associated with. The value of this may change.
+    @Nullable
     private Fragment mFragment;
     private final ObserverList<TabListCallback> mTabListCallbacks;
     private final UrlBarController mUrlBarController;
@@ -66,10 +67,19 @@
     /**
      * Changes the fragment. During configuration changes the fragment may change.
      */
-    void setFragment(BrowserFragment fragment) {
+    void setFragment(@Nullable BrowserFragment fragment) {
         mFragment = fragment;
     }
 
+    /**
+     * Returns the fragment this Browser is associated with. During configuration changes the
+     * fragment may change, and be null for some amount of time.
+     */
+    @Nullable
+    public Fragment getFragment() {
+        return mFragment;
+    }
+
     private void throwIfDestroyed() {
         if (mImpl == null) {
             throw new IllegalStateException("Browser can not be used once destroyed");
diff --git a/weblayer/public/java/org/chromium/weblayer/BrowserFragment.java b/weblayer/public/java/org/chromium/weblayer/BrowserFragment.java
index 5e4fda34..67091ec 100644
--- a/weblayer/public/java/org/chromium/weblayer/BrowserFragment.java
+++ b/weblayer/public/java/org/chromium/weblayer/BrowserFragment.java
@@ -128,11 +128,17 @@
     }
 
     @Override
+    @SuppressWarnings("ReferenceEquality")
     public void onDestroy() {
         ThreadCheck.ensureOnUiThread();
         // If a ViewModel is used, then the Browser is destroyed from the ViewModel, not here
         // (RemoteFragment won't call destroy on Browser either in this case).
         if (mUseViewModel) {
+            if (mBrowser.getFragment() == this) {
+                // The browser is no long associated with this fragment. Null out the reference to
+                // ensure BrowserFragment can be gc'd.
+                mBrowser.setFragment(null);
+            }
             super.onDestroy();
         } else {
             mBrowser.prepareForDestroy();