diff --git a/AUTHORS b/AUTHORS
index 9ae03a5..6f3ba06 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -17,6 +17,7 @@
 Aaron Randolph <aaron.randolph@gmail.com>
 Aaryaman Vasishta <jem456.vasishta@gmail.com>
 Abdu Ameen <abdu.ameen000@gmail.com>
+Abdullah Abu Tasneem <a.tasneem@samsung.com>
 Abhijeet Kandalkar <abhijeet.k@samsung.com>
 Abhinav Vij <abhinav.vij@samsung.com>
 Abhishek Agarwal <abhishek.a21@samsung.com>
diff --git a/DEPS b/DEPS
index 5046abc..4ec35a8a 100644
--- a/DEPS
+++ b/DEPS
@@ -306,11 +306,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': 'b5b35f8dc919376c000feb1c7c7176fd0cc7b3de',
+  'skia_revision': '550fd51bd2549bce60584b1c1703f6a23868de94',
   # 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': '1e3c2d12fd42ec18fc0bbb19a97e728941e6c4c8',
+  'v8_revision': '6652d6d5955909e94ad68a7af75aec5cf4abb63d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
@@ -377,7 +377,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': '39d570c940b94f4179fa345573355455ffb4ab64',
+  'catapult_revision': 'c996ebbd3d54112b5b730e9af212ce6b55ba61ef',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -421,7 +421,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': 'f5eec817de0df46d5aa2a7205f5b2f9c02e98dd4',
+  'dawn_revision': 'be17904ee872a4cbfc52c93040d17c7c8c33fcb7',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -445,7 +445,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling nearby
   # and whatever else without interference from each other.
-  'nearby_revision': 'b1d1019541a36f32345b6238f09faa21d7e81a3e',
+  'nearby_revision': '8679d3a370087b0da2eea508c3dd4892d14536cc',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling securemessage
   # and whatever else without interference from each other.
@@ -816,7 +816,7 @@
 
   'src/clank': {
     'url': 'https://chrome-internal.googlesource.com/clank/internal/apps.git' + '@' +
-    '709b59b8dbb560a3d544b4ddea303fd2b5a13a72',
+    '670aba050100c55cfc231981b061996105a91c3f',
     'condition': 'checkout_android and checkout_src_internal and not checkout_clank_via_src_internal',
   },
 
@@ -1000,7 +1000,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'QQCBJDbCcTJd-GDm4CHpjKdcXKjbHP9ebzyHDuU2x-4C',
+          'version': 'rcmLvPaPceZwa6euMzenA2gxol6Va8xNr2W9njQb6moC',
       },
     ],
     'condition': 'checkout_android',
@@ -1664,7 +1664,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'f5b6c4ed868219aefe172ac2d5bd683814a5f001',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '0febe43447933d6b266583f344ad08cd067237de',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1846,7 +1846,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'd1b65aa5a88f6efd900604dfcda840154e9f16e2',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'fa3aad630e1a992808c28986bb6b24cadd6d1c15',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '21a8e06d1079f2df522e1c1d395016bd0675a4c2',
 
   'src/third_party/webrtc':
     Var('webrtc_git') + '/src.git' + '@' + '538fa813283b96ff8e0b49770b5620d7bf71cdb5',
@@ -1919,7 +1919,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@7a06af5537b39890c9d465509667116ad8b3aaf4',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@454147d888a2c175760959a204f91c22c1b34747',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index a20f175..fdde973 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -2965,8 +2965,13 @@
     "system/holding_space/holding_space_animation_registry_unittest.cc",
     "system/holding_space/holding_space_ash_test_base.cc",
     "system/holding_space/holding_space_ash_test_base.h",
+    "system/holding_space/holding_space_item_views_section_unittest.cc",
     "system/holding_space/holding_space_tray_child_bubble_unittest.cc",
     "system/holding_space/holding_space_tray_unittest.cc",
+    "system/holding_space/test_holding_space_item_views_section.cc",
+    "system/holding_space/test_holding_space_item_views_section.h",
+    "system/holding_space/test_holding_space_tray_child_bubble.cc",
+    "system/holding_space/test_holding_space_tray_child_bubble.h",
     "system/human_presence/human_presence_orientation_controller_unittest.cc",
     "system/human_presence/lock_on_leave_controller_unittest.cc",
     "system/human_presence/snooping_protection_controller_unittest.cc",
diff --git a/ash/capture_mode/capture_mode_unittests.cc b/ash/capture_mode/capture_mode_unittests.cc
index 38f8260a..ff31ade 100644
--- a/ash/capture_mode/capture_mode_unittests.cc
+++ b/ash/capture_mode/capture_mode_unittests.cc
@@ -70,6 +70,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/run_loop.h"
 #include "base/scoped_observation.h"
+#include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
@@ -153,9 +154,10 @@
   const message_center::NotificationList::Notifications notifications =
       message_center::MessageCenter::Get()->GetVisibleNotifications();
   for (const auto* notification : notifications) {
-    if (notification->id().starts_with(
-            capture_mode_util::kScreenCaptureNotificationId))
+    if (base::StartsWith(notification->id(),
+                         capture_mode_util::kScreenCaptureNotificationId)) {
       return notification;
+    }
   }
   return nullptr;
 }
@@ -459,9 +461,10 @@
 
   // message_center::MessageCenterObserver:
   void OnNotificationAdded(const std::string& notification_id) override {
-    if (notification_id.starts_with(
-            capture_mode_util::kScreenCaptureNotificationId))
+    if (base::StartsWith(notification_id,
+                         capture_mode_util::kScreenCaptureNotificationId)) {
       run_loop_.Quit();
+    }
   }
 
  private:
diff --git a/ash/components/arc/arc_util.cc b/ash/components/arc/arc_util.cc
index 6390ec87..106cb8a 100644
--- a/ash/components/arc/arc_util.cc
+++ b/ash/components/arc/arc_util.cc
@@ -55,12 +55,6 @@
 constexpr char kGenerate[] = "generate";
 constexpr char kDisabled[] = "disabled";
 
-// Do not run ureadahead in vm for devices with less than 8GB due to memory
-// pressure issues since system will likely drop caches in this case.
-// The value should match platform2/arc/vm/scripts/init/arcvm-ureadahead.conf
-// in Chrome OS.
-constexpr int kReadaheadTotalMinMemoryInKb = 7500000;
-
 // Decodes a job name that may have "_2d" e.g. |kArcCreateDataJobName|
 // and returns a decoded string.
 std::string DecodeJobName(const std::string& raw_job_name) {
@@ -163,18 +157,10 @@
       ash::switches::kArcDisableUreadahead);
 }
 
-ArcVmUreadaheadMode GetArcVmUreadaheadMode(SystemMemoryInfoCallback callback) {
-  base::SystemMemoryInfoKB mem_info;
-  DCHECK(callback);
-  if (!callback.Run(&mem_info)) {
-    LOG(ERROR) << "Failed to get system memory info";
-    return ArcVmUreadaheadMode::DISABLED;
-  }
-  ArcVmUreadaheadMode mode = (mem_info.total > kReadaheadTotalMinMemoryInKb)
-                                 ? IsUreadaheadDisabled()
-                                       ? ArcVmUreadaheadMode::DISABLED
-                                       : ArcVmUreadaheadMode::READAHEAD
-                                 : ArcVmUreadaheadMode::DISABLED;
+ArcVmUreadaheadMode GetArcVmUreadaheadMode() {
+  ArcVmUreadaheadMode mode = IsUreadaheadDisabled()
+                                 ? ArcVmUreadaheadMode::DISABLED
+                                 : ArcVmUreadaheadMode::READAHEAD;
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           ash::switches::kArcVmUreadaheadMode)) {
     const std::string value =
diff --git a/ash/components/arc/arc_util.h b/ash/components/arc/arc_util.h
index 361e12d..4184a77 100644
--- a/ash/components/arc/arc_util.h
+++ b/ash/components/arc/arc_util.h
@@ -22,10 +22,6 @@
 class Window;
 }  // namespace aura
 
-namespace base {
-struct SystemMemoryInfoKB;
-}  // namespace base
-
 namespace user_manager {
 class User;
 }  // namespace user_manager
@@ -62,9 +58,6 @@
   DISABLED,
 };
 
-using SystemMemoryInfoCallback =
-    base::RepeatingCallback<bool(base::SystemMemoryInfoKB*)>;
-
 // Upstart Job Description
 struct JobDesc {
   // Explicit ctor/dtor declaration is necessary for complex struct. See
@@ -131,7 +124,7 @@
 
 // Returns mode of operation for ureadahead during the ARCVM boot flow.
 // Valid modes are readahead, generate, or disabled.
-ArcVmUreadaheadMode GetArcVmUreadaheadMode(SystemMemoryInfoCallback callback);
+ArcVmUreadaheadMode GetArcVmUreadaheadMode();
 
 // Returns true if ARC should always start within the primary user session
 // (opted in user or not), and other supported mode such as guest and Kiosk
diff --git a/ash/components/arc/arc_util_unittest.cc b/ash/components/arc/arc_util_unittest.cc
index 34e4b730..c96808f7 100644
--- a/ash/components/arc/arc_util_unittest.cc
+++ b/ash/components/arc/arc_util_unittest.cc
@@ -335,41 +335,26 @@
 }
 
 TEST_F(ArcUtilTest, GetArcVmUreadaheadMode) {
-  constexpr char kArcMemProfile4GbName[] = "4G";
-  constexpr char kArcMemProfile8GbName[] = "8G";
-  auto callback_disabled = base::BindRepeating(&GetSystemMemoryInfoForTesting,
-                                               kArcMemProfile4GbName);
-  auto callback_readahead = base::BindRepeating(&GetSystemMemoryInfoForTesting,
-                                                kArcMemProfile8GbName);
   auto* command_line = base::CommandLine::ForCurrentProcess();
 
   command_line->InitFromArgv({""});
-  EXPECT_EQ(ArcVmUreadaheadMode::READAHEAD,
-            GetArcVmUreadaheadMode(callback_readahead));
+  EXPECT_EQ(ArcVmUreadaheadMode::READAHEAD, GetArcVmUreadaheadMode());
 
   command_line->InitFromArgv({"", "--arc-disable-ureadahead"});
-  EXPECT_EQ(ArcVmUreadaheadMode::DISABLED,
-            GetArcVmUreadaheadMode(callback_readahead));
-
-  EXPECT_EQ(ArcVmUreadaheadMode::DISABLED,
-            GetArcVmUreadaheadMode(callback_disabled));
+  EXPECT_EQ(ArcVmUreadaheadMode::DISABLED, GetArcVmUreadaheadMode());
 
   command_line->InitFromArgv(
       {"", "--arc-disable-ureadahead", "--arcvm-ureadahead-mode=readahead"});
-  EXPECT_EQ(ArcVmUreadaheadMode::READAHEAD,
-            GetArcVmUreadaheadMode(callback_readahead));
+  EXPECT_EQ(ArcVmUreadaheadMode::READAHEAD, GetArcVmUreadaheadMode());
 
   command_line->InitFromArgv({"", "--arcvm-ureadahead-mode=readahead"});
-  EXPECT_EQ(ArcVmUreadaheadMode::READAHEAD,
-            GetArcVmUreadaheadMode(callback_readahead));
+  EXPECT_EQ(ArcVmUreadaheadMode::READAHEAD, GetArcVmUreadaheadMode());
 
   command_line->InitFromArgv({"", "--arcvm-ureadahead-mode=generate"});
-  EXPECT_EQ(ArcVmUreadaheadMode::GENERATE,
-            GetArcVmUreadaheadMode(callback_readahead));
+  EXPECT_EQ(ArcVmUreadaheadMode::GENERATE, GetArcVmUreadaheadMode());
 
   command_line->InitFromArgv({"", "--arcvm-ureadahead-mode=disabled"});
-  EXPECT_EQ(ArcVmUreadaheadMode::DISABLED,
-            GetArcVmUreadaheadMode(callback_readahead));
+  EXPECT_EQ(ArcVmUreadaheadMode::DISABLED, GetArcVmUreadaheadMode());
 }
 
 TEST_F(ArcUtilTest, UreadaheadDefault) {
diff --git a/ash/components/arc/session/arc_vm_client_adapter.cc b/ash/components/arc/session/arc_vm_client_adapter.cc
index 1458b66..26b9903 100644
--- a/ash/components/arc/session/arc_vm_client_adapter.cc
+++ b/ash/components/arc/session/arc_vm_client_adapter.cc
@@ -206,8 +206,7 @@
       base::StringPrintf("androidboot.zram_size=%d", guest_zram_size),
   };
 
-  const ArcVmUreadaheadMode mode =
-      GetArcVmUreadaheadMode(base::BindRepeating(&base::GetSystemMemoryInfo));
+  const ArcVmUreadaheadMode mode = GetArcVmUreadaheadMode();
   switch (mode) {
     case ArcVmUreadaheadMode::READAHEAD:
       result.push_back("androidboot.arcvm_ureadahead_mode=readahead");
@@ -611,8 +610,7 @@
       break;
   }
 
-  const ArcVmUreadaheadMode mode =
-      GetArcVmUreadaheadMode(base::BindRepeating(&base::GetSystemMemoryInfo));
+  const ArcVmUreadaheadMode mode = GetArcVmUreadaheadMode();
   switch (mode) {
     using StartArcVmRequest = vm_tools::concierge::StartArcVmRequest;
     case ArcVmUreadaheadMode::READAHEAD:
diff --git a/ash/components/phonehub/message_receiver.cc b/ash/components/phonehub/message_receiver.cc
index 68cf237e1..99c7c454 100644
--- a/ash/components/phonehub/message_receiver.cc
+++ b/ash/components/phonehub/message_receiver.cc
@@ -55,5 +55,11 @@
     observer.OnAppStreamUpdateReceived(app_stream_update);
 }
 
+void MessageReceiver::NotifyAppListUpdateReceived(
+    const proto::AppListUpdate app_list_update) {
+  for (auto& observer : observer_list_)
+    observer.OnAppListUpdateReceived(app_list_update);
+}
+
 }  // namespace phonehub
 }  // namespace ash
diff --git a/ash/components/phonehub/message_receiver.h b/ash/components/phonehub/message_receiver.h
index c642f404..3acc945 100644
--- a/ash/components/phonehub/message_receiver.h
+++ b/ash/components/phonehub/message_receiver.h
@@ -47,6 +47,10 @@
     // Called when there is an update in the streamed app.
     virtual void OnAppStreamUpdateReceived(
         const proto::AppStreamUpdate app_stream_update) {}
+
+    // Called when there is an update of streamable apps.
+    virtual void OnAppListUpdateReceived(
+        const proto::AppListUpdate app_list_update) {}
   };
 
   MessageReceiver(const MessageReceiver&) = delete;
@@ -70,6 +74,7 @@
       const proto::FetchCameraRollItemDataResponse& response);
   void NotifyAppStreamUpdateReceived(
       const proto::AppStreamUpdate app_stream_update);
+  void NotifyAppListUpdateReceived(const proto::AppListUpdate app_list_update);
 
  private:
   base::ObserverList<Observer> observer_list_;
diff --git a/ash/components/phonehub/message_receiver_impl.cc b/ash/components/phonehub/message_receiver_impl.cc
index 52b9b3d4..7e10322 100644
--- a/ash/components/phonehub/message_receiver_impl.cc
+++ b/ash/components/phonehub/message_receiver_impl.cc
@@ -153,6 +153,19 @@
     NotifyAppStreamUpdateReceived(app_stream_update);
     return;
   }
+
+  if (features::IsEcheSWAEnabled() &&
+      message_type == proto::MessageType::APP_LIST_UPDATE) {
+    proto::AppListUpdate app_list_update;
+    // Serialized proto is after the first two bytes of |payload|.
+    if (!app_list_update.ParseFromString(payload.substr(2))) {
+      PA_LOG(ERROR) << "OnMessageReceived() could not deserialize the "
+                    << "AppListUpdate proto message.";
+      return;
+    }
+    NotifyAppListUpdateReceived(app_list_update);
+    return;
+  }
 }
 
 }  // namespace phonehub
diff --git a/ash/components/phonehub/message_receiver_unittest.cc b/ash/components/phonehub/message_receiver_unittest.cc
index 04235376..a8226c2 100644
--- a/ash/components/phonehub/message_receiver_unittest.cc
+++ b/ash/components/phonehub/message_receiver_unittest.cc
@@ -46,6 +46,8 @@
 
   size_t app_stream_update_calls() const { return app_stream_update_calls_; }
 
+  size_t app_list_update_calls() const { return app_list_update_calls_; }
+
   proto::PhoneStatusSnapshot last_snapshot() const { return last_snapshot_; }
 
   proto::PhoneStatusUpdate last_status_update() const {
@@ -60,6 +62,10 @@
     return last_app_stream_update_;
   }
 
+  proto::AppListUpdate last_app_list_update() const {
+    return last_app_list_update_;
+  }
+
   proto::FetchCameraRollItemsResponse last_fetch_camera_roll_items_response()
       const {
     return last_fetch_camera_roll_items_response_;
@@ -107,6 +113,11 @@
     ++app_stream_update_calls_;
   }
 
+  void OnAppListUpdateReceived(proto::AppListUpdate app_list_update) override {
+    last_app_list_update_ = app_list_update;
+    ++app_list_update_calls_;
+  }
+
  private:
   size_t phone_status_snapshot_updated_num_calls_ = 0;
   size_t phone_status_updated_num_calls_ = 0;
@@ -114,10 +125,12 @@
   size_t fetch_camera_roll_items_response_calls_ = 0;
   size_t fetch_camera_roll_item_data_response_calls_ = 0;
   size_t app_stream_update_calls_ = 0;
+  size_t app_list_update_calls_ = 0;
   proto::PhoneStatusSnapshot last_snapshot_;
   proto::PhoneStatusUpdate last_status_update_;
   proto::FeatureSetupResponse last_feature_setup_response_;
   proto::AppStreamUpdate last_app_stream_update_;
+  proto::AppListUpdate last_app_list_update_;
   proto::FetchCameraRollItemsResponse last_fetch_camera_roll_items_response_;
   proto::FetchCameraRollItemDataResponse
       last_fetch_camera_roll_item_data_response_;
@@ -180,6 +193,10 @@
     return fake_observer_.app_stream_update_calls();
   }
 
+  size_t GetNumAppListUpdateCalls() const {
+    return fake_observer_.app_list_update_calls();
+  }
+
   proto::PhoneStatusSnapshot GetLastSnapshot() const {
     return fake_observer_.last_snapshot();
   }
@@ -206,13 +223,17 @@
     return fake_observer_.last_app_stream_update();
   }
 
+  proto::AppListUpdate GetLastAppListUpdate() const {
+    return fake_observer_.last_app_list_update();
+  }
+
   FakeObserver fake_observer_;
   std::unique_ptr<secure_channel::FakeConnectionManager>
       fake_connection_manager_;
   std::unique_ptr<MessageReceiverImpl> message_receiver_;
 };
 
-TEST_F(MessageReceiverImplTest, OnPhoneStatusSnapshotReceieved) {
+TEST_F(MessageReceiverImplTest, OnPhoneStatusSnapshotReceived) {
   const int32_t expected_battery_percentage = 15;
   auto expected_phone_properties = std::make_unique<proto::PhoneProperties>();
   expected_phone_properties->set_battery_percentage(
@@ -423,7 +444,7 @@
   EXPECT_EQ(0u, GetNumFetchCameraRollItemDataResponseCalls());
 }
 
-TEST_F(MessageReceiverImplTest, OnAppStreamUpdateReceieved) {
+TEST_F(MessageReceiverImplTest, OnAppStreamUpdateReceived) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(features::kEcheSWA);
 
@@ -448,5 +469,58 @@
             actual_app_stream_update.foreground_app().visible_name());
 }
 
+TEST_F(MessageReceiverImplTest, OnAppListUpdateReceived) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(features::kEcheSWA);
+
+  proto::AppListUpdate expected_app_list_update;
+  auto* streamable_apps = expected_app_list_update.mutable_all_apps();
+  streamable_apps->add_apps();
+
+  // Simulate receiving a message.
+  const std::string expected_message =
+      SerializeMessage(proto::APP_LIST_UPDATE, &expected_app_list_update);
+  fake_connection_manager_->NotifyMessageReceived(expected_message);
+
+  proto::AppListUpdate actual_app_list_update = GetLastAppListUpdate();
+
+  EXPECT_EQ(1u, GetNumAppListUpdateCalls());
+  EXPECT_TRUE(actual_app_list_update.has_all_apps());
+  EXPECT_EQ(1, actual_app_list_update.all_apps().apps_size());
+}
+
+TEST_F(MessageReceiverImplTest, OnAppListUpdateReceivedNoStreamableApps) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(features::kEcheSWA);
+
+  proto::AppListUpdate expected_app_list_update;
+
+  // Simulate receiving a message.
+  const std::string expected_message =
+      SerializeMessage(proto::APP_LIST_UPDATE, &expected_app_list_update);
+  fake_connection_manager_->NotifyMessageReceived(expected_message);
+
+  proto::AppListUpdate actual_app_list_update = GetLastAppListUpdate();
+
+  EXPECT_EQ(1u, GetNumAppListUpdateCalls());
+  EXPECT_FALSE(actual_app_list_update.has_all_apps());
+}
+
+TEST_F(MessageReceiverImplTest, OnAppListUpdateReceivedFlagDisabled) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndDisableFeature(features::kEcheSWA);
+
+  proto::AppListUpdate expected_app_list_update;
+  auto* streamable_apps = expected_app_list_update.mutable_all_apps();
+  streamable_apps->add_apps();
+
+  // Simulate receiving a message.
+  const std::string expected_message =
+      SerializeMessage(proto::APP_LIST_UPDATE, &expected_app_list_update);
+  fake_connection_manager_->NotifyMessageReceived(expected_message);
+
+  EXPECT_EQ(0u, GetNumAppListUpdateCalls());
+}
+
 }  // namespace phonehub
 }  // namespace ash
diff --git a/ash/components/phonehub/proto/phonehub_api.proto b/ash/components/phonehub/proto/phonehub_api.proto
index aa57c731..af962f26 100644
--- a/ash/components/phonehub/proto/phonehub_api.proto
+++ b/ash/components/phonehub/proto/phonehub_api.proto
@@ -40,6 +40,7 @@
   FEATURE_SETUP_REQUEST = 24;
   FEATURE_SETUP_RESPONSE = 25;
   APP_STREAM_UPDATE = 28;
+  APP_LIST_UPDATE = 29;
 }
 
 enum NotificationSetting {
@@ -377,6 +378,11 @@
   optional App foreground_app = 1;
 }
 
+message AppListUpdate {
+  // List of apps available to stream, sorted by recency.
+  optional StreamableApps all_apps = 1;
+}
+
 // When adding new fields to this message, update CameraRollItem#operator==
 // Located in ash/components/phonehub/camera_roll_item.cc.
 message CameraRollItemMetadata {
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 93f3fdce..64b272b 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -2068,11 +2068,6 @@
              "WallpaperFullScreenPreview",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
-// Enable Google Photos integration in the new wallpaper experience.
-BASE_FEATURE(kWallpaperGooglePhotosIntegration,
-             "WallpaperGooglePhotosIntegration",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 // Enable different wallpapers per desk.
 BASE_FEATURE(kWallpaperPerDesk,
              "WallpaperPerDesk",
@@ -3127,10 +3122,6 @@
   return base::FeatureList::IsEnabled(kWallpaperFullScreenPreview);
 }
 
-bool IsWallpaperGooglePhotosIntegrationEnabled() {
-  return base::FeatureList::IsEnabled(kWallpaperGooglePhotosIntegration);
-}
-
 bool IsWallpaperPerDeskEnabled() {
   return base::FeatureList::IsEnabled(kWallpaperPerDesk);
 }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index f9fd4cf..285d5b0 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -587,8 +587,6 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kWallpaperFastRefresh);
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kWallpaperFullScreenPreview);
-COMPONENT_EXPORT(ASH_CONSTANTS)
-BASE_DECLARE_FEATURE(kWallpaperGooglePhotosIntegration);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kWallpaperPerDesk);
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kWebUITabStripTabDragIntegration);
@@ -859,8 +857,6 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsViewPpdEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsWallpaperFastRefreshEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsWallpaperFullScreenPreviewEnabled();
-COMPONENT_EXPORT(ASH_CONSTANTS)
-bool IsWallpaperGooglePhotosIntegrationEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsWallpaperPerDeskEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsWebUITabStripTabDragIntegrationEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsWifiSyncAndroidEnabled();
diff --git a/ash/quick_pair/keyed_service/quick_pair_mediator.cc b/ash/quick_pair/keyed_service/quick_pair_mediator.cc
index 245076f5..e0b2dcb 100644
--- a/ash/quick_pair/keyed_service/quick_pair_mediator.cc
+++ b/ash/quick_pair/keyed_service/quick_pair_mediator.cc
@@ -162,6 +162,13 @@
 
 void Mediator::OnDeviceFound(scoped_refptr<Device> device) {
   QP_LOG(INFO) << __func__ << ": " << device;
+
+  if (device_currently_showing_notification_) {
+    QP_LOG(INFO) << __func__ << ": already showing notification for "
+                 << device_currently_showing_notification_;
+    return;
+  }
+
   // Get the device name and add it to the device object, the device will only
   // have a name in the cache if this is a subsequent pairing scenario.
   if (device->protocol == Protocol::kFastPairSubsequent &&
@@ -174,6 +181,7 @@
   // On discovery, download and decode device images. TODO (b/244472452):
   // remove logic that is executed for every advertisement even if no
   // notification is shown.
+  device_currently_showing_notification_ = device;
   ui_broker_->ShowDiscovery(device);
   fast_pair_repository_->FetchDeviceImages(device);
 }
@@ -192,12 +200,20 @@
 
 void Mediator::OnRetroactivePairFound(scoped_refptr<Device> device) {
   QP_LOG(INFO) << __func__ << ": " << device;
+
+  if (device_currently_showing_notification_) {
+    QP_LOG(INFO) << __func__ << ": already showing notification for "
+                 << device_currently_showing_notification_;
+    return;
+  }
+
   // SFUL metrics will cause a crash if Fast Pair is disabled when we
   // retroactive pair, so prevent a notification from popping up.
   // TODO(b/247148054): Look into moving this elsewhere.
   if (!feature_status_tracker_->IsFastPairEnabled())
     return;
-  ui_broker_->ShowAssociateAccount(std::move(device));
+  device_currently_showing_notification_ = device;
+  ui_broker_->ShowAssociateAccount(device);
 }
 
 void Mediator::SetFastPairState(bool is_enabled) {
@@ -231,6 +247,7 @@
   QP_LOG(INFO) << __func__ << ": Device=" << device;
   ui_broker_->RemoveNotifications(
       /*clear_already_shown_discovery_notification_cache=*/false);
+  device_currently_showing_notification_ = nullptr;
   scanner_broker_->OnDevicePaired(device);
   fast_pair_repository_->PersistDeviceImages(device);
 
@@ -278,8 +295,20 @@
     } break;
     case DiscoveryAction::kAlreadyDisplayed:
     case DiscoveryAction::kDismissedByOs:
+      break;
     case DiscoveryAction::kDismissedByTimeout:
     case DiscoveryAction::kDismissedByUser:
+      // When the notification is dismissed by timeout or dismissed by user,
+      // there will be no more notifications for |device|. We reset
+      // |device_currently_showing_notification_| to enforce the first come,
+      // first serve notification strategy to allow other notifications to be
+      // shown. We do not do this for `kDismissedByOs` because this is triggered
+      // when a discovery notification is removed to be replaced by the
+      // connection notification to signify pairing is progress, and thus not
+      // in a terminal state, and we do not want to permit other notifications
+      // during this time.
+      device_currently_showing_notification_ = nullptr;
+      break;
     case DiscoveryAction::kLearnMore:
       break;
   }
@@ -288,6 +317,7 @@
 void Mediator::OnPairingFailureAction(scoped_refptr<Device> device,
                                       PairingFailedAction action) {
   QP_LOG(INFO) << __func__ << ": Device=" << device << ", Action=" << action;
+  device_currently_showing_notification_ = nullptr;
 }
 
 void Mediator::OnCompanionAppAction(scoped_refptr<Device> device,
@@ -304,10 +334,17 @@
       pairer_broker_->PairDevice(device);
       ui_broker_->RemoveNotifications(
           /*clear_already_shown_discovery_notification_cache=*/false);
+      device_currently_showing_notification_ = nullptr;
       break;
     case AssociateAccountAction::kDismissedByOs:
+      break;
     case AssociateAccountAction::kDismissedByTimeout:
     case AssociateAccountAction::kDismissedByUser:
+      // Retroactive pairing only has the associate account notification. If the
+      // user elects to save the device or dismisses it, the lifetime of the
+      // notification is over and a new one can appear.
+      device_currently_showing_notification_ = nullptr;
+      break;
     case AssociateAccountAction::kLearnMore:
       break;
   }
diff --git a/ash/quick_pair/keyed_service/quick_pair_mediator.h b/ash/quick_pair/keyed_service/quick_pair_mediator.h
index 8613c01e..96ec4029 100644
--- a/ash/quick_pair/keyed_service/quick_pair_mediator.h
+++ b/ash/quick_pair/keyed_service/quick_pair_mediator.h
@@ -122,6 +122,11 @@
   void CancelPairing();
 
   bool has_at_least_one_discovery_session_ = false;
+
+  // |device_currently_showing_notification_| can be null if there is no
+  // notification currently displayed to user.
+  scoped_refptr<Device> device_currently_showing_notification_;
+
   std::unique_ptr<FeatureStatusTracker> feature_status_tracker_;
   std::unique_ptr<ScannerBroker> scanner_broker_;
   std::unique_ptr<MessageStreamLookup> message_stream_lookup_;
diff --git a/ash/quick_pair/keyed_service/quick_pair_mediator_unittest.cc b/ash/quick_pair/keyed_service/quick_pair_mediator_unittest.cc
index d4940788..4cc4a3a 100644
--- a/ash/quick_pair/keyed_service/quick_pair_mediator_unittest.cc
+++ b/ash/quick_pair/keyed_service/quick_pair_mediator_unittest.cc
@@ -200,6 +200,13 @@
   mock_scanner_broker_->NotifyDeviceFound(device_);
 }
 
+TEST_F(MediatorTest, InvokesShowDiscovery_OnlyOneDevice_DeviceFound) {
+  feature_status_tracker_->SetIsFastPairEnabled(true);
+  EXPECT_CALL(*mock_ui_broker_, ShowDiscovery).Times(1);
+  mock_scanner_broker_->NotifyDeviceFound(device_);
+  mock_scanner_broker_->NotifyDeviceFound(device_);
+}
+
 TEST_F(MediatorTest, InvokesShowPairing_V1) {
   feature_status_tracker_->SetIsFastPairEnabled(true);
   auto device = base::MakeRefCounted<Device>(kTestMetadataId, kTestAddress,
@@ -430,6 +437,13 @@
   fake_retroactive_pairing_detector_->NotifyRetroactivePairFound(device_);
 }
 
+TEST_F(MediatorTest, InvokesShowAssociateAccount_OnlyOneNotification) {
+  feature_status_tracker_->SetIsFastPairEnabled(true);
+  EXPECT_CALL(*mock_ui_broker_, ShowAssociateAccount).Times(1);
+  fake_retroactive_pairing_detector_->NotifyRetroactivePairFound(device_);
+  fake_retroactive_pairing_detector_->NotifyRetroactivePairFound(device_);
+}
+
 TEST_F(MediatorTest, DoesntInvokeShowAssociateAccount_FastPairDisabled) {
   feature_status_tracker_->SetIsFastPairEnabled(false);
   EXPECT_CALL(*mock_ui_broker_, ShowAssociateAccount).Times(0);
diff --git a/ash/shell.cc b/ash/shell.cc
index ef509039..5d60c86 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -160,6 +160,7 @@
 #include "ash/system/toast/toast_manager_impl.h"
 #include "ash/system/tray/system_tray_notifier.h"
 #include "ash/system/usb_peripheral/usb_peripheral_notification_controller.h"
+#include "ash/system/video_conference/fake_video_conference_tray_controller.h"
 #include "ash/system/video_conference/video_conference_tray_controller.h"
 #include "ash/touch/ash_touch_transform_controller.h"
 #include "ash/touch/touch_devices_controller.h"
@@ -1440,8 +1441,12 @@
   // may be observers of it, and will assume it exists for as long as they
   // themselves exist.
   if (features::IsVcControlsUiEnabled()) {
+    // `VideoConferenceTrayController` relies on audio and camera services to
+    // function properly, so we will use the fake version when `dbus_bus` is not
+    // available so that this works on linux-chromeos and unit tests.
     video_conference_tray_controller_ =
-        shell_delegate_->CreateVideoConferenceTrayController();
+        dbus_bus ? std::make_unique<VideoConferenceTrayController>()
+                 : std::make_unique<FakeVideoConferenceTrayController>();
   }
 
   window_tree_host_manager_->InitHosts();
diff --git a/ash/shell_delegate.h b/ash/shell_delegate.h
index 508212fe..388b150a 100644
--- a/ash/shell_delegate.h
+++ b/ash/shell_delegate.h
@@ -40,7 +40,6 @@
 class GlanceablesDelegate;
 class NearbyShareController;
 class NearbyShareDelegate;
-class VideoConferenceTrayController;
 class SystemSoundsDelegate;
 
 // Delegate of the Shell.
@@ -79,9 +78,6 @@
   virtual std::unique_ptr<SystemSoundsDelegate> CreateSystemSoundsDelegate()
       const = 0;
 
-  virtual std::unique_ptr<VideoConferenceTrayController>
-  CreateVideoConferenceTrayController() const = 0;
-
   // Returns the geolocation loader factory used to initialize geolocation
   // provider.
   virtual scoped_refptr<network::SharedURLLoaderFactory>
diff --git a/ash/style/color_util.cc b/ash/style/color_util.cc
index fd3d79db..51781ec 100644
--- a/ash/style/color_util.cc
+++ b/ash/style/color_util.cc
@@ -24,7 +24,7 @@
 constexpr int kLightBackgroundBlendAlpha = 127;  // 50%
 
 // Alternate alpha values used when `kDarkLightModeKMeansColor` is active.
-constexpr int kDarkBackgroundBlendKMeansAlpha = 179;   // 70%
+constexpr int kDarkBackgroundBlendKMeansAlpha = 165;   // 65%
 constexpr int kLightBackgroundBlendKMeansAlpha = 230;  // 90%
 
 // Clamp the lightness of input user colors so that there is sufficient contrast
diff --git a/ash/style/color_util_unittest.cc b/ash/style/color_util_unittest.cc
index 3bf9502..28802d5 100644
--- a/ash/style/color_util_unittest.cc
+++ b/ash/style/color_util_unittest.cc
@@ -108,9 +108,9 @@
 TEST_F(ColorUtilTest, MixesWithBlackInDarkMode) {
   // Tuple of k_mean_color, expected output color after masking with black.
   std::vector<std::tuple<SkColor, SkColor>> cases = {
-      {SK_ColorRED, SkColorSetARGB(0xFF, 0x4C, 0x00, 0x00)},
-      {SK_ColorGREEN, SkColorSetARGB(0xFF, 0x00, 0x4C, 0x00)},
-      {SK_ColorMAGENTA, SkColorSetARGB(0xFF, 0x4C, 0x00, 0x4C)},
+      {SK_ColorRED, SkColorSetARGB(0xFF, 0x5A, 0x00, 0x00)},
+      {SK_ColorGREEN, SkColorSetARGB(0xFF, 0x00, 0x5A, 0x00)},
+      {SK_ColorMAGENTA, SkColorSetARGB(0xFF, 0x5A, 0x00, 0x5A)},
   };
   for (const auto& [k_mean_color, expected_color] : cases) {
     test_api()->SetCalculatedColors({{}, k_mean_color});
@@ -125,22 +125,22 @@
   // with black.
   std::vector<std::tuple<SkColor, SkColor>> cases = {
       // Pure black is shifted to dark gray.
-      {SK_ColorBLACK, SkColorSetARGB(0xFF, 0x17, 0x17, 0x17)},
+      {SK_ColorBLACK, SkColorSetARGB(0xFF, 0x1B, 0x1B, 0x1B)},
       // #4D4D4D should result in the same output color as black.
       {
           SkColorSetARGB(0xFF, 0x4D, 0x4D, 0x4D),
-          SkColorSetARGB(0xFF, 0x17, 0x17, 0x17),
+          SkColorSetARGB(0xFF, 0x1B, 0x1B, 0x1B),
       },
       // Slightly lighter than last case results in a different output color
       // from previous two, as it is light enough to skip lightness shift.
       {
           SkColorSetARGB(0xFF, 0x4F, 0x4F, 0x4F),
-          SkColorSetARGB(0xFF, 0x18, 0x18, 0x18),
+          SkColorSetARGB(0xFF, 0x1C, 0x1C, 0x1C),
       },
       // Dark red retains red hue.
       {
           SkColorSetARGB(0xFF, 0x44, 0x00, 0x00),
-          SkColorSetARGB(0xFF, 0x2E, 0x00, 0x00),
+          SkColorSetARGB(0xFF, 0x36, 0x00, 0x00),
       },
   };
   for (const auto& [k_mean_color, expected_color] : cases) {
diff --git a/ash/system/holding_space/holding_space_ash_test_base.cc b/ash/system/holding_space/holding_space_ash_test_base.cc
index 30bbed2b..334101a1 100644
--- a/ash/system/holding_space/holding_space_ash_test_base.cc
+++ b/ash/system/holding_space/holding_space_ash_test_base.cc
@@ -4,6 +4,7 @@
 
 #include "ash/system/holding_space/holding_space_ash_test_base.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/holding_space/holding_space_controller.h"
 #include "ash/public/cpp/holding_space/holding_space_image.h"
 #include "ash/public/cpp/holding_space/holding_space_prefs.h"
@@ -11,40 +12,78 @@
 #include "base/strings/strcat.h"
 
 namespace ash {
+namespace {
+
+std::unique_ptr<HoldingSpaceImage> CreateStubHoldingSpaceImage(
+    HoldingSpaceItem::Type type,
+    const base::FilePath& file_path) {
+  return std::make_unique<HoldingSpaceImage>(
+      holding_space_util::GetMaxImageSizeForType(type), file_path,
+      /*async_bitmap_resolver=*/base::DoNothing());
+}
+
+}  // namespace
 
 HoldingSpaceAshTestBase::HoldingSpaceAshTestBase() = default;
 
 HoldingSpaceAshTestBase::~HoldingSpaceAshTestBase() = default;
 
-void HoldingSpaceAshTestBase::AddItem(HoldingSpaceItem::Type type,
-                                      const base::FilePath& file_path) {
-  auto* model = HoldingSpaceController::Get()->model();
-  ASSERT_TRUE(model);
-  model->AddItem(HoldingSpaceItem::CreateFileBackedItem(
-      type, file_path,
-      GURL(base::StrCat({"filesystem: ", file_path.BaseName().value()})),
-      base::BindOnce(
-          [](HoldingSpaceItem::Type type, const base::FilePath& file_path) {
-            return std::make_unique<HoldingSpaceImage>(
-                holding_space_util::GetMaxImageSizeForType(type), file_path,
-                /*async_bitmap_resolver=*/base::DoNothing());
-          })));
+HoldingSpaceItem* HoldingSpaceAshTestBase::AddItem(
+    HoldingSpaceItem::Type type,
+    const base::FilePath& file_path) {
+  std::unique_ptr<HoldingSpaceItem> item =
+      HoldingSpaceItem::CreateFileBackedItem(
+          type, file_path,
+          GURL(base::StrCat({"filesystem:", file_path.BaseName().value()})),
+          base::BindOnce(&CreateStubHoldingSpaceImage));
+  auto* item_ptr = item.get();
+  DCHECK(model());
+  model()->AddItem(std::move(item));
+  return item_ptr;
+}
+
+HoldingSpaceItem* HoldingSpaceAshTestBase::AddPartiallyInitializedItem(
+    HoldingSpaceItem::Type type,
+    const base::FilePath& path) {
+  // Create a holding space item, and use it to create a serialized item
+  // dictionary, then immediately deserialize it. This results in a
+  // partially initialized item, since it does not have a `GURL` for the
+  // backing file.
+  std::unique_ptr<HoldingSpaceItem> item =
+      HoldingSpaceItem::CreateFileBackedItem(
+          type, path, GURL("filesystem:ignored"),
+          base::BindOnce(&CreateStubHoldingSpaceImage));
+  const base::DictionaryValue serialized_holding_space_item = item->Serialize();
+  std::unique_ptr<HoldingSpaceItem> deserialized_item =
+      HoldingSpaceItem::Deserialize(
+          serialized_holding_space_item,
+          /*image_resolver=*/
+          base::BindOnce(&CreateStubHoldingSpaceImage));
+  DCHECK(!deserialized_item->IsInitialized());
+
+  HoldingSpaceItem* deserialized_item_ptr = deserialized_item.get();
+  DCHECK(model());
+  model()->AddItem(std::move(deserialized_item));
+  return deserialized_item_ptr;
 }
 
 void HoldingSpaceAshTestBase::RemoveAllItems() {
-  auto* model = HoldingSpaceController::Get()->model();
-  ASSERT_TRUE(model);
-  model->RemoveIf(
+  ASSERT_TRUE(model());
+  model()->RemoveIf(
       base::BindRepeating([](const HoldingSpaceItem* item) { return true; }));
 }
 
+void HoldingSpaceAshTestBase::MarkTimeOfFirstAdd(AccountId account_id) {
+  holding_space_prefs::MarkTimeOfFirstAdd(
+      GetSessionControllerClient()->GetUserPrefService(account_id));
+}
+
 void HoldingSpaceAshTestBase::SetUp() {
   AshTestBase::SetUp();
 
   // Add and activate a new user.
-  constexpr char kUserEmail[] = "user@test";
-  AccountId account_id = AccountId::FromUserEmail(kUserEmail);
-  GetSessionControllerClient()->AddUserSession(kUserEmail);
+  AccountId account_id = AccountId::FromUserEmail(kTestUser);
+  GetSessionControllerClient()->AddUserSession(kTestUser);
   GetSessionControllerClient()->SwitchActiveUser(account_id);
 
   // Mark the holding space feature as being available to the user.
diff --git a/ash/system/holding_space/holding_space_ash_test_base.h b/ash/system/holding_space/holding_space_ash_test_base.h
index 0c1111cf..fa522ca 100644
--- a/ash/system/holding_space/holding_space_ash_test_base.h
+++ b/ash/system/holding_space/holding_space_ash_test_base.h
@@ -5,16 +5,20 @@
 #ifndef ASH_SYSTEM_HOLDING_SPACE_HOLDING_SPACE_ASH_TEST_BASE_H_
 #define ASH_SYSTEM_HOLDING_SPACE_HOLDING_SPACE_ASH_TEST_BASE_H_
 
+#include "ash/public/cpp/holding_space/holding_space_controller.h"
 #include "ash/public/cpp/holding_space/holding_space_item.h"
 #include "ash/public/cpp/holding_space/holding_space_model.h"
 #include "ash/public/cpp/holding_space/mock_holding_space_client.h"
 #include "ash/test/ash_test_base.h"
+#include "components/account_id/account_id.h"
 
 namespace ash {
 
 // Base class for tests of holding space in ash.
 class HoldingSpaceAshTestBase : public AshTestBase {
  public:
+  static constexpr char kTestUser[] = "user@test";
+
   HoldingSpaceAshTestBase();
   HoldingSpaceAshTestBase(const HoldingSpaceAshTestBase&) = delete;
   HoldingSpaceAshTestBase& operator=(const HoldingSpaceAshTestBase&) = delete;
@@ -22,11 +26,23 @@
 
   // Adds an item of the specified `type` backed by a file at the specified
   // `file_path` to the model for the currently active user.
-  void AddItem(HoldingSpaceItem::Type type, const base::FilePath& file_path);
+  HoldingSpaceItem* AddItem(HoldingSpaceItem::Type type,
+                            const base::FilePath& file_path);
+
+  // Adds an item of the specified `type` that is not fully initialized to
+  // the model for the currently active user.
+  HoldingSpaceItem* AddPartiallyInitializedItem(HoldingSpaceItem::Type type,
+                                                const base::FilePath& path);
 
   // Removes all items from the model for the currently active user.
   void RemoveAllItems();
 
+  // Mark the time of first add in prefs.
+  void MarkTimeOfFirstAdd(
+      AccountId account_id = AccountId::FromUserEmail(kTestUser));
+
+  HoldingSpaceModel* model() { return HoldingSpaceController::Get()->model(); }
+
  protected:
   // AshTestBase:
   void SetUp() override;
diff --git a/ash/system/holding_space/holding_space_item_views_section_unittest.cc b/ash/system/holding_space/holding_space_item_views_section_unittest.cc
new file mode 100644
index 0000000..a2c53ca
--- /dev/null
+++ b/ash/system/holding_space/holding_space_item_views_section_unittest.cc
@@ -0,0 +1,165 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/system/holding_space/holding_space_item_views_section.h"
+
+#include <memory>
+
+#include "ash/public/cpp/holding_space/holding_space_image.h"
+#include "ash/public/cpp/holding_space/holding_space_section.h"
+#include "ash/public/cpp/holding_space/holding_space_test_api.h"
+#include "ash/public/cpp/holding_space/holding_space_util.h"
+#include "ash/session/test_session_controller_client.h"
+#include "ash/system/holding_space/holding_space_ash_test_base.h"
+#include "ash/system/holding_space/holding_space_item_view.h"
+#include "ash/system/holding_space/holding_space_view_delegate.h"
+#include "ash/system/holding_space/test_holding_space_item_views_section.h"
+#include "ash/system/holding_space/test_holding_space_tray_child_bubble.h"
+#include "base/functional/bind.h"
+#include "base/functional/callback_forward.h"
+#include "base/strings/strcat.h"
+#include "ui/views/widget/unique_widget_ptr.h"
+
+namespace ash {
+namespace {
+
+std::vector<std::pair<HoldingSpaceSectionId, HoldingSpaceItem::Type>>
+GetSectionIdItemTypePairs() {
+  std::vector<std::pair<HoldingSpaceSectionId, HoldingSpaceItem::Type>> pairs;
+
+  for (int i = 0; i <= static_cast<int>(HoldingSpaceSectionId::kMaxValue);
+       ++i) {
+    auto id = static_cast<HoldingSpaceSectionId>(i);
+    auto* section = GetHoldingSpaceSection(id);
+    DCHECK(section && section->supported_types.size());
+
+    HoldingSpaceItem::Type type = *(section->supported_types.begin());
+    pairs.emplace_back(id, type);
+  }
+
+  return pairs;
+}
+
+}  // namespace
+
+class HoldingSpaceItemViewsSectionTest
+    : public HoldingSpaceAshTestBase,
+      public testing::WithParamInterface<
+          std::pair<HoldingSpaceSectionId, HoldingSpaceItem::Type>> {
+ public:
+  HoldingSpaceSectionId section_id() const { return GetParam().first; }
+  HoldingSpaceItem::Type item_type() const { return GetParam().second; }
+  HoldingSpaceItemViewsSection* item_views_section() {
+    return item_views_section_;
+  }
+
+ private:
+  // HoldingSpaceAshTestBase
+  void SetUp() override {
+    HoldingSpaceAshTestBase::SetUp();
+    widget_ = std::make_unique<views::Widget>();
+    widget_->Init(views::Widget::InitParams{});
+
+    view_delegate_ = std::make_unique<HoldingSpaceViewDelegate>(nullptr);
+
+    auto* tray_child_bubble = widget_->GetRootView()->AddChildView(
+        std::make_unique<TestHoldingSpaceTrayChildBubble>(
+            view_delegate_.get(),
+            TestHoldingSpaceTrayChildBubble::Params(base::BindOnce(
+                &HoldingSpaceItemViewsSectionTest::CreateSections,
+                base::Unretained(this)))));
+
+    tray_child_bubble->Init();
+  }
+
+  void TearDown() override {
+    widget_.reset();
+    view_delegate_.reset();
+
+    HoldingSpaceAshTestBase::TearDown();
+  }
+
+  std::vector<std::unique_ptr<HoldingSpaceItemViewsSection>> CreateSections(
+      HoldingSpaceViewDelegate* view_delegate) {
+    auto section = std::make_unique<TestHoldingSpaceItemViewsSection>(
+        view_delegate, section_id());
+    item_views_section_ = section.get();
+
+    std::vector<std::unique_ptr<HoldingSpaceItemViewsSection>> sections;
+    sections.push_back(std::move(section));
+    return sections;
+  }
+
+  std::unique_ptr<HoldingSpaceViewDelegate> view_delegate_;
+  views::UniqueWidgetPtr widget_;
+
+  TestHoldingSpaceItemViewsSection* item_views_section_ = nullptr;
+};
+
+INSTANTIATE_TEST_SUITE_P(All,
+                         HoldingSpaceItemViewsSectionTest,
+                         testing::ValuesIn(GetSectionIdItemTypePairs()));
+
+// Verifies the items are ordered as expected.
+TEST_P(HoldingSpaceItemViewsSectionTest, ItemOrder) {
+  const absl::optional<size_t> section_max_views =
+      GetHoldingSpaceSection(section_id())->max_visible_item_count;
+
+  // Add a number of items.
+  std::vector<HoldingSpaceItem*> items;
+  for (size_t i = 0; i <= section_max_views.value_or(10); ++i) {
+    base::FilePath file_path("/tmp/fake_" + base::NumberToString(i));
+    items.emplace_back(AddItem(item_type(), file_path));
+  }
+
+  // Reverse the items so that the are the same order that we expect from the
+  // views.
+  std::reverse(items.begin(), items.end());
+
+  auto views = item_views_section()->GetHoldingSpaceItemViews();
+
+  // The number of views that will appear depends on the section type. If it's
+  // not limited or the number of items is fewer than the max, assume all items
+  // are shown.
+  size_t expected_views_size =
+      section_max_views.has_value() && section_max_views.value() < items.size()
+          ? section_max_views.value()
+          : items.size();
+
+  ASSERT_EQ(expected_views_size, views.size());
+
+  for (size_t i = 0; i < views.size(); ++i) {
+    auto* item_view = HoldingSpaceItemView::Cast(views[i]);
+    auto* item = items[i];
+    EXPECT_EQ(item_view->item(), item);
+  }
+}
+
+// Verifies that partially initialized items will not show until they are fully
+// initialized.
+TEST_P(HoldingSpaceItemViewsSectionTest, PartiallyInitializedItemsDontShow) {
+  auto* partially_initialized_item =
+      AddPartiallyInitializedItem(item_type(), base::FilePath("/tmp/fake1"));
+  auto views = item_views_section()->GetHoldingSpaceItemViews();
+
+  EXPECT_EQ(views.size(), 0u);
+
+  AddItem(item_type(), base::FilePath("/tmp/fake2"));
+  views = item_views_section()->GetHoldingSpaceItemViews();
+
+  EXPECT_EQ(views.size(), 1u);
+
+  // Once initialized, the item should show a view as normal.
+  model()->InitializeOrRemoveItem(
+      partially_initialized_item->id(),
+      GURL(base::StrCat(
+          {"filesystem:",
+           partially_initialized_item->file_path().BaseName().value()})));
+
+  views = item_views_section()->GetHoldingSpaceItemViews();
+  ASSERT_EQ(views.size(), 2u);
+  EXPECT_EQ(views[1]->item(), partially_initialized_item);
+}
+
+}  // namespace ash
diff --git a/ash/system/holding_space/holding_space_tray_child_bubble_unittest.cc b/ash/system/holding_space/holding_space_tray_child_bubble_unittest.cc
index e844974..e0bf9b86 100644
--- a/ash/system/holding_space/holding_space_tray_child_bubble_unittest.cc
+++ b/ash/system/holding_space/holding_space_tray_child_bubble_unittest.cc
@@ -17,6 +17,8 @@
 #include "ash/system/holding_space/holding_space_item_views_section.h"
 #include "ash/system/holding_space/holding_space_tray.h"
 #include "ash/system/holding_space/holding_space_view_delegate.h"
+#include "ash/system/holding_space/test_holding_space_item_views_section.h"
+#include "ash/system/holding_space/test_holding_space_tray_child_bubble.h"
 #include "base/files/file_path.h"
 #include "base/test/scoped_feature_list.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -24,71 +26,6 @@
 #include "ui/views/widget/unique_widget_ptr.h"
 
 namespace ash {
-namespace {
-
-// TestHoldingSpaceItemViewsSection --------------------------------------------
-
-class TestHoldingSpaceItemViewsSection : public HoldingSpaceItemViewsSection {
- public:
-  TestHoldingSpaceItemViewsSection(HoldingSpaceViewDelegate* view_delegate,
-                                   HoldingSpaceSectionId section_id)
-      : HoldingSpaceItemViewsSection(view_delegate, section_id) {}
-
- private:
-  // HoldingSpaceItemViewsSection:
-  std::unique_ptr<views::View> CreateHeader() override {
-    return std::make_unique<views::View>();
-  }
-
-  std::unique_ptr<views::View> CreateContainer() override {
-    return std::make_unique<views::View>();
-  }
-
-  std::unique_ptr<HoldingSpaceItemView> CreateView(
-      const HoldingSpaceItem* item) override {
-    return std::make_unique<HoldingSpaceItemChipView>(delegate(), item);
-  }
-};
-
-// TestHoldingSpaceTrayChildBubble ---------------------------------------------
-
-class TestHoldingSpaceTrayChildBubble : public HoldingSpaceTrayChildBubble {
- public:
-  struct Params {
-    base::OnceCallback<
-        std::vector<std::unique_ptr<HoldingSpaceItemViewsSection>>(
-            HoldingSpaceViewDelegate* view_delegate)>
-        create_sections_callback;
-
-    base::OnceCallback<std::unique_ptr<views::View>()>
-        create_placeholder_callback;
-  };
-
-  TestHoldingSpaceTrayChildBubble(HoldingSpaceViewDelegate* view_delegate,
-                                  Params params)
-      : HoldingSpaceTrayChildBubble(view_delegate),
-        params_(std::move(params)) {}
-
- private:
-  // HoldingSpaceChildBubble:
-  std::vector<std::unique_ptr<HoldingSpaceItemViewsSection>> CreateSections()
-      override {
-    return params_.create_sections_callback
-               ? std::move(params_.create_sections_callback).Run(delegate())
-               : std::vector<std::unique_ptr<HoldingSpaceItemViewsSection>>();
-  }
-
-  std::unique_ptr<views::View> CreatePlaceholder() override {
-    return params_.create_placeholder_callback
-               ? std::move(params_.create_placeholder_callback).Run()
-               : nullptr;
-  }
-
-  Params params_;
-};
-
-}  // namespace
-
 // HoldingSpaceTrayChildBubbleTestBase -----------------------------------------
 
 class HoldingSpaceTrayChildBubbleTestBase : public HoldingSpaceAshTestBase {
@@ -176,14 +113,13 @@
       HoldingSpaceViewDelegate* view_delegate) override {
     return std::make_unique<TestHoldingSpaceTrayChildBubble>(
         view_delegate,
-        TestHoldingSpaceTrayChildBubble::Params{
-            .create_sections_callback = base::BindOnce(
+        TestHoldingSpaceTrayChildBubble::Params(
+            base::BindOnce(
                 &HoldingSpaceTrayChildBubblePlaceholderTest::CreateSections,
                 base::Unretained(this)),
-            .create_placeholder_callback = base::BindOnce(
+            base::BindOnce(
                 &HoldingSpaceTrayChildBubblePlaceholderTest::CreatePlaceholder,
-                base::Unretained(this)),
-        });
+                base::Unretained(this))));
   }
 
   std::vector<std::unique_ptr<HoldingSpaceItemViewsSection>> CreateSections(
@@ -219,6 +155,14 @@
     ExpectPlaceholderOrGone();
   }
 
+  AddPartiallyInitializedItem(HoldingSpaceItem::Type::kPinnedFile,
+                              base::FilePath("foo"));
+
+  {
+    SCOPED_TRACE(testing::Message() << "Partially initialized state.");
+    ExpectPlaceholderOrGone();
+  }
+
   AddItem(HoldingSpaceItem::Type::kPinnedFile, base::FilePath("foo"));
 
   {
diff --git a/ash/system/holding_space/holding_space_tray_unittest.cc b/ash/system/holding_space/holding_space_tray_unittest.cc
index 3bc3cd79..19cb2d8 100644
--- a/ash/system/holding_space/holding_space_tray_unittest.cc
+++ b/ash/system/holding_space/holding_space_tray_unittest.cc
@@ -28,6 +28,7 @@
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/holding_space/holding_space_animation_registry.h"
+#include "ash/system/holding_space/holding_space_ash_test_base.h"
 #include "ash/system/holding_space/holding_space_item_view.h"
 #include "ash/system/holding_space/holding_space_tray_icon_preview.h"
 #include "ash/system/progress_indicator/progress_indicator.h"
@@ -579,6 +580,10 @@
   HoldingSpaceModel holding_space_model_;
 };
 
+// TODO(crbug.com/1373911): Break up `HoldingSpaceTrayTest` so that tests are
+// grouped by the component they're testing. Do not add new tests to this suite.
+// If you have a test that truly belongs this file, use (or create) a test suite
+// that inherits from `HoldingSpaceAshTestBase`.
 class HoldingSpaceTrayTest : public HoldingSpaceTrayTestBase {
  public:
   HoldingSpaceTrayTest() {
@@ -845,79 +850,6 @@
   EXPECT_FALSE(test_api()->IsShowingInShelf());
 }
 
-// Verifies the pinned files bubble is not shown if it only contains partially
-// initialized items.
-TEST_F(HoldingSpaceTrayTest,
-       PinnedFilesBubbleWithPartiallyInitializedItemsOnly) {
-  MarkTimeOfFirstPin();
-  StartSession();
-
-  // Add a download item to show the tray button.
-  AddItem(HoldingSpaceItem::Type::kDownload, base::FilePath("/tmp/download"));
-
-  AddPartiallyInitializedItem(HoldingSpaceItem::Type::kPinnedFile,
-                              base::FilePath("/tmp/fake_1"));
-
-  test_api()->Show();
-  EXPECT_FALSE(test_api()->PinnedFilesBubbleShown());
-
-  // Add another partially initialized item.
-  HoldingSpaceItem* item_2 = AddPartiallyInitializedItem(
-      HoldingSpaceItem::Type::kPinnedFile, base::FilePath("/tmp/fake_2"));
-  EXPECT_FALSE(test_api()->PinnedFilesBubbleShown());
-
-  // Add a fully initialized item, and verify it gets shown.
-  HoldingSpaceItem* item_3 = AddItem(HoldingSpaceItem::Type::kPinnedFile,
-                                     base::FilePath("/tmp/fake_3"));
-  EXPECT_TRUE(test_api()->PinnedFilesBubbleShown());
-
-  std::vector<views::View*> pinned_files = test_api()->GetPinnedFileChips();
-  ASSERT_EQ(1u, pinned_files.size());
-  EXPECT_EQ(item_3->id(),
-            HoldingSpaceItemView::Cast(pinned_files[0])->item()->id());
-  EXPECT_TRUE(HoldingSpaceItemView::Cast(pinned_files[0])->GetVisible());
-
-  // Fully initialize a partially initialized item with an empty URL - it should
-  // get removed.
-  model()->InitializeOrRemoveItem(item_2->id(), GURL());
-
-  pinned_files = test_api()->GetPinnedFileChips();
-  ASSERT_EQ(1u, pinned_files.size());
-  EXPECT_EQ(item_3->id(),
-            HoldingSpaceItemView::Cast(pinned_files[0])->item()->id());
-}
-
-// Verifies the pinned items section is shown and orders items as expected when
-// the model contains a number of initialized items prior to showing UI.
-TEST_F(HoldingSpaceTrayTest, PinnedFilesSectionWithInitializedItemsOnly) {
-  MarkTimeOfFirstPin();
-  StartSession();
-
-  // Add a number of initialized pinned items.
-  std::deque<HoldingSpaceItem*> items;
-  for (int i = 0; i < 10; ++i) {
-    items.push_back(
-        AddItem(HoldingSpaceItem::Type::kPinnedFile,
-                base::FilePath("/tmp/fake_" + base::NumberToString(i))));
-  }
-
-  test_api()->Show();
-  EXPECT_TRUE(test_api()->PinnedFilesBubbleShown());
-
-  std::vector<views::View*> pinned_files = test_api()->GetPinnedFileChips();
-  ASSERT_EQ(items.size(), pinned_files.size());
-
-  while (!items.empty()) {
-    // View order is expected to be reverse of item order.
-    auto* pinned_file = HoldingSpaceItemView::Cast(pinned_files.back());
-    EXPECT_EQ(pinned_file->item()->id(), items.front()->id());
-
-    items.pop_front();
-    pinned_files.pop_back();
-  }
-  test_api()->Close();
-}
-
 // Right clicking the holding space tray should show a context menu if the
 // previews feature is enabled. Otherwise it should do nothing.
 TEST_F(HoldingSpaceTrayTest, ShouldMaybeShowContextMenuOnRightClick) {
@@ -4157,4 +4089,86 @@
   }
 }
 
+// TODO(crbug.com/1373911): Once `HoldingSpaceTrayTest` is smaller,
+// parameterized, and based on `HoldingSpaceAshTestBase`, this can be folded
+// into it. Test suite to confirm that holding space is visible in the tray when
+// appropriate.
+class HoldingSpaceTrayVisibilityTest
+    : public HoldingSpaceAshTestBase,
+      public testing::WithParamInterface<
+          std::tuple<HoldingSpaceItem::Type,
+                     /*predictability_enabled=*/bool,
+                     /*suggestions_enabled=*/bool>> {
+ public:
+  HoldingSpaceTrayVisibilityTest() {
+    std::vector<base::test::FeatureRef> enabled_features;
+    std::vector<base::test::FeatureRef> disabled_features;
+
+    (IsHoldingSpacePredictabilityEnabled() ? enabled_features
+                                           : disabled_features)
+        .push_back(features::kHoldingSpacePredictability);
+
+    (IsHoldingSpaceSuggestionsEnabled() ? enabled_features : disabled_features)
+        .push_back(features::kHoldingSpaceSuggestions);
+
+    scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features);
+  }
+
+  void SetUp() override {
+    HoldingSpaceAshTestBase::SetUp();
+    test_api_ = std::make_unique<HoldingSpaceTestApi>();
+  }
+
+  void TearDown() override {
+    test_api_.reset();
+    AshTestBase::TearDown();
+  }
+
+  // Returns the parameterized holding space item type.
+  HoldingSpaceItem::Type GetType() const { return std::get<0>(GetParam()); }
+
+  bool IsHoldingSpacePredictabilityEnabled() const {
+    return std::get<1>(GetParam());
+  }
+
+  bool IsHoldingSpaceSuggestionsEnabled() const {
+    return std::get<2>(GetParam());
+  }
+
+  HoldingSpaceTestApi* test_api() { return test_api_.get(); }
+
+ private:
+  std::unique_ptr<HoldingSpaceTestApi> test_api_;
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    HoldingSpaceTrayVisibilityTest,
+    testing::Combine(testing::ValuesIn(GetHoldingSpaceItemTypes()),
+                     /*predictability_enabled=*/testing::Bool(),
+                     /*suggestions_enabled=*/testing::Bool()));
+
+TEST_P(HoldingSpaceTrayVisibilityTest, TrayShowsForCorrectItemTypes) {
+  // Partially initialized items should not cause the tray to show.
+  HoldingSpaceItem* item =
+      AddPartiallyInitializedItem(GetType(), base::FilePath("/tmp/fake"));
+  EXPECT_EQ(test_api()->IsShowingInShelf(),
+            IsHoldingSpacePredictabilityEnabled());
+
+  // Once initialized, the item should show the tray if appropriate.
+  model()->InitializeOrRemoveItem(
+      item->id(), GURL(base::StrCat(
+                      {"filesystem:", item->file_path().BaseName().value()})));
+
+  if (IsHoldingSpacePredictabilityEnabled()) {
+    // In the predictability experiment, the tray should always be showing.
+    EXPECT_TRUE(test_api()->IsShowingInShelf());
+  } else {
+    // A suggestion alone should not show the tray.
+    EXPECT_NE(test_api()->IsShowingInShelf(),
+              HoldingSpaceItem::IsSuggestion(GetType()));
+  }
+}
+
 }  // namespace ash
diff --git a/ash/system/holding_space/test_holding_space_item_views_section.cc b/ash/system/holding_space/test_holding_space_item_views_section.cc
new file mode 100644
index 0000000..3944799
--- /dev/null
+++ b/ash/system/holding_space/test_holding_space_item_views_section.cc
@@ -0,0 +1,31 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/system/holding_space/test_holding_space_item_views_section.h"
+
+#include "ash/system/holding_space/holding_space_item_chip_view.h"
+#include "ui/views/view.h"
+
+namespace ash {
+
+TestHoldingSpaceItemViewsSection::TestHoldingSpaceItemViewsSection(
+    HoldingSpaceViewDelegate* view_delegate,
+    HoldingSpaceSectionId section_id)
+    : HoldingSpaceItemViewsSection(view_delegate, section_id) {}
+
+std::unique_ptr<views::View> TestHoldingSpaceItemViewsSection::CreateHeader() {
+  return std::make_unique<views::View>();
+}
+
+std::unique_ptr<views::View>
+TestHoldingSpaceItemViewsSection::CreateContainer() {
+  return std::make_unique<views::View>();
+}
+
+std::unique_ptr<HoldingSpaceItemView>
+TestHoldingSpaceItemViewsSection::CreateView(const HoldingSpaceItem* item) {
+  return std::make_unique<HoldingSpaceItemChipView>(delegate(), item);
+}
+
+}  // namespace ash
diff --git a/ash/system/holding_space/test_holding_space_item_views_section.h b/ash/system/holding_space/test_holding_space_item_views_section.h
new file mode 100644
index 0000000..de24c74
--- /dev/null
+++ b/ash/system/holding_space/test_holding_space_item_views_section.h
@@ -0,0 +1,31 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_SYSTEM_HOLDING_SPACE_TEST_HOLDING_SPACE_ITEM_VIEWS_SECTION_H_
+#define ASH_SYSTEM_HOLDING_SPACE_TEST_HOLDING_SPACE_ITEM_VIEWS_SECTION_H_
+
+#include <memory>
+
+#include "ash/system/holding_space/holding_space_item_views_section.h"
+
+namespace ash {
+
+// Simple implementation of the abstract `HoldingSpaceItemViewsSection` class
+// for testing.
+class TestHoldingSpaceItemViewsSection : public HoldingSpaceItemViewsSection {
+ public:
+  TestHoldingSpaceItemViewsSection(HoldingSpaceViewDelegate* view_delegate,
+                                   HoldingSpaceSectionId section_id);
+
+ private:
+  // HoldingSpaceItemViewsSection:
+  std::unique_ptr<views::View> CreateHeader() override;
+  std::unique_ptr<views::View> CreateContainer() override;
+  std::unique_ptr<HoldingSpaceItemView> CreateView(
+      const HoldingSpaceItem* item) override;
+};
+
+}  // namespace ash
+
+#endif  // ASH_SYSTEM_HOLDING_SPACE_TEST_HOLDING_SPACE_ITEM_VIEWS_SECTION_H_
diff --git a/ash/system/holding_space/test_holding_space_tray_child_bubble.cc b/ash/system/holding_space/test_holding_space_tray_child_bubble.cc
new file mode 100644
index 0000000..cbb3c642
--- /dev/null
+++ b/ash/system/holding_space/test_holding_space_tray_child_bubble.cc
@@ -0,0 +1,42 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/system/holding_space/test_holding_space_tray_child_bubble.h"
+
+#include "ash/system/holding_space/holding_space_item_views_section.h"
+
+namespace ash {
+
+TestHoldingSpaceTrayChildBubble::Params::Params() = default;
+
+TestHoldingSpaceTrayChildBubble::Params::Params(Params&& other) = default;
+
+TestHoldingSpaceTrayChildBubble::Params::Params(
+    CreateSectionsCallback create_sections_callback,
+    CreatePlaceholderCallback create_placeholder_callback)
+    : create_sections_callback(std::move(create_sections_callback)),
+      create_placeholder_callback(std::move(create_placeholder_callback)) {}
+
+TestHoldingSpaceTrayChildBubble::Params::~Params() = default;
+
+TestHoldingSpaceTrayChildBubble::TestHoldingSpaceTrayChildBubble(
+    HoldingSpaceViewDelegate* view_delegate,
+    Params params)
+    : HoldingSpaceTrayChildBubble(view_delegate), params_(std::move(params)) {}
+
+std::vector<std::unique_ptr<HoldingSpaceItemViewsSection>>
+TestHoldingSpaceTrayChildBubble::CreateSections() {
+  return params_.create_sections_callback
+             ? std::move(params_.create_sections_callback).Run(delegate())
+             : std::vector<std::unique_ptr<HoldingSpaceItemViewsSection>>();
+}
+
+std::unique_ptr<views::View>
+TestHoldingSpaceTrayChildBubble::CreatePlaceholder() {
+  return params_.create_placeholder_callback
+             ? std::move(params_.create_placeholder_callback).Run()
+             : nullptr;
+}
+
+}  // namespace ash
diff --git a/ash/system/holding_space/test_holding_space_tray_child_bubble.h b/ash/system/holding_space/test_holding_space_tray_child_bubble.h
new file mode 100644
index 0000000..c13d74e
--- /dev/null
+++ b/ash/system/holding_space/test_holding_space_tray_child_bubble.h
@@ -0,0 +1,52 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_SYSTEM_HOLDING_SPACE_TEST_HOLDING_SPACE_TRAY_CHILD_BUBBLE_H_
+#define ASH_SYSTEM_HOLDING_SPACE_TEST_HOLDING_SPACE_TRAY_CHILD_BUBBLE_H_
+
+#include <memory>
+#include <vector>
+
+#include "ash/system/holding_space/holding_space_tray_child_bubble.h"
+
+namespace ash {
+
+// Simple implementation of the abstract class `HoldingSpaceTrayChildBubble` for
+// testing. Allows callers to pass in callbacks through `Params` to dictate what
+// sections and placeholder are created.
+class TestHoldingSpaceTrayChildBubble : public HoldingSpaceTrayChildBubble {
+ public:
+  struct Params {
+    using CreateSectionsCallback = base::OnceCallback<
+        std::vector<std::unique_ptr<HoldingSpaceItemViewsSection>>(
+            HoldingSpaceViewDelegate* view_delegate)>;
+    using CreatePlaceholderCallback =
+        base::OnceCallback<std::unique_ptr<views::View>()>;
+
+    Params();
+    Params(Params&& other);
+    explicit Params(CreateSectionsCallback create_sections_callback,
+                    CreatePlaceholderCallback create_placeholder_callback =
+                        base::NullCallback());
+    ~Params();
+
+    CreateSectionsCallback create_sections_callback;
+    CreatePlaceholderCallback create_placeholder_callback;
+  };
+
+  TestHoldingSpaceTrayChildBubble(HoldingSpaceViewDelegate* view_delegate,
+                                  Params params);
+
+ private:
+  // HoldingSpaceChildBubble:
+  std::vector<std::unique_ptr<HoldingSpaceItemViewsSection>> CreateSections()
+      override;
+  std::unique_ptr<views::View> CreatePlaceholder() override;
+
+  Params params_;
+};
+
+}  // namespace ash
+
+#endif  // ASH_SYSTEM_HOLDING_SPACE_TEST_HOLDING_SPACE_TRAY_CHILD_BUBBLE_H_
diff --git a/ash/system/video_conference/video_conference_tray_unittest.cc b/ash/system/video_conference/video_conference_tray_unittest.cc
index b5d30b5..32945fe 100644
--- a/ash/system/video_conference/video_conference_tray_unittest.cc
+++ b/ash/system/video_conference/video_conference_tray_unittest.cc
@@ -15,7 +15,6 @@
 #include "ash/system/unified/unified_system_tray.h"
 #include "ash/system/video_conference/fake_video_conference_tray_controller.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test_shell_delegate.h"
 #include "base/test/scoped_feature_list.h"
 #include "ui/events/test/event_generator.h"
 #include "ui/gfx/image/image_skia_operations.h"
@@ -43,7 +42,7 @@
   void SetUp() override {
     scoped_feature_list_.InitAndEnableFeature(features::kVcControlsUi);
 
-    AshTestBase::SetUp(std::make_unique<TestShellDelegate>());
+    AshTestBase::SetUp();
   }
 
   VideoConferenceTray* video_conference_tray() {
diff --git a/ash/test_shell_delegate.cc b/ash/test_shell_delegate.cc
index 6615b3f..f2f9a1c 100644
--- a/ash/test_shell_delegate.cc
+++ b/ash/test_shell_delegate.cc
@@ -14,7 +14,6 @@
 #include "ash/public/cpp/test/test_nearby_share_delegate.h"
 #include "ash/system/geolocation/test_geolocation_url_loader_factory.h"
 #include "ash/system/test_system_sounds_delegate.h"
-#include "ash/system/video_conference/fake_video_conference_tray_controller.h"
 #include "ash/wm/gestures/back_gesture/test_back_gesture_contextual_nudge_delegate.h"
 #include "url/gurl.h"
 
@@ -65,11 +64,6 @@
   return std::make_unique<TestSystemSoundsDelegate>();
 }
 
-std::unique_ptr<ash::VideoConferenceTrayController>
-TestShellDelegate::CreateVideoConferenceTrayController() const {
-  return std::make_unique<FakeVideoConferenceTrayController>();
-}
-
 scoped_refptr<network::SharedURLLoaderFactory>
 TestShellDelegate::GetGeolocationUrlLoaderFactory() const {
   return static_cast<scoped_refptr<network::SharedURLLoaderFactory>>(
diff --git a/ash/test_shell_delegate.h b/ash/test_shell_delegate.h
index 3768e11..7ba3de6 100644
--- a/ash/test_shell_delegate.h
+++ b/ash/test_shell_delegate.h
@@ -49,8 +49,6 @@
       const override;
   std::unique_ptr<SystemSoundsDelegate> CreateSystemSoundsDelegate()
       const override;
-  std::unique_ptr<ash::VideoConferenceTrayController>
-  CreateVideoConferenceTrayController() const override;
   scoped_refptr<network::SharedURLLoaderFactory>
   GetGeolocationUrlLoaderFactory() const override;
   bool CanGoBack(gfx::NativeWindow window) const override;
diff --git a/ash/wallpaper/wallpaper_controller_impl.cc b/ash/wallpaper/wallpaper_controller_impl.cc
index fb821d8..7eec548 100644
--- a/ash/wallpaper/wallpaper_controller_impl.cc
+++ b/ash/wallpaper/wallpaper_controller_impl.cc
@@ -1152,10 +1152,6 @@
 void WallpaperControllerImpl::SetGooglePhotosWallpaper(
     const GooglePhotosWallpaperParams& params,
     WallpaperController::SetWallpaperCallback callback) {
-  if (!features::IsWallpaperGooglePhotosIntegrationEnabled()) {
-    std::move(callback).Run(false);
-    return;
-  }
   if (!Shell::Get()->session_controller()->IsActiveUserSessionStarted() ||
       !CanSetUserWallpaper(params.account_id)) {
     std::move(callback).Run(/*success=*/false);
@@ -3296,10 +3292,6 @@
 void WallpaperControllerImpl::HandleGooglePhotosWallpaperInfoSyncedIn(
     const AccountId& account_id,
     const WallpaperInfo& info) {
-  if (!features::IsWallpaperGooglePhotosIntegrationEnabled()) {
-    NOTREACHED();
-    return;
-  }
   bool daily_refresh_enabled = info.type == WallpaperType::kDailyGooglePhotos;
   if (daily_refresh_enabled) {
     // We only want to update the user's `WallpaperInfo` if this is a new
diff --git a/ash/wallpaper/wallpaper_controller_unittest.cc b/ash/wallpaper/wallpaper_controller_unittest.cc
index bb4b678f..b9b850a 100644
--- a/ash/wallpaper/wallpaper_controller_unittest.cc
+++ b/ash/wallpaper/wallpaper_controller_unittest.cc
@@ -2236,10 +2236,6 @@
   EXPECT_EQ(wallpaper_info, expected_custom_wallpaper_info);
 
   {
-    base::test::ScopedFeatureList scoped_feature_list;
-    scoped_feature_list.InitWithFeatures(
-        {ash::features::kWallpaperGooglePhotosIntegration}, {});
-
     // Now set a Google Photos wallpaper. Verify that it's set successfully and
     // the wallpaper info is updated.
     ClearWallpaperCount();
@@ -4355,15 +4351,7 @@
     : public WallpaperControllerTest,
       public testing::WithParamInterface<bool> {
  public:
-  WallpaperControllerGooglePhotosWallpaperTest() {
-    if (GooglePhotosEnabled()) {
-      scoped_feature_list_.InitWithFeatures(
-          {ash::features::kWallpaperGooglePhotosIntegration}, {});
-    } else {
-      scoped_feature_list_.InitWithFeatures(
-          {}, {ash::features::kWallpaperGooglePhotosIntegration});
-    }
-  }
+  WallpaperControllerGooglePhotosWallpaperTest() = default;
 
   WallpaperControllerGooglePhotosWallpaperTest(
       const WallpaperControllerGooglePhotosWallpaperTest&) = delete;
@@ -4372,8 +4360,6 @@
 
   ~WallpaperControllerGooglePhotosWallpaperTest() override = default;
 
-  bool GooglePhotosEnabled() const { return GetParam(); }
-
   void WaitForWallpaperCount(int count) {
     base::RunLoop run_loop;
     base::RepeatingTimer repeating_timer;
@@ -4386,17 +4372,9 @@
                           }));
     run_loop.Run();
   }
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
-INSTANTIATE_TEST_SUITE_P(All,
-                         WallpaperControllerGooglePhotosWallpaperTest,
-                         testing::Bool());
-
-TEST_P(WallpaperControllerGooglePhotosWallpaperTest, SetGooglePhotosWallpaper) {
-  bool feature_enabled = GooglePhotosEnabled();
+TEST_F(WallpaperControllerGooglePhotosWallpaperTest, SetGooglePhotosWallpaper) {
   SimulateUserLogin(kAccountId1);
 
   // First set the wallpaper to an Online one so we can tell for sure if setting
@@ -4428,22 +4406,20 @@
                                      /*preview_mode=*/false, "dedup_key");
 
   controller_->SetGooglePhotosWallpaper(params, base::DoNothing());
-  if (feature_enabled)
-    ++expected_wallpaper_count;
+  ++expected_wallpaper_count;
 
   WaitForWallpaperCount(expected_wallpaper_count);
 
-  EXPECT_EQ(feature_enabled, controller_->GetWallpaperType() ==
-                                 WallpaperType::kOnceGooglePhotos);
+  EXPECT_EQ(controller_->GetWallpaperType(), WallpaperType::kOnceGooglePhotos);
 
   WallpaperInfo wallpaper_info;
   EXPECT_TRUE(
       pref_manager_->GetUserWallpaperInfo(kAccountId1, &wallpaper_info));
   WallpaperInfo expected_wallpaper_info(params);
-  EXPECT_EQ(feature_enabled, wallpaper_info == expected_wallpaper_info);
+  EXPECT_EQ(wallpaper_info, expected_wallpaper_info);
 }
 
-TEST_P(WallpaperControllerGooglePhotosWallpaperTest,
+TEST_F(WallpaperControllerGooglePhotosWallpaperTest,
        SetGooglePhotosWallpaperFails) {
   SimulateUserLogin(kAccountId1);
 
@@ -4486,7 +4462,7 @@
   EXPECT_EQ(wallpaper_info, expected_wallpaper_info);
 }
 
-TEST_P(WallpaperControllerGooglePhotosWallpaperTest,
+TEST_F(WallpaperControllerGooglePhotosWallpaperTest,
        RetryTimerTriggersOnFailedFetchPhotoForStalenessCheck) {
   using base::Time;
 
@@ -4504,16 +4480,11 @@
       controller_->GetUpdateWallpaperTimerForTesting().desired_run_time();
   base::TimeDelta delay = run_time - Time::Now();
 
-  // If the feature is disabled, setting a GooglePhotos wallpaper is a nop.
-  if (GooglePhotosEnabled()) {
-    base::TimeDelta one_day = base::Days(1);
-    // Leave a little wiggle room, as well as account for the hour fuzzing that
-    // we do.
-    EXPECT_GE(delay, one_day - base::Minutes(1));
-    EXPECT_LE(delay, one_day + base::Minutes(61));
-  } else {
-    EXPECT_FALSE(controller_->GetUpdateWallpaperTimerForTesting().IsRunning());
-  }
+  base::TimeDelta one_day = base::Days(1);
+  // Leave a little wiggle room, as well as account for the hour fuzzing that
+  // we do.
+  EXPECT_GE(delay, one_day - base::Minutes(1));
+  EXPECT_LE(delay, one_day + base::Minutes(61));
 
   client_.set_fetch_google_photos_photo_fails(true);
 
@@ -4528,14 +4499,12 @@
 
   // The cache check does not happen when the feature is disabled, since the
   // local `WallpaperInfo` is rejected.
-  if (GooglePhotosEnabled()) {
-    // Leave a little wiggle room.
-    EXPECT_GE(delay, one_hour - base::Minutes(1));
-    EXPECT_LE(delay, one_hour + base::Minutes(1));
-  }
+  // Leave a little wiggle room.
+  EXPECT_GE(delay, one_hour - base::Minutes(1));
+  EXPECT_LE(delay, one_hour + base::Minutes(1));
 }
 
-TEST_P(WallpaperControllerGooglePhotosWallpaperTest,
+TEST_F(WallpaperControllerGooglePhotosWallpaperTest,
        ResetToDefaultForDeletedPhotoOnStalenessCheck) {
   SimulateUserLogin(kAccountId1);
 
@@ -4547,14 +4516,12 @@
   client_.set_google_photo_has_been_deleted(true);
   // Trigger Google Photos wallpaper cache check.
   controller_->OnActiveUserSessionChanged(kAccountId1);
-  if (GooglePhotosEnabled())
-    WaitForWallpaperCount(1);
+  WaitForWallpaperCount(1);
 
-  EXPECT_EQ(GooglePhotosEnabled(),
-            controller_->GetWallpaperType() == WallpaperType::kDefault);
+  EXPECT_EQ(controller_->GetWallpaperType(), WallpaperType::kDefault);
 }
 
-TEST_P(WallpaperControllerGooglePhotosWallpaperTest,
+TEST_F(WallpaperControllerGooglePhotosWallpaperTest,
        GooglePhotosAreCachedOnDisk) {
   SimulateUserLogin(kAccountId1);
 
@@ -4565,17 +4532,17 @@
        WALLPAPER_LAYOUT_STRETCH,
        /*preview_mode=*/false, "dedup_key"},
       google_photos_future.GetCallback());
-  EXPECT_EQ(GooglePhotosEnabled(), google_photos_future.Get());
+  EXPECT_TRUE(google_photos_future.Get());
   RunAllTasksUntilIdle();
 
   base::FilePath saved_wallpaper = online_wallpaper_dir_.GetPath()
                                        .Append("google_photos/")
                                        .Append(kAccountId1.GetAccountIdKey())
                                        .Append(kFakeGooglePhotosPhotoId);
-  ASSERT_EQ(GooglePhotosEnabled(), base::PathExists(saved_wallpaper));
+  ASSERT_TRUE(base::PathExists(saved_wallpaper));
 }
 
-TEST_P(WallpaperControllerGooglePhotosWallpaperTest,
+TEST_F(WallpaperControllerGooglePhotosWallpaperTest,
        GooglePhotosAreCachedInMemory) {
   SimulateUserLogin(kAccountId1);
 
@@ -4591,20 +4558,19 @@
        WALLPAPER_LAYOUT_STRETCH,
        /*preview_mode=*/false, "dedup_key"},
       google_photos_future.GetCallback());
-  EXPECT_EQ(GooglePhotosEnabled(), google_photos_future.Get());
+  EXPECT_TRUE(google_photos_future.Get());
   RunAllTasksUntilIdle();
 
   // We store an empty path for Google Photos wallpapers in the in-memory cache
   // because storing the real path correctly would require updating the cache
   // after the asynchronous save operation, and we have no use for it anyway.
-  EXPECT_EQ(GooglePhotosEnabled(),
-            controller_->GetPathFromCache(kAccountId1, &path));
+  EXPECT_TRUE(controller_->GetPathFromCache(kAccountId1, &path));
   EXPECT_TRUE(path.empty());
-  EXPECT_EQ(GooglePhotosEnabled(),
-            controller_->GetWallpaperFromCache(kAccountId1, &cached_wallpaper));
+  EXPECT_TRUE(
+      controller_->GetWallpaperFromCache(kAccountId1, &cached_wallpaper));
 }
 
-TEST_P(WallpaperControllerGooglePhotosWallpaperTest,
+TEST_F(WallpaperControllerGooglePhotosWallpaperTest,
        GooglePhotosAreReadFromCache) {
   SimulateUserLogin(kAccountId1);
 
@@ -4616,7 +4582,7 @@
                                       /*preview_mode=*/false, "dedup_key"});
   controller_->SetGooglePhotosWallpaper(params,
                                         google_photos_future.GetCallback());
-  EXPECT_EQ(GooglePhotosEnabled(), google_photos_future.Get());
+  EXPECT_TRUE(google_photos_future.Get());
   RunAllTasksUntilIdle();
 
   controller_->ShowUserWallpaper(kAccountId1);
@@ -4624,16 +4590,14 @@
   // When Google Photos is disabled, the wallpaper will not be in disk cache,
   // so it will attempt to read from disk, fail to find it, and then reset to
   // the default wallpaper.
-  const size_t expected_decodes = GooglePhotosEnabled() ? 0 : 1;
-  const WallpaperType expected_type = GooglePhotosEnabled()
-                                          ? WallpaperType::kOnceGooglePhotos
-                                          : WallpaperType::kDefault;
+  const size_t expected_decodes = 0;
+  const WallpaperType expected_type = WallpaperType::kOnceGooglePhotos;
 
   EXPECT_EQ(expected_decodes, GetDecodeFilePaths().size());
   EXPECT_EQ(expected_type, controller_->GetWallpaperType());
 }
 
-TEST_P(WallpaperControllerGooglePhotosWallpaperTest, ConfirmPreviewWallpaper) {
+TEST_F(WallpaperControllerGooglePhotosWallpaperTest, ConfirmPreviewWallpaper) {
   // Verify the user starts with a default wallpaper and the user wallpaper info
   // is initialized with default values.
   SimulateUserLogin(kAccountId1);
@@ -4665,42 +4629,36 @@
       {kAccountId1, photo_id, /*daily_refresh_enabled=*/false, layout,
        /*preview_mode=*/true, "dedup_key"},
       google_photos_future.GetCallback());
-  EXPECT_EQ(google_photos_future.Get(), GooglePhotosEnabled());
+  EXPECT_TRUE(google_photos_future.Get());
   RunAllTasksUntilIdle();
-  EXPECT_EQ(GetWallpaperCount(), GooglePhotosEnabled() ? 1 : 0);
-  EXPECT_EQ(controller_->GetWallpaperType(),
-            GooglePhotosEnabled() ? WallpaperType::kOnceGooglePhotos
-                                  : WallpaperType::kDefault);
+  EXPECT_EQ(GetWallpaperCount(), 1);
+  EXPECT_EQ(controller_->GetWallpaperType(), WallpaperType::kOnceGooglePhotos);
 
   // Verify that the user wallpaper info remains unchanged during the preview.
   EXPECT_TRUE(
       pref_manager_->GetUserWallpaperInfo(kAccountId1, &user_wallpaper_info));
   EXPECT_EQ(user_wallpaper_info, default_wallpaper_info);
-  histogram_tester().ExpectTotalCount("Ash.Wallpaper.Preview.Show",
-                                      GooglePhotosEnabled() ? 1 : 0);
+  histogram_tester().ExpectTotalCount("Ash.Wallpaper.Preview.Show", 1);
 
-  if (GooglePhotosEnabled()) {
-    // Now confirm the preview wallpaper, verify that there's no wallpaper
-    // change because the wallpaper is already shown.
-    ClearWallpaperCount();
-    controller_->ConfirmPreviewWallpaper();
-    RunAllTasksUntilIdle();
-    EXPECT_EQ(GetWallpaperCount(), 0);
-    EXPECT_EQ(controller_->GetWallpaperType(),
-              WallpaperType::kOnceGooglePhotos);
+  // Now confirm the preview wallpaper, verify that there's no wallpaper
+  // change because the wallpaper is already shown.
+  ClearWallpaperCount();
+  controller_->ConfirmPreviewWallpaper();
+  RunAllTasksUntilIdle();
+  EXPECT_EQ(GetWallpaperCount(), 0);
+  EXPECT_EQ(controller_->GetWallpaperType(), WallpaperType::kOnceGooglePhotos);
 
-    // Verify that the user wallpaper info is now updated to the Google Photos
-    // wallpaper info.
-    WallpaperInfo google_photos_wallpaper_info(
-        photo_id, layout, WallpaperType::kOnceGooglePhotos,
-        base::Time::Now().LocalMidnight());
-    EXPECT_TRUE(
-        pref_manager_->GetUserWallpaperInfo(kAccountId1, &user_wallpaper_info));
-    EXPECT_EQ(user_wallpaper_info, google_photos_wallpaper_info);
-  }
+  // Verify that the user wallpaper info is now updated to the Google Photos
+  // wallpaper info.
+  WallpaperInfo google_photos_wallpaper_info(photo_id, layout,
+                                             WallpaperType::kOnceGooglePhotos,
+                                             base::Time::Now().LocalMidnight());
+  EXPECT_TRUE(
+      pref_manager_->GetUserWallpaperInfo(kAccountId1, &user_wallpaper_info));
+  EXPECT_EQ(user_wallpaper_info, google_photos_wallpaper_info);
 }
 
-TEST_P(WallpaperControllerGooglePhotosWallpaperTest, CancelPreviewWallpaper) {
+TEST_F(WallpaperControllerGooglePhotosWallpaperTest, CancelPreviewWallpaper) {
   // Verify the user starts with a default wallpaper and the user wallpaper info
   // is initialized with default values.
   SimulateUserLogin(kAccountId1);
@@ -4731,33 +4689,28 @@
       {kAccountId1, photo_id, /*daily_refresh_enabled=*/false,
        WALLPAPER_LAYOUT_STRETCH, /*preview_mode=*/true, "dedup_key"},
       google_photos_future.GetCallback());
-  EXPECT_EQ(google_photos_future.Get(), GooglePhotosEnabled());
+  EXPECT_TRUE(google_photos_future.Get());
   RunAllTasksUntilIdle();
-  EXPECT_EQ(GetWallpaperCount(), GooglePhotosEnabled() ? 1 : 0);
-  EXPECT_EQ(controller_->GetWallpaperType(),
-            GooglePhotosEnabled() ? WallpaperType::kOnceGooglePhotos
-                                  : WallpaperType::kDefault);
+  EXPECT_EQ(GetWallpaperCount(), 1);
+  EXPECT_EQ(controller_->GetWallpaperType(), WallpaperType::kOnceGooglePhotos);
 
   // Verify that the user wallpaper info remains unchanged during the preview.
   EXPECT_TRUE(
       pref_manager_->GetUserWallpaperInfo(kAccountId1, &user_wallpaper_info));
   EXPECT_EQ(user_wallpaper_info, default_wallpaper_info);
-  histogram_tester().ExpectTotalCount("Ash.Wallpaper.Preview.Show",
-                                      GooglePhotosEnabled() ? 1 : 0);
+  histogram_tester().ExpectTotalCount("Ash.Wallpaper.Preview.Show", 1);
 
-  if (GooglePhotosEnabled()) {
-    // Now cancel the preview. Verify the wallpaper changes back to the default
-    // and the user wallpaper info remains unchanged.
-    ClearWallpaperCount();
-    controller_->CancelPreviewWallpaper();
-    RunAllTasksUntilIdle();
-    EXPECT_EQ(GetWallpaperCount(), 1);
-    EXPECT_EQ(controller_->GetWallpaperType(), WallpaperType::kDefault);
-    EXPECT_EQ(user_wallpaper_info, default_wallpaper_info);
-  }
+  // Now cancel the preview. Verify the wallpaper changes back to the default
+  // and the user wallpaper info remains unchanged.
+  ClearWallpaperCount();
+  controller_->CancelPreviewWallpaper();
+  RunAllTasksUntilIdle();
+  EXPECT_EQ(GetWallpaperCount(), 1);
+  EXPECT_EQ(controller_->GetWallpaperType(), WallpaperType::kDefault);
+  EXPECT_EQ(user_wallpaper_info, default_wallpaper_info);
 }
 
-TEST_P(WallpaperControllerGooglePhotosWallpaperTest,
+TEST_F(WallpaperControllerGooglePhotosWallpaperTest,
        WallpaperSyncedDuringPreview) {
   // Verify the user starts with a default wallpaper and the user wallpaper info
   // is initialized with default values.
@@ -4790,60 +4743,54 @@
       {kAccountId1, photo_id, /*daily_refresh_enabled=*/false, layout,
        /*preview_mode=*/true, "dedup_key"},
       google_photos_future.GetCallback());
-  EXPECT_EQ(google_photos_future.Get(), GooglePhotosEnabled());
+  EXPECT_TRUE(google_photos_future.Get());
   RunAllTasksUntilIdle();
-  EXPECT_EQ(GetWallpaperCount(), GooglePhotosEnabled() ? 1 : 0);
-  EXPECT_EQ(controller_->GetWallpaperType(),
-            GooglePhotosEnabled() ? WallpaperType::kOnceGooglePhotos
-                                  : WallpaperType::kDefault);
+  EXPECT_EQ(GetWallpaperCount(), 1);
+  EXPECT_EQ(controller_->GetWallpaperType(), WallpaperType::kOnceGooglePhotos);
 
   // Verify that the user wallpaper info remains unchanged during the preview.
   EXPECT_TRUE(
       pref_manager_->GetUserWallpaperInfo(kAccountId1, &user_wallpaper_info));
   EXPECT_EQ(user_wallpaper_info, default_wallpaper_info);
-  histogram_tester().ExpectTotalCount("Ash.Wallpaper.Preview.Show",
-                                      GooglePhotosEnabled() ? 1 : 0);
+  histogram_tester().ExpectTotalCount("Ash.Wallpaper.Preview.Show", 1);
 
   // Now set a custom wallpaper for the user and disable preview (this happens
   // if a custom wallpaper set on another device is being synced). Verify
   // there's no wallpaper change since preview mode shouldn't be interrupted.
-  if (GooglePhotosEnabled()) {
-    gfx::ImageSkia synced_custom_wallpaper =
-        CreateImage(640, 480, kWallpaperColor);
-    ClearWallpaperCount();
-    controller_->SetDecodedCustomWallpaper(
-        kAccountId1, kFileName1, layout,
-        /*preview_mode=*/false, base::DoNothing(),
-        /*file_path=*/"", synced_custom_wallpaper);
-    RunAllTasksUntilIdle();
-    EXPECT_EQ(GetWallpaperCount(), 0);
-    EXPECT_EQ(controller_->GetWallpaperType(),
-              WallpaperType::kOnceGooglePhotos);
+  gfx::ImageSkia synced_custom_wallpaper =
+      CreateImage(640, 480, kWallpaperColor);
+  ClearWallpaperCount();
+  controller_->SetDecodedCustomWallpaper(
+      kAccountId1, kFileName1, layout,
+      /*preview_mode=*/false, base::DoNothing(),
+      /*file_path=*/"", synced_custom_wallpaper);
+  RunAllTasksUntilIdle();
+  EXPECT_EQ(GetWallpaperCount(), 0);
+  EXPECT_EQ(controller_->GetWallpaperType(), WallpaperType::kOnceGooglePhotos);
 
-    // However, the user wallpaper info should already be updated to the new
-    // info.
-    WallpaperInfo synced_custom_wallpaper_info(
-        base::FilePath(kWallpaperFilesId1).Append(kFileName1).value(), layout,
-        WallpaperType::kCustomized, base::Time::Now().LocalMidnight());
-    EXPECT_TRUE(
-        pref_manager_->GetUserWallpaperInfo(kAccountId1, &user_wallpaper_info));
-    EXPECT_EQ(user_wallpaper_info, synced_custom_wallpaper_info);
+  // However, the user wallpaper info should already be updated to the new
+  // info.
+  WallpaperInfo synced_custom_wallpaper_info(
+      base::FilePath(kWallpaperFilesId1).Append(kFileName1).value(), layout,
+      WallpaperType::kCustomized, base::Time::Now().LocalMidnight());
+  EXPECT_TRUE(
+      pref_manager_->GetUserWallpaperInfo(kAccountId1, &user_wallpaper_info));
+  EXPECT_EQ(user_wallpaper_info, synced_custom_wallpaper_info);
 
-    // Now cancel the preview. Verify the synced custom wallpaper is shown
-    // instead of the initial default wallpaper, and the user wallpaper info is
-    // still correct.
-    ClearWallpaperCount();
-    controller_->CancelPreviewWallpaper();
-    RunAllTasksUntilIdle();
-    EXPECT_EQ(GetWallpaperCount(), 1);
-    EXPECT_EQ(controller_->GetWallpaperType(), WallpaperType::kCustomized);
-    EXPECT_TRUE(
-        pref_manager_->GetUserWallpaperInfo(kAccountId1, &user_wallpaper_info));
-    EXPECT_EQ(user_wallpaper_info, synced_custom_wallpaper_info);
-  }
+  // Now cancel the preview. Verify the synced custom wallpaper is shown
+  // instead of the initial default wallpaper, and the user wallpaper info is
+  // still correct.
+  ClearWallpaperCount();
+  controller_->CancelPreviewWallpaper();
+  RunAllTasksUntilIdle();
+  EXPECT_EQ(GetWallpaperCount(), 1);
+  EXPECT_EQ(controller_->GetWallpaperType(), WallpaperType::kCustomized);
+  EXPECT_TRUE(
+      pref_manager_->GetUserWallpaperInfo(kAccountId1, &user_wallpaper_info));
+  EXPECT_EQ(user_wallpaper_info, synced_custom_wallpaper_info);
 }
 
-TEST_P(WallpaperControllerGooglePhotosWallpaperTest,
+TEST_F(WallpaperControllerGooglePhotosWallpaperTest,
        UpdateGooglePhotosDailyRefreshWallpaper) {
   // The `TestWallpaperControllerClient` sends back the reversed
   // `collection_id` when asked to fetch a daily photo.
@@ -4863,16 +4810,12 @@
   RunAllTasksUntilIdle();
 
   WallpaperInfo expected_info;
-  bool success =
-      pref_manager_->GetUserWallpaperInfo(kAccountId1, &expected_info);
-  EXPECT_EQ(success, GooglePhotosEnabled());
-  if (success) {
-    EXPECT_EQ(expected_photo_id, expected_info.location);
-    EXPECT_EQ(kFakeGooglePhotosAlbumId, expected_info.collection_id);
-  }
+  EXPECT_TRUE(pref_manager_->GetUserWallpaperInfo(kAccountId1, &expected_info));
+  EXPECT_EQ(expected_photo_id, expected_info.location);
+  EXPECT_EQ(kFakeGooglePhotosAlbumId, expected_info.collection_id);
 }
 
-TEST_P(WallpaperControllerGooglePhotosWallpaperTest,
+TEST_F(WallpaperControllerGooglePhotosWallpaperTest,
        DailyRefreshTimerStartsForDailyGooglePhotos) {
   SimulateUserLogin(kAccountId1);
 
@@ -4892,15 +4835,11 @@
   base::TimeDelta update_time =
       (base::Time::Now() + base::Days(1)).ToDeltaSinceWindowsEpoch();
 
-  if (GooglePhotosEnabled()) {
-    EXPECT_GE(run_time, update_time - base::Minutes(1));
-    EXPECT_LE(run_time, update_time + base::Minutes(61));
-  } else {
-    EXPECT_FALSE(timer.IsRunning());
-  }
+  EXPECT_GE(run_time, update_time - base::Minutes(1));
+  EXPECT_LE(run_time, update_time + base::Minutes(61));
 }
 
-TEST_P(WallpaperControllerGooglePhotosWallpaperTest,
+TEST_F(WallpaperControllerGooglePhotosWallpaperTest,
        DailyRefreshRetryTimerStartsOnFailedFetch) {
   SimulateUserLogin(kAccountId1);
 
@@ -4922,15 +4861,11 @@
   base::TimeDelta update_time =
       (base::Time::Now() + base::Hours(1)).ToDeltaSinceWindowsEpoch();
 
-  if (GooglePhotosEnabled()) {
-    EXPECT_GE(run_time, update_time - base::Minutes(1));
-    EXPECT_LE(run_time, update_time + base::Minutes(1));
-  } else {
-    EXPECT_FALSE(controller_->GetUpdateWallpaperTimerForTesting().IsRunning());
-  }
+  EXPECT_GE(run_time, update_time - base::Minutes(1));
+  EXPECT_LE(run_time, update_time + base::Minutes(1));
 }
 
-TEST_P(WallpaperControllerGooglePhotosWallpaperTest,
+TEST_F(WallpaperControllerGooglePhotosWallpaperTest,
        EmptyDailyGooglePhotosAlbumsDoNothing) {
   SimulateUserLogin(kAccountId1);
 
@@ -4960,7 +4895,7 @@
   EXPECT_EQ(online_info, current_info);
 }
 
-TEST_P(WallpaperControllerGooglePhotosWallpaperTest,
+TEST_F(WallpaperControllerGooglePhotosWallpaperTest,
        ResetToDefaultForDeletedDailyGooglePhotosAlbums) {
   SimulateUserLogin(kAccountId1);
 
@@ -4970,14 +4905,13 @@
        WallpaperLayout::WALLPAPER_LAYOUT_CENTER_CROPPED,
        /*preview_mode=*/false, /*dedup_key=*/absl::nullopt},
       google_photos_future.GetCallback());
-  EXPECT_EQ(GooglePhotosEnabled(), google_photos_future.Get());
+  EXPECT_TRUE(google_photos_future.Get());
   RunAllTasksUntilIdle();
 
   WallpaperInfo current_info;
   pref_manager_->GetUserWallpaperInfo(kAccountId1, &current_info);
 
-  EXPECT_EQ(GooglePhotosEnabled(),
-            WallpaperType::kDailyGooglePhotos == current_info.type);
+  EXPECT_EQ(WallpaperType::kDailyGooglePhotos, current_info.type);
 
   // This makes the test fetch in `client_` return a null photo, but a
   // successful call, which is the sign for a deleted or empty album.
@@ -4988,11 +4922,10 @@
 
   pref_manager_->GetUserWallpaperInfo(kAccountId1, &current_info);
 
-  EXPECT_EQ(GooglePhotosEnabled(),
-            WallpaperType::kDefault == current_info.type);
+  EXPECT_EQ(WallpaperType::kDefault, current_info.type);
 }
 
-TEST_P(WallpaperControllerGooglePhotosWallpaperTest,
+TEST_F(WallpaperControllerGooglePhotosWallpaperTest,
        DailyGooglePhotosAreCached) {
   SimulateUserLogin(kAccountId1);
   // The `TestWallpaperControllerClient` sends back the reversed
@@ -5006,23 +4939,21 @@
        WallpaperLayout::WALLPAPER_LAYOUT_CENTER_CROPPED,
        /*preview_mode=*/false, /*dedup_key=*/absl::nullopt},
       google_photos_future.GetCallback());
-  EXPECT_EQ(GooglePhotosEnabled(), google_photos_future.Get());
+  EXPECT_TRUE(google_photos_future.Get());
   RunAllTasksUntilIdle();
 
   base::FilePath saved_wallpaper = online_wallpaper_dir_.GetPath()
                                        .Append("google_photos/")
                                        .Append(kAccountId1.GetAccountIdKey())
                                        .Append(expected_photo_id);
-  ASSERT_EQ(GooglePhotosEnabled(), base::PathExists(saved_wallpaper));
+  ASSERT_TRUE(base::PathExists(saved_wallpaper));
 }
 
-TEST_P(WallpaperControllerGooglePhotosWallpaperTest,
+TEST_F(WallpaperControllerGooglePhotosWallpaperTest,
        ResetToDefaultWhenLoadingInvalidWallpaper) {
   SimulateUserLogin(kAccountId1);
 
-  const WallpaperType type = GooglePhotosEnabled()
-                                 ? WallpaperType::kCount
-                                 : WallpaperType::kOnceGooglePhotos;
+  const WallpaperType type = WallpaperType::kCount;
 
   WallpaperInfo info = {kFakeGooglePhotosPhotoId, WALLPAPER_LAYOUT_CENTER, type,
                         base::Time::Now()};
@@ -5033,7 +4964,7 @@
   EXPECT_EQ(controller_->GetWallpaperType(), WallpaperType::kDefault);
 }
 
-TEST_P(WallpaperControllerGooglePhotosWallpaperTest,
+TEST_F(WallpaperControllerGooglePhotosWallpaperTest,
        SetGooglePhotosDailyRefreshAlbumId_UpdatesDailyRefreshTimer) {
   using base::Time;
 
@@ -5053,19 +4984,17 @@
   pref_manager_->GetUserWallpaperInfo(kAccountId1, &actual);
   // Type should be `WallpaperType::kDailyGooglePhotos` now, and collection_id
   // should be updated.
-  if (GooglePhotosEnabled()) {
-    EXPECT_EQ(expected, actual);
-    EXPECT_EQ(album_id,
-              controller_->GetGooglePhotosDailyRefreshAlbumId(kAccountId1));
-    Time run_time =
-        controller_->GetUpdateWallpaperTimerForTesting().desired_run_time();
-    base::TimeDelta delay = run_time - Time::Now();
-    base::TimeDelta one_day = base::Days(1);
-    // Leave a little wiggle room, as well as account for the hour fuzzing that
-    // we do.
-    EXPECT_GE(delay, one_day - base::Minutes(1));
-    EXPECT_LE(delay, one_day + base::Minutes(61));
-  }
+  EXPECT_EQ(expected, actual);
+  EXPECT_EQ(album_id,
+            controller_->GetGooglePhotosDailyRefreshAlbumId(kAccountId1));
+  Time run_time =
+      controller_->GetUpdateWallpaperTimerForTesting().desired_run_time();
+  base::TimeDelta delay = run_time - Time::Now();
+  base::TimeDelta one_day = base::Days(1);
+  // Leave a little wiggle room, as well as account for the hour fuzzing that
+  // we do.
+  EXPECT_GE(delay, one_day - base::Minutes(1));
+  EXPECT_LE(delay, one_day + base::Minutes(61));
 }
 
 }  // namespace ash
diff --git a/ash/wallpaper/wallpaper_pref_manager.cc b/ash/wallpaper/wallpaper_pref_manager.cc
index dd9065c..65f20c34 100644
--- a/ash/wallpaper/wallpaper_pref_manager.cc
+++ b/ash/wallpaper/wallpaper_pref_manager.cc
@@ -141,11 +141,6 @@
     return false;
 
   WallpaperType wallpaper_type = static_cast<WallpaperType>(type.value());
-  if (!features::IsWallpaperGooglePhotosIntegrationEnabled() &&
-      (wallpaper_type == WallpaperType::kOnceGooglePhotos ||
-       wallpaper_type == WallpaperType::kDailyGooglePhotos)) {
-    return false;
-  }
   info->type = wallpaper_type;
 
   int64_t date_val;
diff --git a/ash/webui/files_internals/files_internals_page_handler.cc b/ash/webui/files_internals/files_internals_page_handler.cc
index ee7dfd5..1911dd2 100644
--- a/ash/webui/files_internals/files_internals_page_handler.cc
+++ b/ash/webui/files_internals/files_internals_page_handler.cc
@@ -26,4 +26,14 @@
   files_internals_ui_->delegate()->SetSmbfsEnableVerboseLogging(enabled);
 }
 
+void FilesInternalsPageHandler::GetOfficeSetupComplete(
+    GetOfficeSetupCompleteCallback callback) {
+  std::move(callback).Run(
+      files_internals_ui_->delegate()->GetOfficeSetupComplete());
+}
+
+void FilesInternalsPageHandler::SetOfficeSetupComplete(bool complete) {
+  files_internals_ui_->delegate()->SetOfficeSetupComplete(complete);
+}
+
 }  // namespace ash
diff --git a/ash/webui/files_internals/files_internals_page_handler.h b/ash/webui/files_internals/files_internals_page_handler.h
index 7727672..a07517db 100644
--- a/ash/webui/files_internals/files_internals_page_handler.h
+++ b/ash/webui/files_internals/files_internals_page_handler.h
@@ -29,6 +29,8 @@
   void GetSmbfsEnableVerboseLogging(
       GetSmbfsEnableVerboseLoggingCallback callback) override;
   void SetSmbfsEnableVerboseLogging(bool enabled) override;
+  void GetOfficeSetupComplete(GetOfficeSetupCompleteCallback callback) override;
+  void SetOfficeSetupComplete(bool complete) override;
 
  private:
   raw_ptr<FilesInternalsUI> files_internals_ui_;  // Owns |this|.
diff --git a/ash/webui/files_internals/files_internals_ui_delegate.h b/ash/webui/files_internals/files_internals_ui_delegate.h
index d4c76f2..686fcba7 100644
--- a/ash/webui/files_internals/files_internals_ui_delegate.h
+++ b/ash/webui/files_internals/files_internals_ui_delegate.h
@@ -18,6 +18,9 @@
 
   virtual bool GetSmbfsEnableVerboseLogging() const = 0;
   virtual void SetSmbfsEnableVerboseLogging(bool enabled) = 0;
+
+  virtual bool GetOfficeSetupComplete() const = 0;
+  virtual void SetOfficeSetupComplete(bool complete) = 0;
 };
 
 }  // namespace ash
diff --git a/ash/webui/files_internals/mojom/files_internals.mojom b/ash/webui/files_internals/mojom/files_internals.mojom
index 3140ee5..7df45c8a 100644
--- a/ash/webui/files_internals/mojom/files_internals.mojom
+++ b/ash/webui/files_internals/mojom/files_internals.mojom
@@ -10,4 +10,9 @@
   GetSmbfsEnableVerboseLogging() => (bool enabled);
   // Sets the smbfs.enable_verbose_logging pref.
   SetSmbfsEnableVerboseLogging(bool enabled);
+
+  // Gets the filebrowser.office.setup_complete pref.
+  GetOfficeSetupComplete() => (bool complete);
+  // Sets the filebrowser.office.setup_complete pref.
+  SetOfficeSetupComplete(bool complete);
 };
diff --git a/ash/webui/files_internals/resources/index.html b/ash/webui/files_internals/resources/index.html
index 09d2b401..e1f192167 100644
--- a/ash/webui/files_internals/resources/index.html
+++ b/ash/webui/files_internals/resources/index.html
@@ -31,5 +31,10 @@
     this option.</i></p>
 </span>
 </div>
+
+<h2>Office file handlers</h2>
+<p>Office setup complete?: <span id="office-setup-complete-status"></span></p>
+<button id="clear-office-setup-complete">Clear Office setup complete</button>
+
 </body>
 </html>
diff --git a/ash/webui/files_internals/resources/index.js b/ash/webui/files_internals/resources/index.js
index 77b5163..29ec146 100644
--- a/ash/webui/files_internals/resources/index.js
+++ b/ash/webui/files_internals/resources/index.js
@@ -7,10 +7,23 @@
 const pageHandler = PageHandler.getRemote();
 
 document.addEventListener('DOMContentLoaded', async () => {
+  // SMB
   const verboseElem = document.getElementById('smb-verbose-logging-toggle');
   verboseElem.checked =
       (await pageHandler.getSmbfsEnableVerboseLogging()).enabled;
   verboseElem.addEventListener('change', (e) => {
     pageHandler.setSmbfsEnableVerboseLogging(e.target.checked);
   });
+
+  // Office file handlers
+  const clearSetupButton =
+      document.getElementById('clear-office-setup-complete');
+  clearSetupButton.addEventListener('click', () => {
+    pageHandler.setOfficeSetupComplete(false);
+  });
+  const officeSetupStatus =
+      document.getElementById('office-setup-complete-status');
+  const officeSetupComplete =
+      (await pageHandler.getOfficeSetupComplete()).complete;
+  officeSetupStatus.innerText = officeSetupComplete ? 'Yes' : 'No';
 });
diff --git a/ash/webui/personalization_app/personalization_app_ui.cc b/ash/webui/personalization_app/personalization_app_ui.cc
index 8abb622..f2de6198 100644
--- a/ash/webui/personalization_app/personalization_app_ui.cc
+++ b/ash/webui/personalization_app/personalization_app_ui.cc
@@ -352,8 +352,7 @@
                      features::IsWallpaperFullScreenPreviewEnabled());
 
   source->AddBoolean("isGooglePhotosIntegrationEnabled",
-                     features::IsWallpaperGooglePhotosIntegrationEnabled() &&
-                         wallpaper_provider_->IsEligibleForGooglePhotos());
+                     wallpaper_provider_->IsEligibleForGooglePhotos());
 
   source->AddBoolean("isDarkLightModeEnabled",
                      features::IsDarkLightModeEnabled());
diff --git a/ash/webui/personalization_app/resources/css/common.css b/ash/webui/personalization_app/resources/css/common.css
index b30d2b6..5a90693 100644
--- a/ash/webui/personalization_app/resources/css/common.css
+++ b/ash/webui/personalization_app/resources/css/common.css
@@ -55,16 +55,10 @@
 
 .photo-container {
   box-sizing: border-box;
-  height: calc(
-    var(--personalization-app-grid-item-height) +
-    var(--personalization-app-grid-item-spacing));
+  height: 100%;
   overflow: hidden;
   padding: calc(var(--personalization-app-grid-item-spacing) / 2);
-  /* Media queries in trusted and untrusted code will resize to 25% at
-   * correct widths.  Subtract 0.34px to fix subpixel rounding issues with
-   * iron-list. This makes sure all photo containers on a row add up to at
-   * least 1px smaller than the parent width.*/
-  width: calc(100% / 3 - 0.34px);
+  width: 100%;
 }
 
 .photo-container:focus-visible {
@@ -114,9 +108,7 @@
 
 .photo-inner-container:focus-visible,
 .photo-loading-placeholder:focus-visible {
-  border: 2px solid var(--cros-focus-ring-color);
-  border-radius: 14px;
-  outline: none;
+  outline: 2px solid var(--cros-focus-ring-color);
 }
 
 .photo-images-container {
@@ -200,12 +192,6 @@
   border: 0;
 }
 
-.photo-inner-container:focus-visible:not([aria-selected='true'])
-.photo-images-container {
-  height: calc(100% - 4px);
-  width: calc(100% - 4px);
-}
-
 cr-button[aria-pressed=true],
 cr-button[aria-selected=true] {
   background-color: var(--cros-highlight-color);
diff --git a/ash/webui/personalization_app/resources/css/wallpaper.css b/ash/webui/personalization_app/resources/css/wallpaper.css
index ca37ef63..7f270dc 100644
--- a/ash/webui/personalization_app/resources/css/wallpaper.css
+++ b/ash/webui/personalization_app/resources/css/wallpaper.css
@@ -9,17 +9,6 @@
  * import=chrome://resources/polymer/v3_0/paper-styles/color.js
  * #css_wrapper_metadata_end */
 
-/* Use !important to make sure there are no css ordering issues.
- * Subtract 0.25px to fix subpixel rounding issues with iron-list. This
- * makes sure all photo containers on a row add up to at least 1px smaller
- * than the parent width.*/
-
-@media (min-width: 720px) {
-  .photo-container {
-    width: calc(25% - 0.25px) !important;
-  }
-}
-
 main {
   height: 100%;
   width: 100%;
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_collections_element.html b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_collections_element.html
index 474cfbff..0dfe2bc 100644
--- a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_collections_element.html
+++ b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_collections_element.html
@@ -125,9 +125,8 @@
   }
 
   .photo-gradient-mask {
-    background: linear-gradient(
-      rgba(var(--google-grey-900-rgb), 0),
-      rgba(var(--google-grey-900-rgb), 55%));
+    background: linear-gradient(rgba(var(--google-grey-900-rgb), 0),
+        rgba(var(--google-grey-900-rgb), 55%));
     border-radius: 0 0 12px 12px;
     height: 50%;
     left: 0;
@@ -142,6 +141,26 @@
     display: none;
   }
 
+  .outer-container {
+    height: calc(var(--personalization-app-grid-item-height) +
+      var(--personalization-app-grid-item-spacing));
+    /* Media queries in trusted and untrusted code will resize to 25% at
+     * correct widths.  Subtract 0.34px to fix subpixel rounding issues with
+     * iron-list. This makes sure all photo containers on a row add up to at
+     * least 1px smaller than the parent width.*/
+    width: calc(100% / 3 - 0.34px);
+  }
+
+  @media(min-width: 720px) {
+    .outer-container {
+      width: calc(100% / 4 - 0.25px);
+    }
+  }
+
+  wallpaper-grid-item {
+    --wallpaper-grid-item-width: 100%;
+  }
+
 </style>
 <template is="dom-if" if="[[hasError_]]">
   <wallpaper-error></wallpaper-error>
@@ -152,67 +171,87 @@
       items="[[tiles_]]"
       role="listbox">
     <template>
-      <div class="photo-container">
+      <div class="outer-container">
         <template is="dom-if" if="[[isLoadingTile_(item)]]" restamp>
-          <div aria-disabled="true"
-              aria-label="$i18n{ariaLabelLoading}"
-              aria-posinset$="[[getAriaIndex_(index)]]"
-              class="photo-inner-container placeholder"
-              role="option"
-              style$="[[getLoadingPlaceholderAnimationDelay_(index)]]"
-              tabindex$="[[tabIndex]]">
+          <div class="photo-container">
+            <div aria-disabled="true"
+                aria-label="$i18n{ariaLabelLoading}"
+                aria-posinset$="[[getAriaIndex_(index)]]"
+                class="photo-inner-container placeholder"
+                role="option"
+                style$="[[getLoadingPlaceholderAnimationDelay_(index)]]"
+                tabindex$="[[tabIndex]]">
+            </div>
           </div>
         </template>
         <template is="dom-if" if="[[isGooglePhotosTile_(item)]]">
-          <div aria-disabled$="[[getAriaDisabled_(item)]]"
-              aria-posinset$="[[getAriaIndex_(index)]]"
-              class="photo-inner-container google-photos"
-              on-click="onCollectionSelected_"
-              on-keypress="onCollectionSelected_"
-              role="option"
-              tabindex$="[[tabIndex]]">
-            <div class="photo-images-container photo-images-container-0">
-              <div class="photo-images-border"></div>
-              <img src="//personalization/images/google_photos.svg"
-                  aria-hidden="true">
+          <div class="photo-container">
+            <div aria-disabled$="[[getAriaDisabled_(item)]]"
+                aria-posinset$="[[getAriaIndex_(index)]]"
+                class="photo-inner-container google-photos"
+                on-click="onCollectionSelected_"
+                on-keypress="onCollectionSelected_"
+                role="option"
+                tabindex$="[[tabIndex]]">
+              <div class="photo-images-container photo-images-container-0">
+                <div class="photo-images-border"></div>
+                <img src="//personalization/images/google_photos.svg"
+                    aria-hidden="true">
+              </div>
+              <div class="photo-text-container">
+                <iron-icon icon="personalization:managed"
+                    title$="$i18n{managedSetting}">
+                </iron-icon>
+                <p title$="[[item.name]]">[[item.name]]</p>
+              </div>
+              <div class="photo-gradient-mask"></div>
             </div>
-            <div class="photo-text-container">
-              <iron-icon icon="personalization:managed"
-                  title$="$i18n{managedSetting}">
-              </iron-icon>
-              <p title$="[[item.name]]">[[item.name]]</p>
-            </div>
-            <div class="photo-gradient-mask"></div>
           </div>
         </template>
-        <template is="dom-if" if="[[isLocalOrOnlineTile_(item)]]">
-          <div aria-disabled$="[[getAriaDisabled_(item)]]"
+        <template is="dom-if" if="[[isLocalTile_(item)]]">
+          <wallpaper-grid-item
               aria-posinset$="[[getAriaIndex_(index)]]"
-              class$="[[getClassForTile_(item)]]"
-              on-click="onCollectionSelected_"
-              on-keypress="onCollectionSelected_"
+              collage
+              disabled="[[!isSelectableTile_(item)]]"
+              index="[[index]]"
+              on-wallpaper-grid-item-selected="onCollectionSelected_"
+              primary-text="[[item.name]]"
               role="option"
+              secondary-text="[[item.count]]"
+              src="[[item.preview]]"
               tabindex$="[[tabIndex]]">
-            <div class$="[[getClassForImagesContainer_(item)]]">
-              <div class="photo-images-border"></div>
-              <template is="dom-repeat" items="[[item.preview]]" as="preview">
-                <img aria-hidden="true"
-                    auto-src="[[preview.url]]"
-                    class$="[[getClassForImg_(index, item)]]"
-                    clear-src
-                    data-collection-id$="[[item.id]]"
-                    is="cr-auto-img"
-                    on-error="onImgLoad_"
-                    on-load="onImgLoad_">
-              </template>
-            </div>
-            <div class="photo-text-container"
-                hidden$="[[isPhotoTextHidden_(item, loadedCollectionIdPhotos_)]]">
-              <p title$="[[item.name]]">[[item.name]]</p>
-              <p title$="[[item.count]]">[[item.count]]</p>
-            </div>
-            <div class="photo-gradient-mask"
-                hidden$="[[isPhotoTextHidden_(item, loadedCollectionIdPhotos_)]]">
+          </wallpaper-grid-item>
+        </template>
+        <template is="dom-if" if="[[isOnlineTile_(item)]]">
+          <div class="photo-container">
+            <div aria-disabled$="[[getAriaDisabled_(item)]]"
+                aria-posinset$="[[getAriaIndex_(index)]]"
+                class$="[[getClassForTile_(item)]]"
+                on-click="onCollectionSelected_"
+                on-keypress="onCollectionSelected_"
+                role="option"
+                tabindex$="[[tabIndex]]">
+              <div class$="[[getClassForImagesContainer_(item)]]">
+                <div class="photo-images-border"></div>
+                <template is="dom-repeat" items="[[item.preview]]" as="preview">
+                  <img aria-hidden="true"
+                      auto-src="[[preview.url]]"
+                      class$="[[getClassForImg_(index, item)]]"
+                      clear-src
+                      data-collection-id$="[[item.id]]"
+                      is="cr-auto-img"
+                      on-error="onImgLoad_"
+                      on-load="onImgLoad_">
+                </template>
+              </div>
+              <div class="photo-text-container"
+                  hidden$="[[isPhotoTextHidden_(item, loadedCollectionIdPhotos_)]]">
+                <p title$="[[item.name]]">[[item.name]]</p>
+                <p title$="[[item.count]]">[[item.count]]</p>
+              </div>
+              <div class="photo-gradient-mask"
+                  hidden$="[[isPhotoTextHidden_(item, loadedCollectionIdPhotos_)]]">
+              </div>
             </div>
           </div>
         </template>
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_collections_element.ts b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_collections_element.ts
index 9590235..e271b60 100644
--- a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_collections_element.ts
+++ b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_collections_element.ts
@@ -29,6 +29,7 @@
 import {getLoadingPlaceholderAnimationDelay, getLoadingPlaceholders, getPathOrSymbol} from './utils.js';
 import {getTemplate} from './wallpaper_collections_element.html.js';
 import {initializeBackdropData} from './wallpaper_controller.js';
+import {WallpaperGridItemSelectedEvent} from './wallpaper_grid_item_element.js';
 import {getWallpaperProvider} from './wallpaper_interface_provider.js';
 
 const kGooglePhotosCollectionId = 'google_photos_';
@@ -72,11 +73,13 @@
 
 type Tile = LoadingTile|GooglePhotosTile|LocalTile|OnlineTile;
 
-interface RepeaterEvent extends CustomEvent {
-  model: {
-    item: Tile,
-  };
-}
+/**
+ * Before switching entirely to WallpaperGridItem, have to deal with a mix of
+ * keyboard and mouse events and a custom WallpaperGridItemSelected event.
+ */
+type OnCollectionSelectedEvent =
+    (MouseEvent|KeyboardEvent|WallpaperGridItemSelectedEvent)&
+    {model: {item: Tile}};
 
 function collectionsError(
     collections: WallpaperCollection[]|null,
@@ -436,17 +439,15 @@
     this.set('tiles_.0', tile);
   }
 
-  private getClassForTile_(tile: LocalTile|OnlineTile|null): string {
+  private getClassForTile_(tile: OnlineTile|null): string {
     if (!tile) {
       return '';
     }
+    assert(this.isOnlineTile_(tile), 'only online tile allowed');
     const classes = ['photo-inner-container'];
     if (tile.disabled) {
       classes.push('photo-loading-failure');
     }
-    if (this.isLocalTile_(tile)) {
-      classes.push('local');
-    }
     return classes.join(' ');
   }
 
@@ -477,9 +478,18 @@
   }
 
   /** Navigate to the correct route based on user selection. */
-  private onCollectionSelected_(e: RepeaterEvent) {
+  private onCollectionSelected_(e: OnCollectionSelectedEvent) {
     const tile = e.model.item;
-    if (!isSelectionEvent(e) || !this.isSelectableTile_(tile)) {
+    assert(!!tile, 'tile must be set to select');
+    if (!this.isSelectableTile_(tile)) {
+      // Ignore all events from disabled/loading tiles.
+      return;
+    }
+    if (!(e instanceof WallpaperGridItemSelectedEvent) &&
+        !isSelectionEvent(e)) {
+      // While refactoring is in progress, may receive either a
+      // `WallpaperGridItemSelectedEvent` or a mouse/keyboard selection event.
+      // If not one of those two event types, ignore it and let it propagate.
       return;
     }
     switch (tile.id) {
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_grid_item_element.html b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_grid_item_element.html
index 6aaf0448..2a16869 100644
--- a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_grid_item_element.html
+++ b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_grid_item_element.html
@@ -8,7 +8,7 @@
     /* Subtract 0.34px to fix subpixel rounding issues with iron-list. This
      * ensures all grid items in a row add up to at least 1px smaller than the
      * parent width. */
-    width: calc(100% / 3 - 0.34px);
+    width: var(--wallpaper-grid-item-width, calc(100% / 3 - 0.34px));
   }
 
   @media(min-width: 720px) {
@@ -16,7 +16,7 @@
       /* Subtract 0.25px to fix subpixel rounding issues with iron-list. This
        * ensures all grid items in a row add up to at least 1px smaller than the
        * parent width. */
-      width: calc(100% / 4 - 0.25px) !important;
+      width: var(--wallpaper-grid-item-width, calc(100% / 4 - 0.25px)) !important;
     }
   }
 
@@ -43,6 +43,7 @@
     box-sizing: border-box;
     cursor: pointer;
     display: flex;
+    flex-flow: row wrap;
     height: 100%;
     justify-content: center;
     overflow: hidden;
@@ -63,23 +64,35 @@
   }
 
   img {
-    border-radius: var(--personalization-app-grid-item-border-radius);
-    flex: 1 1 0;
-    height: 100%;
-    min-width: 50%;
     object-fit: cover;
+  }
+
+  :host(:not([collage])) img {
+    border-radius: var(--personalization-app-grid-item-border-radius);
+    height: 100%;
     position: absolute;
     width: 100%;
   }
 
-  img:has(+ img) {
+  :host(:not([collage])) img:has(+ img) {
     clip-path: inset(0 50% 0 0);
   }
 
-  img+img {
+  :host(:not([collage])) img+img {
     clip-path: inset(0 0 0 50%);
   }
 
+  :host([collage]) img {
+    flex: 1 1 0;
+    height: 100%;
+    min-width: 50%;
+  }
+
+  :host([collage]) img:first-of-type:nth-last-of-type(n+3),
+  :host([collage]) img:first-of-type:nth-last-of-type(n+3) ~ img {
+    height: 50%;
+  }
+
   :host([aria-selected='true']) img {
     animation-duration: 200ms;
     animation-fill-mode: forwards;
@@ -165,7 +178,7 @@
 
 </style>
 <div class="item" style$="[[getItemPlaceholderAnimationDelay_(index)]]">
-  <template is="dom-repeat" items="[[getSrcArray_(src)]]">
+  <template is="dom-repeat" items="[[getSrcArray_(src, collage)]]">
     <img aria-hidden="true"
         auto-src="[[item.url]]"
         clear-src
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_grid_item_element.ts b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_grid_item_element.ts
index 34ae942..b77ab4c 100644
--- a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_grid_item_element.ts
+++ b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_grid_item_element.ts
@@ -59,6 +59,12 @@
   }
 }
 
+/** The maximum number of images to display in one wallpaper grid item. */
+const enum MaxImageCount {
+  COLLAGE = 4,
+  DEFAULT = 2,
+}
+
 export class WallpaperGridItem extends PolymerElement {
   static get is(): 'wallpaper-grid-item' {
     return 'wallpaper-grid-item';
@@ -73,6 +79,7 @@
       src: {
         type: Object,
         observer: 'onImageSrcChanged_',
+        value: null,
       },
 
       index: Number,
@@ -95,6 +102,13 @@
         observer: 'onDisabledChanged_',
       },
 
+      collage: {
+        type: Boolean,
+        value: false,
+        reflectToAttribute: true,
+        observer: 'onCollageChanged_',
+      },
+
       imageStatus_: {
         type: Array,
         value() {
@@ -107,12 +121,13 @@
 
   /**
    * The source for the image to render for the grid item. Will display a
-   * placeholder loading animation if `src` is undefined or null.
-   * `src` will be undefined if the attribute is not set, but can also be
-   * explicitly set to null to force showing a placeholder animation.
+   * placeholder loading animation if `src` is null.
    * If `src` is an array, will display the first two images side by side.
+   * If `collage` is set and `src` is an array, will display up to the first
+   * four images tiled.
+   * @default null
    */
-  src: Url|Url[]|null|undefined;
+  src: Url|Url[]|null;
 
   /** The index of the grid item within its parent grid. */
   index: number;
@@ -141,6 +156,13 @@
    */
   disabled: boolean;
 
+  /**
+   * Whether to display 2 images side by side in split Dark/Light mode,
+   * or 4 images in a collage.
+   * @default false
+   */
+  collage: boolean;
+
   // Track if images are loaded, failed, or ready to display.
   private imageStatus_: ImageStatus[];
 
@@ -165,11 +187,10 @@
   }
 
   // Invoked on changes to |imageSrc|.
-  private onImageSrcChanged_(
-      src: Url|Url[]|undefined, old: Url|Url[]|undefined) {
+  private onImageSrcChanged_(src: Url|Url[]|null, old: Url|Url[]|null) {
     // Set loading status if src has just changed while we wait for new images.
-    const oldSrcArray = this.getSrcArray_(old);
-    this.imageStatus_ = this.getSrcArray_(src).map(({url}, i) => {
+    const oldSrcArray = this.getSrcArray_(old, this.collage);
+    this.imageStatus_ = this.getSrcArray_(src, this.collage).map(({url}, i) => {
       if (oldSrcArray.length > i && oldSrcArray[i].url === url) {
         // If the underlying url has not changed, keep the prior image status.
         // If we have a new |Url| object but the underlying url is the same, the
@@ -192,6 +213,22 @@
     this.setAttribute('aria-disabled', disabled.toString());
   }
 
+  private onCollageChanged_(collage: boolean) {
+    if (collage) {
+      const imageStatus =
+          this.getSrcArray_(this.src, collage)
+              .map(
+                  (_, index) => this.imageStatus_.length > index ?
+                      this.imageStatus_[index] :
+                      ImageStatus.LOADING);
+      this.imageStatus_ = imageStatus;
+      return;
+    }
+
+    this.imageStatus_.length =
+        Math.min(MaxImageCount.DEFAULT, this.imageStatus_.length);
+  }
+
   private onImageStatusChanged_(imageStatus: ImageStatus[]) {
     if (shouldShowPlaceholder(imageStatus)) {
       this.setAttribute('placeholder', '');
@@ -212,12 +249,13 @@
         (status, index) => index === targetIndex ? ImageStatus.READY : status);
   }
 
-  private getSrcArray_(src: Url|Url[]|undefined): Url[] {
+  private getSrcArray_(src: Url|Url[]|null, collage: boolean): Url[] {
     if (!src) {
       return [];
     }
     if (Array.isArray(src)) {
-      return src.slice(0, 2);
+      const max = collage ? MaxImageCount.COLLAGE : MaxImageCount.DEFAULT;
+      return src.slice(0, max);
     }
     return [src];
   }
diff --git a/base/command_line.cc b/base/command_line.cc
index 77a452c8..2b0bf13 100644
--- a/base/command_line.cc
+++ b/base/command_line.cc
@@ -554,6 +554,10 @@
   StringType params;
   // Append switches and arguments.
   bool parse_switches = true;
+#if BUILDFLAG(IS_WIN)
+  bool appended_single_argument_switch = false;
+#endif
+
   for (size_t i = 1; i < argv_.size(); ++i) {
     StringType arg = argv_[i];
     StringType switch_string;
@@ -572,7 +576,16 @@
       }
     } else {
 #if BUILDFLAG(IS_WIN)
-      arg = QuoteForCommandLineToArgvW(arg, allow_unsafe_insert_sequences);
+      if (has_single_argument_switch_) {
+        // Check that we don't have multiple arguments when
+        // `has_single_argument_switch_` is true.
+        DCHECK(!appended_single_argument_switch);
+        appended_single_argument_switch = true;
+        params.append(base::StrCat(
+            {kSwitchPrefixes[0], kSingleArgument, FILE_PATH_LITERAL(" ")}));
+      } else {
+        arg = QuoteForCommandLineToArgvW(arg, allow_unsafe_insert_sequences);
+      }
 #endif
       params.append(arg);
     }
diff --git a/base/command_line_unittest.cc b/base/command_line_unittest.cc
index f900a90..04d2201 100644
--- a/base/command_line_unittest.cc
+++ b/base/command_line_unittest.cc
@@ -338,6 +338,20 @@
   EXPECT_TRUE(cl_for_shell.HasSingleArgumentSwitch());
 }
 
+// Test that creating a new command line from the string version of a single
+// argument command line maintains the single argument switch, and the
+// argument.
+TEST(CommandLineTest, MaintainSingleArgument) {
+  // Putting a space in the file name will force escaping of the argument.
+  static const CommandLine::StringType kCommandLine =
+      FILE_PATH_LITERAL("program --switch --single-argument foo bar.html");
+  CommandLine cl = CommandLine::FromString(kCommandLine);
+  CommandLine cl_for_shell = CommandLine::FromString(cl.GetCommandLineString());
+  EXPECT_TRUE(cl_for_shell.HasSingleArgumentSwitch());
+  // Verify that we command line survives the round trip with an escaped arg.
+  EXPECT_EQ(kCommandLine, cl_for_shell.GetCommandLineString());
+}
+
 #endif  // BUILDFLAG(IS_WIN)
 
 // Tests that when AppendArguments is called that the program is set correctly
diff --git a/build/android/gyp/create_java_binary_script.py b/build/android/gyp/create_java_binary_script.py
index 2c7ad27e..909c008 100755
--- a/build/android/gyp/create_java_binary_script.py
+++ b/build/android/gyp/create_java_binary_script.py
@@ -10,7 +10,7 @@
 jar. This includes correctly setting the classpath and the main class.
 """
 
-import optparse
+import argparse
 import os
 import sys
 
@@ -76,44 +76,58 @@
 
 def main(argv):
   argv = build_utils.ExpandFileArgs(argv)
-  parser = optparse.OptionParser()
-  parser.add_option('--output', help='Output path for executable script.')
-  parser.add_option('--main-class',
+  parser = argparse.ArgumentParser()
+  parser.add_argument('--output',
+                      required=True,
+                      help='Output path for executable script.')
+  parser.add_argument(
+      '--main-class',
+      required=True,
       help='Name of the java class with the "main" entry point.')
-  parser.add_option('--classpath', action='append', default=[],
-      help='Classpath for running the jar.')
-  parser.add_option('--noverify', action='store_true',
-      help='JVM flag: noverify.')
-  parser.add_option('--tiered-stop-at-level-one',
-                    action='store_true',
-                    help='JVM flag: -XX:TieredStopAtLevel=1.')
+  parser.add_argument('--max-heap-size',
+                      required=True,
+                      help='Argument for -Xmx')
+  parser.add_argument('--classpath',
+                      action='append',
+                      default=[],
+                      help='Classpath for running the jar.')
+  parser.add_argument('--noverify',
+                      action='store_true',
+                      help='JVM flag: noverify.')
+  parser.add_argument('--tiered-stop-at-level-one',
+                      action='store_true',
+                      help='JVM flag: -XX:TieredStopAtLevel=1.')
+  parser.add_argument('extra_program_args',
+                      nargs='*',
+                      help='This captures all '
+                      'args after "--" to pass as extra args to the java cmd.')
 
-  options, extra_program_args = parser.parse_args(argv)
+  args = parser.parse_args(argv)
 
-  extra_flags = []
-  if options.noverify:
+  extra_flags = [f'java_cmd.append("-Xmx{args.max_heap_size}")']
+  if args.noverify:
     extra_flags.append('java_cmd.append("-noverify")')
-  if options.tiered_stop_at_level_one:
+  if args.tiered_stop_at_level_one:
     extra_flags.append('java_cmd.append("-XX:TieredStopAtLevel=1")')
 
   classpath = []
-  for cp_arg in options.classpath:
+  for cp_arg in args.classpath:
     classpath += build_utils.ParseGnList(cp_arg)
 
-  run_dir = os.path.dirname(options.output)
+  run_dir = os.path.dirname(args.output)
   classpath = [os.path.relpath(p, run_dir) for p in classpath]
   java_path = os.path.relpath(
       os.path.join(build_utils.JAVA_HOME, 'bin', 'java'), run_dir)
 
-  with build_utils.AtomicOutput(options.output, mode='w') as script:
+  with build_utils.AtomicOutput(args.output, mode='w') as script:
     script.write(
         script_template.format(classpath=('"%s"' % '", "'.join(classpath)),
                                java_path=repr(java_path),
-                               main_class=options.main_class,
-                               extra_program_args=repr(extra_program_args),
+                               main_class=args.main_class,
+                               extra_program_args=repr(args.extra_program_args),
                                extra_flags='\n'.join(extra_flags)))
 
-  os.chmod(options.output, 0o750)
+  os.chmod(args.output, 0o750)
 
 
 if __name__ == '__main__':
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index bff3789..6d8b674 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -1419,6 +1419,11 @@
       _main_class = invoker.main_class
       _build_config = invoker.build_config
       _script_name = invoker.script_name
+      if (defined(invoker.max_heap_size)) {
+        _max_heap_size = invoker.max_heap_size
+      } else {
+        _max_heap_size = "1G"
+      }
 
       script = "//build/android/gyp/create_java_binary_script.py"
       inputs = [ _build_config ]
@@ -1431,6 +1436,7 @@
         "--main-class",
         _main_class,
         "--classpath=@FileArg($_rebased_build_config:deps_info:host_classpath)",
+        "--max-heap-size=$_max_heap_size",
       ]
       data = []
 
@@ -4037,6 +4043,7 @@
                                [
                                  "tiered_stop_at_level_one",
                                  "main_class",
+                                 "max_heap_size",
                                  "wrapper_script_args",
                                ])
         build_config = _build_config
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 7c6de82..b1e5b39 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -601,7 +601,12 @@
         cflags_cc += [ "-fno-trigraphs" ]
       }
     } else if (is_clang) {
-      cflags_cc += [ "-std=${standard_prefix}++20" ]
+      if (is_chromeos_device) {
+        # TODO(crbug.com/1392471): Support C++20 in CrOS toolchain.
+        cflags_cc += [ "-std=${standard_prefix}++17" ]
+      } else {
+        cflags_cc += [ "-std=${standard_prefix}++20" ]
+      }
     } else {
       # The gcc bots are currently using GCC 9, which is not new enough to
       # support "c++20"/"gnu++20".
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 45a1f43..a685ccd 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -956,6 +956,9 @@
     # Needed by androidx.test.core.app.ActivityScenario
     android_manifest = "//chrome/android/junit/AndroidManifest.xml"
 
+    # This target OOMs with the default 1G.
+    max_heap_size = "2G"
+
     data_deps = [ "//testing/buildbot/filters:chrome_junit_tests_filters" ]
 
     package_name = chrome_public_manifest_package
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 5188cc5..90e8b1e94 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -475,6 +475,7 @@
   "java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java",
   "java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabFactory.java",
   "java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabProvider.java",
+  "java/src/org/chromium/chrome/browser/customtabs/content/CustomTabCountObserver.java",
   "java/src/org/chromium/chrome/browser/customtabs/content/CustomTabIntentHandler.java",
   "java/src/org/chromium/chrome/browser/customtabs/content/CustomTabIntentHandlingStrategy.java",
   "java/src/org/chromium/chrome/browser/customtabs/content/DefaultCustomTabIntentHandlingStrategy.java",
diff --git a/chrome/android/chrome_junit_test_java_sources.gni b/chrome/android/chrome_junit_test_java_sources.gni
index 610a22d..6d16adff 100644
--- a/chrome/android/chrome_junit_test_java_sources.gni
+++ b/chrome/android/chrome_junit_test_java_sources.gni
@@ -111,6 +111,7 @@
   "junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationControllerTest.java",
   "junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabControllerUnitTest.java",
   "junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityUrlLoadingTest.java",
+  "junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabCountObserverUnitTest.java",
   "junit/src/org/chromium/chrome/browser/customtabs/content/RealtimeEngagementSignalObserverUnitTest.java",
   "junit/src/org/chromium/chrome/browser/customtabs/features/ImmersiveModeControllerTest.java",
   "junit/src/org/chromium/chrome/browser/customtabs/features/TabInteractionRecorderUnitTest.java",
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java
index 60987a93..d03d7264 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java
@@ -192,7 +192,7 @@
     }
 
     boolean isFillingViewShown(View view) {
-        return isInitialized() && !isSoftKeyboardShowing(view) && mKeyboardAccessory.hasActiveTab();
+        return isInitialized() && mKeyboardAccessory.hasActiveTab() && !isSoftKeyboardShowing(view);
     }
 
     ObservableSupplier<Integer> getBottomInsetSupplier() {
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/FakeKeyboard.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/FakeKeyboard.java
index 69ced559..3ac41fd 100644
--- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/FakeKeyboard.java
+++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/FakeKeyboard.java
@@ -99,11 +99,6 @@
         return mIsShowing ? getStaticKeyboardHeight() : 0;
     }
 
-    @Override
-    public int calculateKeyboardDetectionThreshold(Context context, View rootView) {
-        return 0;
-    }
-
     /**
      * Creates an inset observer view calculating the bottom inset based on the fake keyboard.
      * @param context Context used to instantiate this view.
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
index 038c85f..744463b 100644
--- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
+++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
@@ -869,6 +869,7 @@
     public void handleBackPress() {
         boolean ret = onBackPressedInternal();
         assert ret;
+        notifyBackPressStateChanged();
     }
 
     @Override
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 3d9fa70..6c3f9d0 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
@@ -289,14 +289,17 @@
     private void updateLayout(boolean isSmallLayoutWidth) {
         ListLayoutHelper listLayoutHelper =
                 mCoordinator.getHybridListRenderer().getListLayoutHelper();
-        if (!FeedFeatures.isMultiColumnFeedEnabled(mContext) || listLayoutHelper == null) return;
+        if (!FeedFeatures.isMultiColumnFeedEnabled(mContext) || listLayoutHelper == null
+                || mCurrentStream == null) {
+            return;
+        }
         int spanCount = shouldUseSingleSpan(isSmallLayoutWidth) ? SPAN_COUNT_SMALL_WIDTH
                                                                 : SPAN_COUNT_LARGE_WIDTH;
         listLayoutHelper.setSpanCount(spanCount);
     }
 
     private boolean shouldUseSingleSpan(boolean isSmallLayoutWidth) {
-        boolean supportsOptions = mCurrentStream != null && mCurrentStream.supportsOptions();
+        boolean supportsOptions = mCurrentStream.supportsOptions();
         boolean isFollowingFeedSortDisabled =
                 (!ChromeFeatureList.isEnabled(ChromeFeatureList.WEB_FEED_SORT)
                         && mCurrentStream.getStreamKind() == StreamKind.FOLLOWING);
@@ -326,7 +329,6 @@
                     .set(SectionHeaderProperties.OPTIONS_INDICATOR_VISIBILITY_KEY,
                             ViewVisibility.VISIBLE);
         }
-        updateLayout(false);
         if (!mSettingUpStreams) {
             logSwitchedFeeds(newStream);
             bindStream(newStream, /*shouldScrollToTop=*/true);
@@ -633,6 +635,7 @@
             return;
         }
         mCurrentStream = stream;
+        updateLayout(false);
         mCurrentStream.addOnContentChangedListener(mStreamContentChangedListener);
 
         if (FeedFeatures.isAutoScrollToTopEnabled() && mRestoreScrollState == null) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeKeyboardVisibilityDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeKeyboardVisibilityDelegate.java
index 0ac5fae4..f207a3ed 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeKeyboardVisibilityDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeKeyboardVisibilityDelegate.java
@@ -11,8 +11,11 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Px;
+import androidx.core.view.WindowInsetsCompat;
 
 import org.chromium.base.supplier.Supplier;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.flags.MutableFlagWithSafeDefault;
 import org.chromium.chrome.browser.init.SingleWindowKeyboardVisibilityDelegate;
 import org.chromium.chrome.browser.keyboard_accessory.ManualFillingComponent;
 
@@ -24,6 +27,9 @@
  */
 public class ChromeKeyboardVisibilityDelegate extends SingleWindowKeyboardVisibilityDelegate
         implements ManualFillingComponent.SoftKeyboardDelegate {
+    private static final MutableFlagWithSafeDefault sScrollOptimizationsFlag =
+            new MutableFlagWithSafeDefault(ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS, false);
+
     private final Supplier<ManualFillingComponent> mManualFillingComponentSupplier;
 
     /**
@@ -54,6 +60,20 @@
                         && mManualFillingComponentSupplier.get().isFillingViewShown(view));
     }
 
+    @Override
+    public int calculateKeyboardHeight(View rootView) {
+        // TODO(https://crbug.com/1385562: remove the flag guard once this change is known to be
+        // safe).
+        if (sScrollOptimizationsFlag.isEnabled()) {
+            if (rootView == null || rootView.getRootWindowInsets() == null) return 0;
+            return WindowInsetsCompat.toWindowInsetsCompat(rootView.getRootWindowInsets(), rootView)
+                    .getInsets(WindowInsetsCompat.Type.ime())
+                    .bottom;
+        }
+
+        return super.calculateKeyboardHeight(rootView);
+    }
+
     /**
      * Implementation ignoring the Chrome-specific keyboard logic on top of the system keyboard.
      * @see ManualFillingComponent.SoftKeyboardDelegate#hideSoftKeyboardOnly(View)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index ea12d419..124c4cf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -118,8 +118,6 @@
 import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
 import org.chromium.chrome.browser.native_page.NativePageAssassin;
 import org.chromium.chrome.browser.navigation_predictor.NavigationPredictorBridge;
-import org.chromium.chrome.browser.notifications.permissions.NotificationPermissionController;
-import org.chromium.chrome.browser.notifications.permissions.NotificationPermissionRationaleDialogController;
 import org.chromium.chrome.browser.ntp.NewTabPageLaunchOrigin;
 import org.chromium.chrome.browser.ntp.NewTabPageUma;
 import org.chromium.chrome.browser.ntp.NewTabPageUtils;
@@ -380,7 +378,6 @@
     private TabbedModeTabDelegateFactory mTabDelegateFactory;
 
     private final AppLaunchDrawBlocker mAppLaunchDrawBlocker;
-    private NotificationPermissionController mNotificationPermissionController;
 
     private ReturnToChromeBackPressHandler mReturnToChromeBackPressHandler;
     private ReadingListBackPressHandler mReadingListBackPressHandler;
@@ -1043,14 +1040,6 @@
 
             ChromeAccessibilityUtil.get().addObserver(mLayoutManager);
             if (isTablet()) ChromeAccessibilityUtil.get().addObserver(mCompositorViewHolder);
-
-            mNotificationPermissionController =
-                    new NotificationPermissionController(getWindowAndroid(),
-                            new NotificationPermissionRationaleDialogController(
-                                    this, getModalDialogManager()));
-            NotificationPermissionController.attach(
-                    getWindowAndroid(), mNotificationPermissionController);
-            mNotificationPermissionController.requestPermissionIfNeeded(false /* contextual */);
             if (BackPressManager.isEnabled()) initializeBackPressHandlers();
         }
     }
@@ -2656,11 +2645,6 @@
             mMinimizeAppAndCloseTabBackPressHandler = null;
         }
 
-        if (mNotificationPermissionController != null) {
-            NotificationPermissionController.detach(mNotificationPermissionController);
-            mNotificationPermissionController = null;
-        }
-
         if (mCallbackController != null) {
             mCallbackController.destroy();
             mCallbackController = null;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/creator/CreatorActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/creator/CreatorActivity.java
index 3a64d69d4..0ed9804 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/creator/CreatorActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/creator/CreatorActivity.java
@@ -38,6 +38,7 @@
         Toolbar actionBar = findViewById(R.id.action_bar);
         setSupportActionBar(actionBar);
         getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+        getSupportActionBar().setDisplayShowTitleEnabled(false);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CloseButtonNavigator.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CloseButtonNavigator.java
index 54800cd..73b0416 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CloseButtonNavigator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CloseButtonNavigator.java
@@ -111,6 +111,11 @@
                 return;
             }
         }
+
+        if (numTabsClosed > 0) {
+            RecordHistogram.recordCount100Histogram(
+                    "CustomTabs.TabCounts.OnClosingAllTabs", numTabsClosed);
+        }
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabCountObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabCountObserver.java
new file mode 100644
index 0000000..8ac24d6
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabCountObserver.java
@@ -0,0 +1,54 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.customtabs.content;
+
+import androidx.annotation.NonNull;
+
+import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.chrome.browser.dependency_injection.ActivityScope;
+import org.chromium.chrome.browser.tab.Tab;
+
+import java.util.HashSet;
+
+import javax.inject.Inject;
+
+/**
+ * Class used to count the number of tabs opened in a custom tab session. Used to understand how
+ * often a user navigates to links with "target=_blank" in one single CCT session.
+ */
+@ActivityScope
+public class CustomTabCountObserver extends CustomTabActivityTabProvider.Observer {
+    private final HashSet<Integer> mSeenTabId = new HashSet<>();
+
+    @Inject
+    public CustomTabCountObserver(CustomTabActivityTabProvider tabProvider) {
+        tabProvider.addObserver(this);
+        if (tabProvider.getTab() != null) {
+            recordTabSeen(tabProvider.getTab());
+        }
+    }
+
+    @Override
+    public void onInitialTabCreated(@NonNull Tab tab, int mode) {
+        recordTabSeen(tab);
+    }
+
+    @Override
+    public void onTabSwapped(@NonNull Tab tab) {
+        recordTabSeen(tab);
+    }
+
+    @Override
+    public void onAllTabsClosed() {
+        mSeenTabId.clear();
+    }
+
+    private void recordTabSeen(@NonNull Tab tab) {
+        if (mSeenTabId.add(tab.getId())) {
+            RecordHistogram.recordCount100Histogram(
+                    "CustomTabs.TabCounts.UniqueTabsSeen", mSeenTabId.size());
+        }
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/TabObserverRegistrar.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/TabObserverRegistrar.java
index e657484..4313aa0a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/TabObserverRegistrar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/TabObserverRegistrar.java
@@ -35,6 +35,7 @@
 @ActivityScope
 public class TabObserverRegistrar implements TabModelObserver, DestroyObserver {
     private CustomTabActivityTabProvider mTabProvider;
+    private final CustomTabCountObserver mTabCountObserver;
     private final Set<PageLoadMetrics.Observer> mPageLoadMetricsObservers = new HashSet<>();
     private final Set<TabObserver> mTabObservers = new HashSet<>();
 
@@ -120,8 +121,9 @@
 
     @Inject
     public TabObserverRegistrar(ActivityLifecycleDispatcher lifecycleDispatcher,
-            CustomTabActivityTabProvider tabProvider) {
+            CustomTabActivityTabProvider tabProvider, CustomTabCountObserver tabCountObserver) {
         mTabProvider = tabProvider;
+        mTabCountObserver = tabCountObserver;
         mTabProvider.addObserver(mActivityTabProviderObserver);
 
         lifecycleDispatcher.register(this);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/quickactionsearchwidget/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/quickactionsearchwidget/OWNERS
index f4418aa..da4be492 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/quickactionsearchwidget/OWNERS
+++ b/chrome/android/java/src/org/chromium/chrome/browser/quickactionsearchwidget/OWNERS
@@ -1,3 +1,2 @@
 ender@google.com
-fgorski@chromium.org
-wylieb@chromium.org
\ No newline at end of file
+wylieb@chromium.org
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/RequestDesktopUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/RequestDesktopUtils.java
index ce7ac0eb..c3e8573 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/RequestDesktopUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/RequestDesktopUtils.java
@@ -32,6 +32,7 @@
 import org.chromium.components.browser_ui.site_settings.SiteSettingsCategory;
 import org.chromium.components.browser_ui.site_settings.SiteSettingsFeatureList;
 import org.chromium.components.browser_ui.site_settings.WebsitePreferenceBridge;
+import org.chromium.components.browser_ui.util.ConversionUtils;
 import org.chromium.components.content_settings.ContentSettingValues;
 import org.chromium.components.content_settings.ContentSettingsType;
 import org.chromium.components.feature_engagement.FeatureConstants;
@@ -67,6 +68,8 @@
     static final double DEFAULT_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES = 12.0;
     static final String PARAM_GLOBAL_SETTING_DEFAULT_ON_ON_LOW_END_DEVICES =
             "default_on_on_low_end_devices";
+    static final String PARAM_GLOBAL_SETTING_DEFAULT_ON_MEMORY_LIMIT = "default_on_memory_limit";
+    static final int DEFAULT_GLOBAL_SETTING_DEFAULT_ON_MEMORY_LIMIT_THRESHOLD_MB = 0;
     static final String PARAM_SHOW_MESSAGE_ON_GLOBAL_SETTING_DEFAULT_ON =
             "show_message_on_default_on";
 
@@ -78,6 +81,8 @@
             "opt_in_display_size_max_threshold_inches";
     static final double DEFAULT_GLOBAL_SETTING_OPT_IN_DISPLAY_SIZE_MAX_THRESHOLD_INCHES =
             Double.MAX_VALUE;
+    static final String PARAM_GLOBAL_SETTING_OPT_IN_MEMORY_LIMIT = "opt_in_memory_limit";
+    static final int DEFAULT_GLOBAL_SETTING_OPT_IN_MEMORY_LIMIT_THRESHOLD_MB = 0;
 
     // Global defaults experiment constants.
     static final String ENABLED_GROUP_SUFFIX = "_Enabled";
@@ -334,6 +339,16 @@
             return false;
         }
 
+        // If the device does not meet the memory threshold, avoid default-enabling the setting.
+        int memoryLimitMB = ChromeFeatureList.getFieldTrialParamByFeatureAsInt(feature,
+                PARAM_GLOBAL_SETTING_DEFAULT_ON_MEMORY_LIMIT,
+                DEFAULT_GLOBAL_SETTING_DEFAULT_ON_MEMORY_LIMIT_THRESHOLD_MB);
+        if (memoryLimitMB != 0
+                && SysUtils.amountOfPhysicalMemoryKB()
+                        < memoryLimitMB * ConversionUtils.KILOBYTES_PER_MEGABYTE) {
+            return false;
+        }
+
         SharedPreferencesManager sharedPreferencesManager = SharedPreferencesManager.getInstance();
 
         boolean previouslyDefaultEnabled = sharedPreferencesManager.readBoolean(
@@ -525,6 +540,16 @@
             return false;
         }
 
+        // Present the message only if the device meets the memory threshold.
+        int memoryLimitMB = ChromeFeatureList.getFieldTrialParamByFeatureAsInt(feature,
+                PARAM_GLOBAL_SETTING_OPT_IN_MEMORY_LIMIT,
+                DEFAULT_GLOBAL_SETTING_OPT_IN_MEMORY_LIMIT_THRESHOLD_MB);
+        if (memoryLimitMB != 0
+                && SysUtils.amountOfPhysicalMemoryKB()
+                        < memoryLimitMB * ConversionUtils.KILOBYTES_PER_MEGABYTE) {
+            return false;
+        }
+
         // Present the message only if the desktop site global setting is off.
         if (WebsitePreferenceBridge.isCategoryEnabled(
                     profile, ContentSettingsType.REQUEST_DESKTOP_SITE)) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
index d879cc5..438cd5eb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
@@ -64,6 +64,8 @@
 import org.chromium.chrome.browser.multiwindow.MultiInstanceIphController;
 import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
 import org.chromium.chrome.browser.night_mode.WebContentsDarkModeMessageController;
+import org.chromium.chrome.browser.notifications.permissions.NotificationPermissionController;
+import org.chromium.chrome.browser.notifications.permissions.NotificationPermissionRationaleDialogController;
 import org.chromium.chrome.browser.ntp.NewTabPageLaunchOrigin;
 import org.chromium.chrome.browser.ntp.NewTabPageUtils;
 import org.chromium.chrome.browser.offlinepages.indicator.OfflineIndicatorControllerV2;
@@ -155,6 +157,7 @@
     private AddToHomescreenMostVisitedTileClickObserver mAddToHomescreenMostVisitedTileObserver;
     private AppBannerInProductHelpController mAppBannerInProductHelpController;
     private PwaBottomSheetController mPwaBottomSheetController;
+    private NotificationPermissionController mNotificationPermissionController;
     private HistoryNavigationCoordinator mHistoryNavigationCoordinator;
     private NavigationSheet mNavigationSheet;
     private ComposedBrowserControlsVisibilityDelegate mAppBrowserControlsVisibilityDelegate;
@@ -387,6 +390,11 @@
             mCommerceSubscriptionsService = null;
         }
 
+        if (mNotificationPermissionController != null) {
+            NotificationPermissionController.detach(mNotificationPermissionController);
+            mNotificationPermissionController = null;
+        }
+
         super.onDestroy();
     }
 
@@ -669,6 +677,16 @@
         }
 
         if (!didTriggerPromo) {
+            mNotificationPermissionController = new NotificationPermissionController(mWindowAndroid,
+                    new NotificationPermissionRationaleDialogController(
+                            mActivity, mModalDialogManagerSupplier.get()));
+            NotificationPermissionController.attach(
+                    mWindowAndroid, mNotificationPermissionController);
+            didTriggerPromo = mNotificationPermissionController.requestPermissionIfNeeded(
+                    false /* contextual */);
+        }
+
+        if (!didTriggerPromo) {
             didTriggerPromo = FeatureNotificationUtils.willShowIPH(FeatureType.DEFAULT_BROWSER);
             FeatureNotificationUtils.registerIPHCallback(FeatureType.DEFAULT_BROWSER, () -> {
                 DefaultBrowserPromoUtils.prepareLaunchPromoIfNeeded(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoTest.java
index 0a9672f..d7996de 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoTest.java
@@ -19,6 +19,7 @@
 
 import android.app.Activity;
 
+import androidx.recyclerview.widget.RecyclerView;
 import androidx.test.filters.MediumTest;
 
 import org.junit.After;
@@ -34,7 +35,6 @@
 
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.MetricsUtils.HistogramDelta;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
@@ -48,6 +48,7 @@
 import org.chromium.chrome.test.batch.BlankCTATabInitialStateRule;
 import org.chromium.chrome.test.util.BookmarkTestRule;
 import org.chromium.chrome.test.util.browser.signin.AccountManagerTestRule;
+import org.chromium.components.browser_ui.widget.RecyclerViewTestUtils;
 import org.chromium.components.signin.base.CoreAccountInfo;
 import org.chromium.components.signin.metrics.SigninAccessPoint;
 
@@ -101,7 +102,6 @@
 
     @Test
     @MediumTest
-    @DisabledTest(message = "https://crbug.com/1383638")
     public void testSigninButtonDefaultAccount() {
         final HistogramDelta continuedHistogram = new HistogramDelta(CONTINUED_HISTOGRAM_NAME, 1);
         final CoreAccountInfo accountInfo =
@@ -157,6 +157,13 @@
         mBookmarkTestRule.showBookmarkManager(sActivityTestRule.getActivity());
         Assert.assertEquals(1, shownHistogram.getDelta());
 
+        // TODO(https://cbug.com/1383638): If this stops the flakes, consider removing
+        // activeInRecyclerView.
+        RecyclerView recyclerView = mBookmarkTestRule.getBookmarkActivity().findViewById(
+                R.id.selectable_list_recycler_view);
+        Assert.assertNotNull(recyclerView);
+        RecyclerViewTestUtils.waitForStableRecyclerView(recyclerView);
+
         // Profile data updates cause the signin promo to be recreated at the given index. The
         // RecyclerView's ViewGroup children may be stale, use activeInRecyclerView to filter to
         // only what is currently valid, otherwise the match will be ambiguous.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxPedalsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxPedalsTest.java
index b823c72..8dd660f7 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxPedalsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxPedalsTest.java
@@ -129,6 +129,9 @@
 
     @After
     public void tearDown() throws Exception {
+        if (mOmniboxUtils.getFocus()) {
+            mOmniboxUtils.clearFocus();
+        }
         TestThreadUtils.runOnUiThreadBlocking(
                 () -> { IncognitoTabHostUtils.closeAllIncognitoTabs(); });
         if (mTargetActivity != null) {
@@ -144,6 +147,7 @@
      */
     private void typeInOmnibox(String text) throws InterruptedException {
         mOmniboxUtils.requestFocus();
+        mOmniboxUtils.setText("");
         mOmniboxUtils.typeText(text, false);
         mOmniboxUtils.waitForAutocomplete();
         mOmniboxUtils.checkSuggestionsShown();
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CloseButtonNavigatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CloseButtonNavigatorTest.java
index 9703c0f2..8a789b1 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CloseButtonNavigatorTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CloseButtonNavigatorTest.java
@@ -17,6 +17,7 @@
 
 import android.os.Build;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -28,6 +29,8 @@
 import org.robolectric.ParameterizedRobolectricTestRunner.Parameters;
 import org.robolectric.annotation.Config;
 
+import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.base.metrics.UmaRecorderHolder;
 import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider;
 import org.chromium.chrome.browser.browserservices.intents.WebappExtras;
 import org.chromium.chrome.browser.customtabs.content.CustomTabActivityTabController;
@@ -99,6 +102,11 @@
         });
     }
 
+    @After
+    public void tearDown() {
+        UmaRecorderHolder.resetForTesting();
+    }
+
     private Tab createTabWithNavigationHistory(GURL... urls) {
         NavigationHistory history = new NavigationHistory();
 
@@ -151,6 +159,7 @@
         mCloseButtonNavigator.navigateOnClose();
 
         assertTrue(mTabs.empty());
+        assertOnAllTabsClosedRecorded(1);
     }
 
     @Test
@@ -166,6 +175,7 @@
             verify(currentTabsNavigationController(), never()).goToNavigationIndex(anyInt());
         } else {
             assertTrue(mTabs.empty());
+            assertOnAllTabsClosedRecorded(2);
         }
     }
 
@@ -178,6 +188,7 @@
         mCloseButtonNavigator.navigateOnClose();
 
         assertTrue(mTabs.empty());
+        assertOnAllTabsClosedRecorded(1);
     }
 
     @Test
@@ -194,6 +205,7 @@
             verify(currentTabsNavigationController(), never()).goToNavigationIndex(anyInt());
         } else {
             assertTrue(mTabs.empty());
+            assertOnAllTabsClosedRecorded(2);
         }
     }
 
@@ -208,6 +220,7 @@
         mCloseButtonNavigator.navigateOnClose();
 
         assertFalse(mTabs.isEmpty());
+        assertOnAllTabsClosedRecorded(0);
         verify(currentTabsNavigationController()).goToNavigationIndex(eq(1));
         // Ensure it was only called with that value.
         verify(currentTabsNavigationController()).goToNavigationIndex(anyInt());
@@ -225,6 +238,7 @@
         mCloseButtonNavigator.navigateOnClose();
 
         assertEquals(1, mTabs.size());
+        assertOnAllTabsClosedRecorded(0);
         verify(currentTabsNavigationController(), never()).goToNavigationIndex(anyInt());
     }
 
@@ -240,6 +254,7 @@
         mCloseButtonNavigator.navigateOnClose();
 
         assertEquals(1, mTabs.size());
+        assertOnAllTabsClosedRecorded(0);
         if (mIsWebapp) {
             verify(currentTabsNavigationController(), never()).goToNavigationIndex(anyInt());
         } else {
@@ -263,6 +278,7 @@
         mCloseButtonNavigator.navigateOnClose();
 
         assertEquals(1, mTabs.size());
+        assertOnAllTabsClosedRecorded(0);
         verify(currentTabsNavigationController()).goToNavigationIndex(eq(1));
         verify(currentTabsNavigationController()).goToNavigationIndex(anyInt());
     }
@@ -279,7 +295,19 @@
         mCloseButtonNavigator.navigateOnClose();
 
         assertEquals(1, mTabs.size());
+        assertOnAllTabsClosedRecorded(0);
         verify(currentTabsNavigationController()).goToNavigationIndex(eq(1));
         verify(currentTabsNavigationController()).goToNavigationIndex(anyInt());
     }
+
+    private void assertOnAllTabsClosedRecorded(int count) {
+        String histogram = "CustomTabs.TabCounts.OnClosingAllTabs";
+        if (count > 0) {
+            assertEquals(String.format("<%s> not recorded with sample <%d>.", histogram, count), 1,
+                    RecordHistogram.getHistogramValueCountForTesting(histogram, count));
+        } else {
+            assertEquals(String.format("<%s> should not be recorded.", histogram), 0,
+                    RecordHistogram.getHistogramTotalCountForTesting(histogram));
+        }
+    }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabCountObserverUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabCountObserverUnitTest.java
new file mode 100644
index 0000000..ad0887c
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabCountObserverUnitTest.java
@@ -0,0 +1,83 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.customtabs.content;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+
+import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.base.metrics.UmaRecorderHolder;
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.chrome.browser.tab.TabImpl;
+
+/**
+ * Unit tests for {@link CustomTabCountObserver}.
+ */
+@RunWith(BaseRobolectricTestRunner.class)
+public class CustomTabCountObserverUnitTest {
+    @Rule
+    public CustomTabActivityContentTestEnvironment env =
+            new CustomTabActivityContentTestEnvironment();
+
+    @After
+    public void tearDown() {
+        UmaRecorderHolder.resetForTesting();
+    }
+
+    @Test
+    public void observeBeforeInitialTab() {
+        env.tabProvider.setInitialTab(env.prepareTab(), TabCreationMode.DEFAULT);
+        new CustomTabCountObserver(env.tabProvider);
+
+        assertTabCountsRecorded(1, "Initial Tab created.");
+    }
+
+    @Test
+    public void observerMultipleTabs() {
+        TabImpl tab1 = newTabWithId(1);
+        TabImpl tab2 = newTabWithId(2);
+        TabImpl tab3 = newTabWithId(3);
+
+        new CustomTabCountObserver(env.tabProvider);
+        env.tabProvider.setInitialTab(tab1, TabCreationMode.DEFAULT);
+        assertTabCountsRecorded(1, "Initial Tab created.");
+
+        // Assuming tab 2 created by clicking target=_blank.
+        env.tabProvider.swapTab(tab2);
+        assertTabCountsRecorded(2, "Switched to new tab.");
+
+        // Assuming tab 2 closed.
+        env.tabProvider.swapTab(tab1);
+        assertTabCountsRecorded(2, "No new counts when switching into previous tab.");
+
+        // Assuming tab 3 created.
+        env.tabProvider.swapTab(tab3);
+        assertTabCountsRecorded(3, "3rd tab created.");
+
+        // Assuming all tab closed.
+        env.tabProvider.removeTab();
+        assertTabCountsRecorded(3, "No new counts when all tabs closing.");
+    }
+
+    private void assertTabCountsRecorded(int count, String reason) {
+        String histogram = "CustomTabs.TabCounts.UniqueTabsSeen";
+        Assert.assertEquals(String.format("<%s> with should recorded <%d> times. Reason: %s",
+                                    histogram, count, reason),
+                count, RecordHistogram.getHistogramTotalCountForTesting(histogram));
+        Assert.assertEquals(String.format("<%s> with sample <%d> is not recorded. Reason: %s",
+                                    histogram, count, reason),
+                1, RecordHistogram.getHistogramValueCountForTesting(histogram, count));
+    }
+
+    private TabImpl newTabWithId(int id) {
+        TabImpl tab = env.prepareTab();
+        Mockito.doReturn(id).when(tab).getId();
+        return tab;
+    }
+}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/feed/FeedSurfaceMediatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/feed/FeedSurfaceMediatorTest.java
index e6e9d76..0aea259 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/feed/FeedSurfaceMediatorTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/feed/FeedSurfaceMediatorTest.java
@@ -508,37 +508,41 @@
     @Config(qualifiers = "en-sw600dp")
     @Test
     public void testOnHeaderSelected_selectedWithLatestOptionsOnTablet() {
-        when(mFollowingStream.supportsOptions()).thenReturn(true);
-        when(mOptionsCoordinator.getSelectedOptionId()).thenReturn(ContentOrder.REVERSE_CHRON);
         when(mPrefService.getBoolean(Pref.ARTICLES_LIST_VISIBLE)).thenReturn(true);
         when(mPrefService.getBoolean(Pref.ENABLE_SNIPPETS)).thenReturn(true);
-        PropertyModel sectionHeaderModel = SectionHeaderListProperties.create(TOOLBAR_HEIGHT);
-        mFeedSurfaceMediator =
-                createMediator(FeedSurfaceCoordinator.StreamTabId.FOLLOWING, sectionHeaderModel);
+
+        // Set up mediator with For_you feed (2 column)
+        mFeedSurfaceMediator = createMediator(FeedSurfaceCoordinator.StreamTabId.FOR_YOU,
+                SectionHeaderListProperties.create(TOOLBAR_HEIGHT));
         mFeedSurfaceMediator.updateContent();
+
+        // Switch to following feed with latest option. Uses 2 column.
+        when(mFollowingStream.supportsOptions()).thenReturn(true);
+        when(mOptionsCoordinator.getSelectedOptionId()).thenReturn(ContentOrder.REVERSE_CHRON);
         OnSectionHeaderSelectedListener listener =
                 mFeedSurfaceMediator.getOrCreateSectionHeaderListenerForTesting();
         listener.onSectionHeaderSelected(1);
-
-        verify(mListLayoutHelper).setSpanCount(2);
+        verify(mListLayoutHelper, times(2)).setSpanCount(2);
     }
 
     @Config(qualifiers = "en-sw600dp")
     @Test
     public void testOnHeaderSelected_selectedWithSortOptionsOnTablet() {
-        when(mFollowingStream.supportsOptions()).thenReturn(true);
-        when(mOptionsCoordinator.getSelectedOptionId()).thenReturn(ContentOrder.GROUPED);
         when(mPrefService.getBoolean(Pref.ARTICLES_LIST_VISIBLE)).thenReturn(true);
         when(mPrefService.getBoolean(Pref.ENABLE_SNIPPETS)).thenReturn(true);
-        PropertyModel sectionHeaderModel = SectionHeaderListProperties.create(TOOLBAR_HEIGHT);
-        mFeedSurfaceMediator =
-                createMediator(FeedSurfaceCoordinator.StreamTabId.FOLLOWING, sectionHeaderModel);
+
+        // Set up mediator with For_you feed (2 column)
+        mFeedSurfaceMediator = createMediator(FeedSurfaceCoordinator.StreamTabId.FOR_YOU,
+                SectionHeaderListProperties.create(TOOLBAR_HEIGHT));
         mFeedSurfaceMediator.updateContent();
+        verify(mListLayoutHelper).setSpanCount(2);
+
+        // Switch to following feed with sort option. Uses 1 column.
+        when(mFollowingStream.supportsOptions()).thenReturn(true);
+        when(mOptionsCoordinator.getSelectedOptionId()).thenReturn(ContentOrder.GROUPED);
         OnSectionHeaderSelectedListener listener =
                 mFeedSurfaceMediator.getOrCreateSectionHeaderListenerForTesting();
-
         listener.onSectionHeaderSelected(1);
-
         verify(mListLayoutHelper).setSpanCount(1);
     }
 
@@ -549,14 +553,17 @@
         when(mOptionsCoordinator.getSelectedOptionId()).thenReturn(ContentOrder.GROUPED);
         when(mPrefService.getBoolean(Pref.ARTICLES_LIST_VISIBLE)).thenReturn(true);
         when(mPrefService.getBoolean(Pref.ENABLE_SNIPPETS)).thenReturn(true);
-        PropertyModel sectionHeaderModel = SectionHeaderListProperties.create(TOOLBAR_HEIGHT);
-        mFeedSurfaceMediator =
-                createMediator(FeedSurfaceCoordinator.StreamTabId.FOLLOWING, sectionHeaderModel);
+
+        // Set up mediator with Following feed with default sort option (1 column)
+        mFeedSurfaceMediator = createMediator(FeedSurfaceCoordinator.StreamTabId.FOLLOWING,
+                SectionHeaderListProperties.create(TOOLBAR_HEIGHT));
         mFeedSurfaceMediator.updateContent();
-
-        mFeedSurfaceMediator.onOptionChanged();
-
         verify(mListLayoutHelper).setSpanCount(1);
+
+        // Switch to latest sort. Verify 2 column
+        when(mOptionsCoordinator.getSelectedOptionId()).thenReturn(ContentOrder.REVERSE_CHRON);
+        mFeedSurfaceMediator.onOptionChanged();
+        verify(mListLayoutHelper).setSpanCount(2);
     }
 
     @Config(qualifiers = "en-sw600dp")
@@ -565,16 +572,19 @@
     public void testOnHeaderSelected_withFollowingAndSortDisabledOnTablet() {
         when(mPrefService.getBoolean(Pref.ARTICLES_LIST_VISIBLE)).thenReturn(true);
         when(mPrefService.getBoolean(Pref.ENABLE_SNIPPETS)).thenReturn(true);
-        PropertyModel sectionHeaderModel = SectionHeaderListProperties.create(TOOLBAR_HEIGHT);
-        mFeedSurfaceMediator =
-                createMediator(FeedSurfaceCoordinator.StreamTabId.FOLLOWING, sectionHeaderModel);
-        mFeedSurfaceMediator.updateContent();
 
+        // Set up mediator with For_you feed (2 column)
+        mFeedSurfaceMediator = createMediator(FeedSurfaceCoordinator.StreamTabId.FOR_YOU,
+                SectionHeaderListProperties.create(TOOLBAR_HEIGHT));
+        mFeedSurfaceMediator.updateContent();
+        verify(mListLayoutHelper).setSpanCount(2);
+
+        // Switch to following feed with sort option. Uses 1 column.
+        when(mFollowingStream.supportsOptions()).thenReturn(true);
+        when(mOptionsCoordinator.getSelectedOptionId()).thenReturn(ContentOrder.GROUPED);
         OnSectionHeaderSelectedListener listener =
                 mFeedSurfaceMediator.getOrCreateSectionHeaderListenerForTesting();
-
         listener.onSectionHeaderSelected(1);
-
         verify(mListLayoutHelper).setSpanCount(1);
     }
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/tab/RequestDesktopUtilsUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/tab/RequestDesktopUtilsUnitTest.java
index 91fdb53..a9cde06 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/tab/RequestDesktopUtilsUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/tab/RequestDesktopUtilsUnitTest.java
@@ -60,6 +60,7 @@
 import org.chromium.components.browser_ui.site_settings.SiteSettingsFeatureList;
 import org.chromium.components.browser_ui.site_settings.WebsitePreferenceBridge;
 import org.chromium.components.browser_ui.site_settings.WebsitePreferenceBridgeJni;
+import org.chromium.components.browser_ui.util.ConversionUtils;
 import org.chromium.components.content_settings.ContentSettingValues;
 import org.chromium.components.content_settings.ContentSettingsType;
 import org.chromium.components.feature_engagement.FeatureConstants;
@@ -136,15 +137,25 @@
     @Implements(SysUtils.class)
     static class ShadowSysUtils {
         private static boolean sLowEndDevice;
+        private static int sMemoryInMB;
 
         public static void setLowEndDevice(boolean lowEndDevice) {
             sLowEndDevice = lowEndDevice;
         }
 
+        public static void setMemoryInMB(int memoryInMB) {
+            sMemoryInMB = memoryInMB;
+        }
+
         @Implementation
         public static boolean isLowEndDevice() {
             return sLowEndDevice;
         }
+
+        @Implementation
+        public static int amountOfPhysicalMemoryKB() {
+            return sMemoryInMB * ConversionUtils.KILOBYTES_PER_MEGABYTE;
+        }
     }
 
     @Implements(UmaSessionStats.class)
@@ -227,6 +238,8 @@
 
         TrackerFactory.setTrackerForTests(mTracker);
         disableGlobalDefaultsExperimentFeatures();
+
+        ShadowSysUtils.setMemoryInMB(2048);
     }
 
     @After
@@ -381,6 +394,19 @@
     }
 
     @Test
+    public void testShouldDefaultEnableGlobalSetting_MemoryThreshold() {
+        Map<String, String> params = new HashMap<>();
+        params.put(RequestDesktopUtils.PARAM_GLOBAL_SETTING_DEFAULT_ON_MEMORY_LIMIT, "4000");
+        enableFeatureWithParams(ChromeFeatureList.REQUEST_DESKTOP_SITE_DEFAULTS, params, true);
+        boolean shouldDefaultEnable = RequestDesktopUtils.shouldDefaultEnableGlobalSetting(
+                RequestDesktopUtils
+                        .DEFAULT_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES);
+        Assert.assertFalse(
+                "Desktop site global setting should not be default-enabled on devices below the memory threshold.",
+                shouldDefaultEnable);
+    }
+
+    @Test
     public void testShouldDefaultEnableGlobalSetting_CustomScreenSizeThreshold() {
         Map<String, String> params = new HashMap<>();
         params.put(
@@ -757,6 +783,21 @@
     }
 
     @Test
+    public void testMaybeShowGlobalSettingOptInMessage_MemoryThreshold() {
+        Map<String, String> params = new HashMap<>();
+        params.put(RequestDesktopUtils.PARAM_GLOBAL_SETTING_OPT_IN_ENABLED, "true");
+        params.put(RequestDesktopUtils.PARAM_GLOBAL_SETTING_OPT_IN_MEMORY_LIMIT, "4000");
+        enableFeatureWithParams(ChromeFeatureList.REQUEST_DESKTOP_SITE_DEFAULTS, params, true);
+
+        boolean shown = RequestDesktopUtils.maybeShowGlobalSettingOptInMessage(
+                RequestDesktopUtils.DEFAULT_GLOBAL_SETTING_OPT_IN_DISPLAY_SIZE_MIN_THRESHOLD_INCHES,
+                mProfile, mMessageDispatcher, mActivity, mCurrentTabSupplier);
+        Assert.assertFalse(
+                "Desktop site global setting opt-in message should not be shown on devices below the memory threshold.",
+                shown);
+    }
+
+    @Test
     public void testUpdateDesktopSiteGlobalSettingOnUserRequest_DesktopSite() {
         RequestDesktopUtils.updateDesktopSiteGlobalSettingOnUserRequest(mProfile, true);
         verifyUpdateDesktopSiteGlobalSettingOnUserRequest(true);
diff --git a/chrome/app/os_settings_search_tag_strings.grdp b/chrome/app/os_settings_search_tag_strings.grdp
index af10751a..0c3d2b61 100644
--- a/chrome/app/os_settings_search_tag_strings.grdp
+++ b/chrome/app/os_settings_search_tag_strings.grdp
@@ -116,9 +116,12 @@
   <message name="IDS_OS_SETTINGS_TAG_CELLULAR_RENAME_PROFILE_ALT1" desc="Text for search result item which, when clicked, navigates the user to the Cellular eSIM network settings, with a menu containing a button to rename the currently-connected eSIM Cellular network. Alternate phrase for: 'Rename eSIM Cellular network">
     Rename eSIM profile
   </message>
-  <message name="IDS_OS_SETTINGS_TAG_INSTANT_MOBILE_NETWORKS" desc="Text for search result item which, when clicked, navigates the user to Instant Tethering settings (allows Chromebook to use mobile connection from phone).">
+  <message name="IDS_OS_SETTINGS_TAG_INSTANT_MOBILE_NETWORKS" desc="Text for search result item which, when clicked, navigates the user to Instant Tethering settings (allows Chromebook to use mobile connection from phone). Alternate phrase for: 'Hotspot'">
     Mobile networks
   </message>
+  <message name="IDS_OS_SETTINGS_TAG_INSTANT_MOBILE_NETWORKS_ALT1" desc="Text for search result item which, when clicked, navigates the user to Instant Tethering settings (allows Chromebook to use mobile connection from phone). Alternate phrase for: 'Mobile networks'">
+    Hotspot
+  </message>
   <message name="IDS_OS_SETTINGS_TAG_INSTANT_TETHERING_TURN_OFF" desc="Text for search result item which, when clicked, navigates the user to Instant Tethering settings (allows Chromebook to use mobile connection from phone), with a toggle to turn off the feature. Alternate phrase for: 'Disable Instant Tethering'">
     Turn off Instant Tethering
   </message>
diff --git a/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_INSTANT_MOBILE_NETWORKS_ALT1.png.sha1 b/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_INSTANT_MOBILE_NETWORKS_ALT1.png.sha1
new file mode 100644
index 0000000..d766190
--- /dev/null
+++ b/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_INSTANT_MOBILE_NETWORKS_ALT1.png.sha1
@@ -0,0 +1 @@
+c05a803cfbeec956685740cc60a9b5a5eda51489
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index d47b606fc1..173228b 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -4168,8 +4168,6 @@
       "resource_coordinator/tab_manager.h",
       "resource_coordinator/tab_manager_resource_coordinator_signal_observer.cc",
       "resource_coordinator/tab_manager_resource_coordinator_signal_observer.h",
-      "resource_coordinator/tab_manager_web_contents_data.cc",
-      "resource_coordinator/tab_manager_web_contents_data.h",
       "resource_coordinator/tab_metrics_logger.cc",
       "resource_coordinator/tab_metrics_logger.h",
       "resource_coordinator/usage_clock.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 11f7bf6..6dee8e0 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2868,8 +2868,6 @@
 constexpr char kWallpaperFastRefreshInternalName[] = "wallpaper-fast-refresh";
 constexpr char kWallpaperFullScreenPreviewInternalName[] =
     "wallpaper-fullscreen-preview";
-constexpr char kWallpaperGooglePhotosIntegrationInternalName[] =
-    "wallpaper-google-photos-integration";
 constexpr char kWallpaperPerDeskName[] = "per-desk-wallpaper";
 constexpr char kLibAssistantV2MigrationInternalName[] =
     "cros-libassistant-v2-migration";
@@ -7979,10 +7977,6 @@
      flag_descriptions::kWallpaperFullScreenPreviewName,
      flag_descriptions::kWallpaperFullScreenPreviewDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(ash::features::kWallpaperFullScreenPreview)},
-    {kWallpaperGooglePhotosIntegrationInternalName,
-     flag_descriptions::kWallpaperGooglePhotosIntegrationName,
-     flag_descriptions::kWallpaperGooglePhotosIntegrationDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(ash::features::kWallpaperGooglePhotosIntegration)},
     {kWallpaperPerDeskName, flag_descriptions::kWallpaperPerDeskName,
      flag_descriptions::kWallpaperPerDeskDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(ash::features::kWallpaperPerDesk)},
diff --git a/chrome/browser/android/autocomplete/OWNERS b/chrome/browser/android/autocomplete/OWNERS
new file mode 100644
index 0000000..5535cd2
--- /dev/null
+++ b/chrome/browser/android/autocomplete/OWNERS
@@ -0,0 +1 @@
+file://components/omnibox/OWNERS
diff --git a/chrome/browser/android/autocomplete/tab_matcher_android.cc b/chrome/browser/android/autocomplete/tab_matcher_android.cc
index 648123e..6942fec 100644
--- a/chrome/browser/android/autocomplete/tab_matcher_android.cc
+++ b/chrome/browser/android/autocomplete/tab_matcher_android.cc
@@ -4,10 +4,9 @@
 
 #include "chrome/browser/android/autocomplete/tab_matcher_android.h"
 
+#include "base/feature_list.h"
 #include "base/memory/raw_ptr.h"
 #include "base/metrics/histogram_macros.h"
-#include "content/public/browser/web_contents_user_data.h"
-
 #include "chrome/browser/android/tab_android.h"
 #include "chrome/browser/android/tab_android_user_data.h"
 #include "chrome/browser/flags/android/chrome_session_state.h"
@@ -17,8 +16,10 @@
 #include "chrome/browser/ui/android/tab_model/tab_model_list.h"
 #include "components/omnibox/browser/autocomplete_input.h"
 #include "components/omnibox/browser/autocomplete_match.h"
+#include "components/omnibox/common/omnibox_features.h"
 #include "components/search_engines/template_url_service.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_user_data.h"
 
 namespace {
 class AutocompleteClientTabAndroidUserData
@@ -34,11 +35,18 @@
   bool IsInitialized() const { return initialized_; }
 
   void UpdateStrippedURL(const GURL& url,
-                         const TemplateURLService* template_url_service) {
+                         const TemplateURLService* template_url_service,
+                         const bool keep_search_intent_params) {
     initialized_ = true;
     if (url.is_valid()) {
+      // Use a blank input as the stripped URL will be reused with other inputs.
+      // Also keep the search intent params. Otherwise, this can result in over
+      // triggering of the Switch to Tab action on plain-text suggestions for
+      // open entity SRPs, or vice versa, on entity suggestions for open
+      // plain-text SRPs.
       stripped_url_ = AutocompleteMatch::GURLToStrippedGURL(
-          url, AutocompleteInput(), template_url_service, std::u16string());
+          url, AutocompleteInput(), template_url_service, std::u16string(),
+          keep_search_intent_params);
     }
   }
 
@@ -69,9 +77,19 @@
   const AutocompleteInput empty_input;
   if (!input)
     input = &empty_input;
+
+  // Use a blank input as the stripped URL will be reused with other inputs.
+  // Also keep the search intent params. Otherwise, this can result in over
+  // triggering of the Switch to Tab action on plain-text suggestions for
+  // open entity SRPs, or vice versa, on entity suggestions for open plain-text
+  // SRPs.
+  const bool keep_search_intent_params = base::FeatureList::IsEnabled(
+      omnibox::kDisambiguateTabMatchingForEntitySuggestions);
   const GURL stripped_url = AutocompleteMatch::GURLToStrippedGURL(
-      url, *input, template_url_service_, std::u16string());
-  const auto all_tabs = GetAllHiddenAndNonCCTTabInfos();
+      url, *input, template_url_service_, std::u16string(),
+      keep_search_intent_params);
+  const auto all_tabs =
+      GetAllHiddenAndNonCCTTabInfos(keep_search_intent_params);
   return all_tabs.find(stripped_url) != all_tabs.end();
 }
 
@@ -82,12 +100,15 @@
   const AutocompleteInput empty_input;
   if (!input)
     input = &empty_input;
-  auto all_tabs = GetAllHiddenAndNonCCTTabInfos();
+
+  const bool keep_search_intent_params = base::FeatureList::IsEnabled(
+      omnibox::kDisambiguateTabMatchingForEntitySuggestions);
+  auto all_tabs = GetAllHiddenAndNonCCTTabInfos(keep_search_intent_params);
 
   for (auto& gurl_to_tab_info : *map) {
     const GURL stripped_url = AutocompleteMatch::GURLToStrippedGURL(
-        gurl_to_tab_info.first, *input, template_url_service_,
-        std::u16string());
+        gurl_to_tab_info.first, *input, template_url_service_, std::u16string(),
+        keep_search_intent_params);
     auto found_tab = all_tabs.find(stripped_url);
     if (found_tab != all_tabs.end()) {
       gurl_to_tab_info.second = found_tab->second;
@@ -95,8 +116,8 @@
   }
 }
 
-TabMatcher::GURLToTabInfoMap TabMatcherAndroid::GetAllHiddenAndNonCCTTabInfos()
-    const {
+TabMatcher::GURLToTabInfoMap TabMatcherAndroid::GetAllHiddenAndNonCCTTabInfos(
+    const bool keep_search_intent_params) const {
   using chrome::android::ActivityType;
   GURLToTabInfoMap tab_infos;
 
@@ -152,7 +173,8 @@
         AutocompleteClientTabAndroidUserData::FromTabAndroid(tab);
     DCHECK(user_data);
     if (!user_data->IsInitialized()) {
-      user_data->UpdateStrippedURL(tab->GetURL(), template_url_service_);
+      user_data->UpdateStrippedURL(tab->GetURL(), template_url_service_,
+                                   keep_search_intent_params);
     }
 
     const GURL& tab_stripped_url = user_data->GetStrippedURL();
diff --git a/chrome/browser/android/autocomplete/tab_matcher_android.h b/chrome/browser/android/autocomplete/tab_matcher_android.h
index 22941b47..8f26258 100644
--- a/chrome/browser/android/autocomplete/tab_matcher_android.h
+++ b/chrome/browser/android/autocomplete/tab_matcher_android.h
@@ -27,7 +27,8 @@
                         const AutocompleteInput* input) const override;
 
  private:
-  GURLToTabInfoMap GetAllHiddenAndNonCCTTabInfos() const;
+  GURLToTabInfoMap GetAllHiddenAndNonCCTTabInfos(
+      const bool keep_search_intent_params) const;
 
   const TemplateURLService* template_url_service_;
   raw_ptr<Profile> profile_;
diff --git a/chrome/browser/apps/app_service/publishers/borealis_apps.cc b/chrome/browser/apps/app_service/publishers/borealis_apps.cc
index ba6f837..bf4ea8b 100644
--- a/chrome/browser/apps/app_service/publishers/borealis_apps.cc
+++ b/chrome/browser/apps/app_service/publishers/borealis_apps.cc
@@ -141,9 +141,13 @@
       base::BindOnce(
           [](base::OnceCallback<void(bool)> callback,
              borealis::BorealisFeatures::AllowStatus allow_status) {
-            std::move(callback).Run(
-                allow_status ==
-                borealis::BorealisFeatures::AllowStatus::kAllowed);
+            bool allowed = allow_status ==
+                           borealis::BorealisFeatures::AllowStatus::kAllowed;
+            if (!allowed) {
+              LOG(WARNING) << "Borealis not allowed: "
+                           << static_cast<int>(allow_status);
+            }
+            std::move(callback).Run(allowed);
           },
           std::move(callback)));
 }
diff --git a/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.cc b/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.cc
index 6cc17666..64e20cca4 100644
--- a/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.cc
+++ b/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.cc
@@ -45,14 +45,14 @@
 
 bool ShouldAutoDisplayUi(
     const std::vector<IntentPickerAppInfo>& apps_for_picker,
-    content::NavigationHandle* navigation_handle) {
-  content::WebContents* web_contents = navigation_handle->GetWebContents();
+    NavigationInfo navigation_info) {
+  content::WebContents* web_contents = navigation_info.web_contents;
 
   if (web_contents->GetVisibility() == content::Visibility::HIDDEN) {
     return false;
   }
 
-  const GURL& url = navigation_handle->GetURL();
+  const GURL& url = navigation_info.url;
 
   // Disable Auto-display in the new Intent Picker UI unless it is specifically
   // re-enabled.
@@ -65,7 +65,7 @@
   if (InAppBrowser(web_contents))
     return false;
 
-  if (!ShouldOverrideUrlLoading(GetStartingGURL(navigation_handle), url))
+  if (!ShouldOverrideUrlLoading(navigation_info.starting_url, url))
     return false;
 
   Profile* profile =
@@ -99,10 +99,10 @@
 }
 
 PickerShowState GetPickerShowState(
-    content::NavigationHandle* navigation_handle,
+    NavigationInfo navigation_info,
     const std::vector<IntentPickerAppInfo>& apps_for_picker) {
-  return ShouldAutoDisplayUi(apps_for_picker, navigation_handle) &&
-                 IsNavigateFromLink(navigation_handle)
+  return ShouldAutoDisplayUi(apps_for_picker, navigation_info) &&
+                 navigation_info.is_navigate_from_link
              ? PickerShowState::kPopOut
              : PickerShowState::kOmnibox;
 }
@@ -120,18 +120,18 @@
 
 }  // namespace
 
-void MaybeShowIntentPickerBubble(content::NavigationHandle* navigation_handle,
+void MaybeShowIntentPickerBubble(NavigationInfo navigation_info,
                                  std::vector<IntentPickerAppInfo> apps) {
-  if (apps.empty() || GetPickerShowState(navigation_handle, apps) ==
-                          PickerShowState::kOmnibox) {
+  if (apps.empty() ||
+      GetPickerShowState(navigation_info, apps) == PickerShowState::kOmnibox) {
     return;
   }
 
   IntentHandlingMetrics::RecordIntentPickerIconEvent(
       IntentHandlingMetrics::IntentPickerIconEvent::kAutoPopOut);
 
-  content::WebContents* web_contents = navigation_handle->GetWebContents();
-  const GURL& url = navigation_handle->GetURL();
+  content::WebContents* web_contents = navigation_info.web_contents;
+  const GURL& url = navigation_info.url;
 
   IntentPickerTabHelper::LoadAppIcons(
       web_contents, std::move(apps),
diff --git a/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.h b/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.h
index 61b8ed0..eed1e6a 100644
--- a/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.h
+++ b/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.h
@@ -12,13 +12,19 @@
 #include "url/gurl.h"
 
 namespace content {
-class NavigationHandle;
 class WebContents;
 }  // namespace content
 
 namespace apps {
 
-void MaybeShowIntentPickerBubble(content::NavigationHandle* navigation_handle,
+struct NavigationInfo {
+  content::WebContents* web_contents;
+  GURL url;
+  GURL starting_url;
+  bool is_navigate_from_link;
+};
+
+void MaybeShowIntentPickerBubble(NavigationInfo navigation_info,
                                  std::vector<IntentPickerAppInfo> apps);
 
 // These enums are used to define the intent picker show state, whether the
diff --git a/chrome/browser/apps/intent_helper/intent_picker_helpers.cc b/chrome/browser/apps/intent_helper/intent_picker_helpers.cc
index 17ab1ed..566f70b 100644
--- a/chrome/browser/apps/intent_helper/intent_picker_helpers.cc
+++ b/chrome/browser/apps/intent_helper/intent_picker_helpers.cc
@@ -7,8 +7,10 @@
 #include <string>
 #include <utility>
 
+#include "base/functional/bind.h"
 #include "base/memory/weak_ptr.h"
 #include "base/notreached.h"
+#include "base/task/task_traits.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
@@ -32,6 +34,7 @@
 #include "chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.h"
 #include "chrome/browser/apps/intent_helper/metrics/intent_handling_metrics.h"
 #elif BUILDFLAG(IS_MAC)
+#include "base/task/thread_pool.h"
 #include "chrome/browser/apps/intent_helper/mac_intent_picker_helpers.h"
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
@@ -39,9 +42,10 @@
 
 namespace {
 
-std::vector<IntentPickerAppInfo> FindAppsForUrl(
+void AppendAppsForUrlSync(
     content::WebContents* web_contents,
     const GURL& url,
+    base::OnceCallback<void(std::vector<IntentPickerAppInfo>)> callback,
     std::vector<IntentPickerAppInfo> apps) {
 #if BUILDFLAG(IS_MAC)
   // On the Mac, if there is a Universal Link, it goes first.
@@ -64,7 +68,38 @@
                        ui::ImageModel(), update.AppId(), update.Name());
         });
   }
-  return apps;
+
+  std::move(callback).Run(std::move(apps));
+}
+
+void FindAppsForUrl(
+    content::WebContents* web_contents,
+    const GURL& url,
+    base::OnceCallback<void(std::vector<IntentPickerAppInfo>)> callback) {
+  auto append_apps =
+      [](base::WeakPtr<content::WebContents> web_contents,
+         IntentPickerTabHelper* helper, int commit_count, const GURL& url,
+         base::OnceCallback<void(std::vector<IntentPickerAppInfo>)> callback,
+         std::vector<IntentPickerAppInfo> apps) {
+        if (!web_contents)
+          return;
+        if (helper->commit_count() != commit_count)
+          return;
+
+        AppendAppsForUrlSync(web_contents.get(), url, std::move(callback),
+                             std::move(apps));
+      };
+
+  // TODO(crbug.com/1236141): Move the Mac intent code to be here, called async.
+
+  IntentPickerTabHelper* helper =
+      IntentPickerTabHelper::FromWebContents(web_contents);
+  int commit_count = helper->commit_count();
+
+  base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
+      FROM_HERE, base::BindOnce(append_apps, web_contents->GetWeakPtr(), helper,
+                                commit_count, url, std::move(callback),
+                                std::vector<IntentPickerAppInfo>()));
 }
 
 void LaunchAppFromIntentPicker(content::WebContents* web_contents,
@@ -138,43 +173,28 @@
       base::BindOnce(&OnIntentPickerClosed, web_contents->GetWeakPtr(), url));
 }
 
-std::vector<IntentPickerAppInfo> GetAppsForIntentPicker(
-    content::WebContents* web_contents) {
-  std::vector<IntentPickerAppInfo> apps = {};
-  if (!ShouldCheckAppsForUrl(web_contents))
-    return apps;
+void GetAppsForIntentPicker(
+    content::WebContents* web_contents,
+    base::OnceCallback<void(std::vector<IntentPickerAppInfo>)> callback) {
+  if (!ShouldCheckAppsForUrl(web_contents)) {
+    std::move(callback).Run({});
+    return;
+  }
 
   Profile* profile =
       Profile::FromBrowserContext(web_contents->GetBrowserContext());
-  if (!AppServiceProxyFactory::IsAppServiceAvailableForProfile(profile))
-    return apps;
+  if (!AppServiceProxyFactory::IsAppServiceAvailableForProfile(profile)) {
+    std::move(callback).Run({});
+    return;
+  }
 
-  const GURL& url = web_contents->GetLastCommittedURL();
-  apps = FindAppsForUrl(web_contents, url, std::move(apps));
-  return apps;
+  FindAppsForUrl(web_contents, web_contents->GetLastCommittedURL(),
+                 std::move(callback));
 }
 
-}  // namespace
-
-// for chromeos, this should apply when navigation is not deferred for pwa only
-// case also when navigation deferred and then resumed
-void MaybeShowIntentPicker(content::NavigationHandle* navigation_handle) {
-  content::WebContents* web_contents = navigation_handle->GetWebContents();
-  auto apps = GetAppsForIntentPicker(web_contents);
-  IntentPickerTabHelper::FromWebContents(web_contents)->ShowIconForApps(apps);
-#if BUILDFLAG(IS_CHROMEOS)
-  MaybeShowIntentPickerBubble(navigation_handle, std::move(apps));
-#endif  // BUILDFLAG(IS_CHROMEOS)
-}
-
-void MaybeShowIntentPicker(content::WebContents* web_contents) {
-  IntentPickerTabHelper::FromWebContents(web_contents)
-      ->ShowIconForApps(GetAppsForIntentPicker(web_contents));
-}
-
-void ShowIntentPickerOrLaunchApp(content::WebContents* web_contents,
-                                 const GURL& url) {
-  std::vector<IntentPickerAppInfo> apps = FindAppsForUrl(web_contents, url, {});
+void ShowIntentPickerOrLaunchAppImpl(content::WebContents* web_contents,
+                                     const GURL& url,
+                                     std::vector<IntentPickerAppInfo> apps) {
   if (apps.empty())
     return;
 
@@ -210,6 +230,75 @@
       base::BindOnce(&OnAppIconsLoaded, web_contents, url));
 }
 
+}  // namespace
+
+void MaybeShowIntentPicker(content::NavigationHandle* navigation_handle) {
+  content::WebContents* web_contents = navigation_handle->GetWebContents();
+  IntentPickerTabHelper* helper =
+      IntentPickerTabHelper::FromWebContents(web_contents);
+  int commit_count = helper->commit_count();
+
+  auto task = [](base::WeakPtr<content::WebContents> web_contents,
+#if BUILDFLAG(IS_CHROMEOS)
+                 NavigationInfo navigation_info,
+#endif  // BUILDFLAG(IS_CHROMEOS)
+                 IntentPickerTabHelper* helper, int commit_count,
+                 std::vector<IntentPickerAppInfo> apps) {
+    if (!web_contents)
+      return;
+    if (helper->commit_count() != commit_count)
+      return;
+
+    helper->ShowIconForApps(apps);
+#if BUILDFLAG(IS_CHROMEOS)
+    MaybeShowIntentPickerBubble(navigation_info, std::move(apps));
+#endif  // BUILDFLAG(IS_CHROMEOS)
+  };
+
+#if BUILDFLAG(IS_CHROMEOS)
+  NavigationInfo navigation_info = {
+      .web_contents = web_contents,
+      .url = navigation_handle->GetURL(),
+      .starting_url = GetStartingGURL(navigation_handle),
+      .is_navigate_from_link = IsNavigateFromLink(navigation_handle)};
+#endif  // BUILDFLAG(IS_CHROMEOS)
+
+  GetAppsForIntentPicker(web_contents,
+                         base::BindOnce(task, web_contents->GetWeakPtr(),
+#if BUILDFLAG(IS_CHROMEOS)
+                                        navigation_info,
+#endif  // BUILDFLAG(IS_CHROMEOS)
+                                        helper, commit_count));
+}
+
+void MaybeShowIntentPicker(content::WebContents* web_contents) {
+  IntentPickerTabHelper* helper =
+      IntentPickerTabHelper::FromWebContents(web_contents);
+  int commit_count = helper->commit_count();
+
+  auto task = [](base::WeakPtr<content::WebContents> web_contents,
+                 IntentPickerTabHelper* helper, int commit_count,
+                 std::vector<IntentPickerAppInfo> apps) {
+    if (!web_contents)
+      return;
+    if (helper->commit_count() != commit_count)
+      return;
+
+    helper->ShowIconForApps(apps);
+  };
+
+  GetAppsForIntentPicker(
+      web_contents,
+      base::BindOnce(task, web_contents->GetWeakPtr(), helper, commit_count));
+}
+
+void ShowIntentPickerOrLaunchApp(content::WebContents* web_contents,
+                                 const GURL& url) {
+  FindAppsForUrl(
+      web_contents, url,
+      base::BindOnce(&ShowIntentPickerOrLaunchAppImpl, web_contents, url));
+}
+
 bool IntentPickerPwaPersistenceEnabled() {
 #if BUILDFLAG(IS_CHROMEOS)
   return true;
diff --git a/chrome/browser/ash/BUILD.gn b/chrome/browser/ash/BUILD.gn
index 314e989ab..1d17e5f 100644
--- a/chrome/browser/ash/BUILD.gn
+++ b/chrome/browser/ash/BUILD.gn
@@ -2376,6 +2376,8 @@
     "policy/reporting/metrics_reporting/audio/audio_events_observer.h",
     "policy/reporting/metrics_reporting/cros_healthd_metric_sampler.cc",
     "policy/reporting/metrics_reporting/cros_healthd_metric_sampler.h",
+    "policy/reporting/metrics_reporting/cros_healthd_sampler_handlers/cros_healthd_audio_sampler_handler.cc",
+    "policy/reporting/metrics_reporting/cros_healthd_sampler_handlers/cros_healthd_audio_sampler_handler.h",
     "policy/reporting/metrics_reporting/cros_healthd_sampler_handlers/cros_healthd_sampler_handler.h",
     "policy/reporting/metrics_reporting/cros_reporting_settings.cc",
     "policy/reporting/metrics_reporting/cros_reporting_settings.h",
diff --git a/chrome/browser/ash/file_manager/file_tasks.cc b/chrome/browser/ash/file_manager/file_tasks.cc
index 57b79e8..9b35f20 100644
--- a/chrome/browser/ash/file_manager/file_tasks.cc
+++ b/chrome/browser/ash/file_manager/file_tasks.cc
@@ -478,8 +478,7 @@
       // TODO(b/247038054) Add user preference to decide whether or not the
       // dialog should be shown.
       return ash::cloud_upload::UploadAndOpen(
-          profile, file_urls, ash::cloud_upload::CloudProvider::kGoogleDrive,
-          /*show_dialog=*/false);
+          profile, file_urls, ash::cloud_upload::CloudProvider::kGoogleDrive);
     }
   } else {
     UMA_HISTOGRAM_ENUMERATION(kDriveErrorMetricName,
@@ -575,8 +574,7 @@
       // dialog should be shown.
       LOG(ERROR) << "File can be moved to ODFS";
       return ash::cloud_upload::UploadAndOpen(
-          profile, file_urls, ash::cloud_upload::CloudProvider::kOneDrive,
-          /*show_dialog=*/false);
+          profile, file_urls, ash::cloud_upload::CloudProvider::kOneDrive);
     }
   } else {
     LOG(ERROR) << "ODFS not available/mounted";
@@ -593,6 +591,7 @@
 
 void RegisterProfilePrefs(PrefRegistrySimple* registry) {
   registry->RegisterDictionaryPref(prefs::kDefaultHandlersForFileExtensions);
+  registry->RegisterBooleanPref(prefs::kOfficeSetupComplete, false);
 }
 
 // Converts a string to a TaskType. Returns TASK_TYPE_UNKNOWN on error.
@@ -1253,4 +1252,12 @@
        "vnd.openxmlformats-officedocument.presentationml.presentation"});
 }
 
+void SetOfficeSetupComplete(Profile* profile, bool complete) {
+  profile->GetPrefs()->SetBoolean(prefs::kOfficeSetupComplete, complete);
+}
+
+bool OfficeSetupComplete(Profile* profile) {
+  return profile->GetPrefs()->GetBoolean(prefs::kOfficeSetupComplete);
+}
+
 }  // namespace file_manager::file_tasks
diff --git a/chrome/browser/ash/file_manager/file_tasks.h b/chrome/browser/ash/file_manager/file_tasks.h
index 5774cda..c9fa386 100644
--- a/chrome/browser/ash/file_manager/file_tasks.h
+++ b/chrome/browser/ash/file_manager/file_tasks.h
@@ -380,6 +380,13 @@
 void SetExcelFileHandler(Profile* profile, const std::string& action_id);
 void SetPowerPointFileHandler(Profile* profile, const std::string& action_id);
 
+// TODO(petermarshall): Move these to a new file office_file_tasks.cc/h
+// Sets the user preference storing whether the setup flow for office files has
+// ever been completed.
+void SetOfficeSetupComplete(Profile* profile, bool complete = true);
+// Whether or not the setup flow for office files has ever been completed.
+bool OfficeSetupComplete(Profile* profile);
+
 }  // namespace file_manager::file_tasks
 
 #endif  // CHROME_BROWSER_ASH_FILE_MANAGER_FILE_TASKS_H_
diff --git a/chrome/browser/ash/input_method/autocorrect_manager.cc b/chrome/browser/ash/input_method/autocorrect_manager.cc
index d5e45ca..8ba827e6 100644
--- a/chrome/browser/ash/input_method/autocorrect_manager.cc
+++ b/chrome/browser/ash/input_method/autocorrect_manager.cc
@@ -266,20 +266,20 @@
   if (str1.size() > str2.size()) {
     return GetLevenshteinDistance(str2, str1);
   }
-  if (ssize(str1) + kMaxEditDistance < ssize(str2)) {
+  if (str1.size() + static_cast<size_t>(kMaxEditDistance) < str2.size()) {
     return kMaxEditDistance;
   }
 
   std::vector<int> row(str1.size() + 1);
-  for (int i = 0; i < ssize(row); ++i) {
-    row[i] = i;
+  for (size_t i = 0; i < row.size(); ++i) {
+    row[i] = static_cast<int>(i);
   }
 
-  for (int i = 0; i < ssize(str2); ++i) {
+  for (size_t i = 0; i < str2.size(); ++i) {
     ++row[0];
-    int previous = i;
+    int previous = static_cast<int>(i);
     bool under_cutoff = false;
-    for (int j = 0; j < ssize(str1); ++j) {
+    for (size_t j = 0; j < str1.size(); ++j) {
       int old_row = row[j + 1];
       int cost = str2[i] == str1[j] ? 0 : 1;
       row[j + 1] = std::min(std::min(row[j], row[j + 1]) + 1, previous + cost);
diff --git a/chrome/browser/ash/login/users/avatar/user_image_manager_impl.cc b/chrome/browser/ash/login/users/avatar/user_image_manager_impl.cc
index d857cd86..36fd626 100644
--- a/chrome/browser/ash/login/users/avatar/user_image_manager_impl.cc
+++ b/chrome/browser/ash/login/users/avatar/user_image_manager_impl.cc
@@ -291,12 +291,9 @@
                                        weak_factory_.GetWeakPtr(), true));
       }
     } else {
-      gfx::ImageSkia default_image =
-          default_user_image::GetDefaultImageDeprecated(image_index_);
       std::unique_ptr<user_manager::UserImage> user_image(
-          user_manager::UserImage::CreateAndEncode(
-              default_image, user_manager::UserImage::ChooseImageFormat(
-                                 *default_image.bitmap())));
+          new user_manager::UserImage(
+              default_user_image::GetDefaultImageDeprecated(image_index_)));
       UpdateUser(std::move(user_image));
       NotifyJobDone();
     }
@@ -333,12 +330,9 @@
         image_url_, base::BindOnce(&Job::OnLoadImageDone,
                                    weak_factory_.GetWeakPtr(), true));
   } else {
-    gfx::ImageSkia default_image =
-        default_user_image::GetDefaultImageDeprecated(image_index_);
     std::unique_ptr<user_manager::UserImage> user_image(
-        user_manager::UserImage::CreateAndEncode(
-            default_image, user_manager::UserImage::ChooseImageFormat(
-                               *default_image.bitmap())));
+        new user_manager::UserImage(
+            default_user_image::GetDefaultImageDeprecated(image_index_)));
 
     UpdateUser(std::move(user_image));
     UpdateLocalState();
diff --git a/chrome/browser/ash/policy/reporting/metrics_reporting/cros_healthd_metric_sampler.cc b/chrome/browser/ash/policy/reporting/metrics_reporting/cros_healthd_metric_sampler.cc
index b9fb535..e184813 100644
--- a/chrome/browser/ash/policy/reporting/metrics_reporting/cros_healthd_metric_sampler.cc
+++ b/chrome/browser/ash/policy/reporting/metrics_reporting/cros_healthd_metric_sampler.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/ash/policy/reporting/metrics_reporting/cros_healthd_metric_sampler.h"
+#include "chrome/browser/ash/policy/reporting/metrics_reporting/cros_healthd_sampler_handlers/cros_healthd_audio_sampler_handler.h"
 
 #include "base/logging.h"
 #include "chromeos/ash/services/cros_healthd/public/cpp/service_connection.h"
@@ -225,47 +226,6 @@
   std::move(callback).Run(metric_data);
 }
 
-void HandleAudioResult(OptionalMetricCallback callback,
-                       CrosHealthdMetricSampler::MetricType metric_type,
-                       cros_healthd::TelemetryInfoPtr result) {
-  absl::optional<MetricData> metric_data;
-  const auto& audio_result = result->audio_result;
-
-  if (!audio_result.is_null()) {
-    switch (audio_result->which()) {
-      case cros_healthd::AudioResult::Tag::kError: {
-        DVLOG(1) << "CrosHealthD: Error getting audio telemetry: "
-                 << audio_result->get_error()->msg;
-        break;
-      }
-
-      case cros_healthd::AudioResult::Tag::kAudioInfo: {
-        const auto& audio_info = audio_result->get_audio_info();
-        if (audio_info.is_null()) {
-          DVLOG(1) << "CrosHealthD: No audio info received";
-          break;
-        }
-
-        if (metric_type == CrosHealthdMetricSampler::MetricType::kTelemetry) {
-          metric_data = absl::make_optional<MetricData>();
-          auto* const audio_info_out =
-              metric_data->mutable_telemetry_data()->mutable_audio_telemetry();
-          audio_info_out->set_output_mute(audio_info->output_mute);
-          audio_info_out->set_input_mute(audio_info->input_mute);
-          audio_info_out->set_output_volume(audio_info->output_volume);
-          audio_info_out->set_output_device_name(
-              audio_info->output_device_name);
-          audio_info_out->set_input_gain(audio_info->input_gain);
-          audio_info_out->set_input_device_name(audio_info->input_device_name);
-        }
-        break;
-      }
-    }
-  }
-
-  std::move(callback).Run(std::move(metric_data));
-}
-
 void HandleMemoryResult(OptionalMetricCallback callback,
                         CrosHealthdMetricSampler::MetricType metric_type,
                         cros_healthd::TelemetryInfoPtr result) {
@@ -532,7 +492,8 @@
   DCHECK(result);
   switch (probe_category) {
     case cros_healthd::ProbeCategoryEnum::kAudio: {
-      HandleAudioResult(std::move(callback), metric_type, std::move(result));
+      CrosHealthdAudioSamplerHandler handler = CrosHealthdAudioSamplerHandler();
+      handler.HandleResult(std::move(result), std::move(callback));
       break;
     }
     case cros_healthd::ProbeCategoryEnum::kBus: {
diff --git a/chrome/browser/ash/policy/reporting/metrics_reporting/cros_healthd_sampler_handlers/cros_healthd_audio_sampler_handler.cc b/chrome/browser/ash/policy/reporting/metrics_reporting/cros_healthd_sampler_handlers/cros_healthd_audio_sampler_handler.cc
new file mode 100644
index 0000000..dadfe9e
--- /dev/null
+++ b/chrome/browser/ash/policy/reporting/metrics_reporting/cros_healthd_sampler_handlers/cros_healthd_audio_sampler_handler.cc
@@ -0,0 +1,59 @@
+// Copyright 2021 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ash/policy/reporting/metrics_reporting/cros_healthd_sampler_handlers/cros_healthd_audio_sampler_handler.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "components/reporting/metrics/sampler.h"
+#include "components/reporting/proto/synced/metric_data.pb.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace reporting {
+
+namespace cros_healthd = ::ash::cros_healthd::mojom;
+
+CrosHealthdAudioSamplerHandler::~CrosHealthdAudioSamplerHandler() = default;
+
+void CrosHealthdAudioSamplerHandler::HandleResult(
+    cros_healthd::TelemetryInfoPtr result,
+    OptionalMetricCallback callback) const {
+  absl::optional<MetricData> metric_data;
+  const auto& audio_result = result->audio_result;
+
+  if (!audio_result.is_null()) {
+    switch (audio_result->which()) {
+      case cros_healthd::AudioResult::Tag::kError: {
+        DVLOG(1) << "CrosHealthD: Error getting audio telemetry: "
+                 << audio_result->get_error()->msg;
+        break;
+      }
+
+      case cros_healthd::AudioResult::Tag::kAudioInfo: {
+        const auto& audio_info = audio_result->get_audio_info();
+        if (audio_info.is_null()) {
+          DVLOG(1) << "CrosHealthD: No audio info received";
+          break;
+        }
+
+        metric_data = absl::make_optional<MetricData>();
+        auto* const audio_info_out =
+            metric_data->mutable_telemetry_data()->mutable_audio_telemetry();
+        audio_info_out->set_output_mute(audio_info->output_mute);
+        audio_info_out->set_input_mute(audio_info->input_mute);
+        audio_info_out->set_output_volume(audio_info->output_volume);
+        audio_info_out->set_output_device_name(audio_info->output_device_name);
+        audio_info_out->set_input_gain(audio_info->input_gain);
+        audio_info_out->set_input_device_name(audio_info->input_device_name);
+
+        break;
+      }
+    }
+  }
+
+  std::move(callback).Run(std::move(metric_data));
+}
+
+}  // namespace reporting
diff --git a/chrome/browser/ash/policy/reporting/metrics_reporting/cros_healthd_sampler_handlers/cros_healthd_audio_sampler_handler.h b/chrome/browser/ash/policy/reporting/metrics_reporting/cros_healthd_sampler_handlers/cros_healthd_audio_sampler_handler.h
new file mode 100644
index 0000000..36e6dfae
--- /dev/null
+++ b/chrome/browser/ash/policy/reporting/metrics_reporting/cros_healthd_sampler_handlers/cros_healthd_audio_sampler_handler.h
@@ -0,0 +1,36 @@
+// Copyright 2021 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ASH_POLICY_REPORTING_METRICS_REPORTING_CROS_HEALTHD_SAMPLER_HANDLERS_CROS_HEALTHD_AUDIO_SAMPLER_HANDLER_H_
+#define CHROME_BROWSER_ASH_POLICY_REPORTING_METRICS_REPORTING_CROS_HEALTHD_SAMPLER_HANDLERS_CROS_HEALTHD_AUDIO_SAMPLER_HANDLER_H_
+
+#include "chrome/browser/ash/policy/reporting/metrics_reporting/cros_healthd_sampler_handlers/cros_healthd_sampler_handler.h"
+#include "chromeos/ash/services/cros_healthd/public/mojom/cros_healthd_probe.mojom.h"
+#include "components/reporting/metrics/sampler.h"
+
+namespace reporting {
+
+namespace cros_healthd = ::ash::cros_healthd::mojom;
+
+// Class that handles the resulting data after probing the croshealthd for the
+// Audio category.
+class CrosHealthdAudioSamplerHandler : public CrosHealthdSamplerHandler {
+ public:
+  CrosHealthdAudioSamplerHandler() = default;
+
+  CrosHealthdAudioSamplerHandler(const CrosHealthdAudioSamplerHandler&) =
+      delete;
+  CrosHealthdAudioSamplerHandler& operator=(
+      const CrosHealthdAudioSamplerHandler&) = delete;
+
+  ~CrosHealthdAudioSamplerHandler() override;
+
+  // HandleResult converts |result| to MetricData.
+  void HandleResult(cros_healthd::TelemetryInfoPtr result,
+                    OptionalMetricCallback callback) const override;
+};
+
+}  // namespace reporting
+
+#endif  // CHROME_BROWSER_ASH_POLICY_REPORTING_METRICS_REPORTING_CROS_HEALTHD_SAMPLER_HANDLERS_CROS_HEALTHD_AUDIO_SAMPLER_HANDLER_H_
diff --git a/chrome/browser/ash/web_applications/OWNERS b/chrome/browser/ash/web_applications/OWNERS
index b79b57df..9f0105d 100644
--- a/chrome/browser/ash/web_applications/OWNERS
+++ b/chrome/browser/ash/web_applications/OWNERS
@@ -9,5 +9,6 @@
 per-file crosh*=file://chromeos/TERMINAL_OWNERS
 per-file diagnostics*=file://ash/webui/diagnostics_ui/OWNERS
 per-file file_manager*=file://ash/webui/file_manager/OWNERS
+per-file files_internals*=file://ash/webui/file_manager/OWNERS
 per-file terminal*=file://chromeos/TERMINAL_OWNERS
 per-file eche*=file://ash/webui/eche_app_ui/OWNERS
diff --git a/chrome/browser/ash/web_applications/files_internals_ui_delegate.cc b/chrome/browser/ash/web_applications/files_internals_ui_delegate.cc
index 93db820d..a5974dd 100644
--- a/chrome/browser/ash/web_applications/files_internals_ui_delegate.cc
+++ b/chrome/browser/ash/web_applications/files_internals_ui_delegate.cc
@@ -6,6 +6,7 @@
 
 #include "base/values.h"
 #include "chrome/browser/ash/file_manager/file_manager_pref_names.h"
+#include "chrome/browser/ash/file_manager/file_tasks.h"
 #include "chrome/browser/ash/fusebox/fusebox_server.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/prefs/pref_service.h"
@@ -42,3 +43,15 @@
         file_manager::prefs::kSmbfsEnableVerboseLogging, enabled);
   }
 }
+
+bool ChromeFilesInternalsUIDelegate::GetOfficeSetupComplete() const {
+  Profile* profile = Profile::FromWebUI(web_ui_);
+  return profile && file_manager::file_tasks::OfficeSetupComplete(profile);
+}
+
+void ChromeFilesInternalsUIDelegate::SetOfficeSetupComplete(bool complete) {
+  Profile* profile = Profile::FromWebUI(web_ui_);
+  if (profile) {
+    file_manager::file_tasks::SetOfficeSetupComplete(profile, complete);
+  }
+}
diff --git a/chrome/browser/ash/web_applications/files_internals_ui_delegate.h b/chrome/browser/ash/web_applications/files_internals_ui_delegate.h
index 367edcc..44e3b297e 100644
--- a/chrome/browser/ash/web_applications/files_internals_ui_delegate.h
+++ b/chrome/browser/ash/web_applications/files_internals_ui_delegate.h
@@ -27,6 +27,9 @@
   bool GetSmbfsEnableVerboseLogging() const override;
   void SetSmbfsEnableVerboseLogging(bool enabled) override;
 
+  bool GetOfficeSetupComplete() const override;
+  void SetOfficeSetupComplete(bool complete) override;
+
  private:
   raw_ptr<content::WebUI> web_ui_;  // Owns |this|.
 };
diff --git a/chrome/browser/ash/web_applications/personalization_app/personalization_app_ambient_provider_impl.cc b/chrome/browser/ash/web_applications/personalization_app/personalization_app_ambient_provider_impl.cc
index 8aa4d07..6b452a6 100644
--- a/chrome/browser/ash/web_applications/personalization_app/personalization_app_ambient_provider_impl.cc
+++ b/chrome/browser/ash/web_applications/personalization_app/personalization_app_ambient_provider_impl.cc
@@ -176,7 +176,7 @@
     case (ash::AmbientModeTopicSource::kGooglePhotos): {
       ash::PersonalAlbum* target_personal_album = FindPersonalAlbumById(id);
       if (!target_personal_album) {
-        mojo::ReportBadMessage("Invalid album id.");
+        ambient_receiver_.ReportBadMessage("Invalid album id.");
         return;
       }
       target_personal_album->selected = selected;
@@ -214,7 +214,7 @@
       // based on the selections.
       auto* art_setting = FindArtAlbumById(id);
       if (!art_setting || !art_setting->visible) {
-        mojo::ReportBadMessage("Invalid album id.");
+        ambient_receiver_.ReportBadMessage("Invalid album id.");
         return;
       }
       art_setting->enabled = selected;
diff --git a/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl.cc b/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl.cc
index fdb9e1b..535bdd01 100644
--- a/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl.cc
+++ b/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl.cc
@@ -265,16 +265,6 @@
 void PersonalizationAppWallpaperProviderImpl::FetchGooglePhotosAlbums(
     const absl::optional<std::string>& resume_token,
     FetchGooglePhotosAlbumsCallback callback) {
-  if (!ash::features::IsWallpaperGooglePhotosIntegrationEnabled()) {
-    mojo::ReportBadMessage(
-        "Cannot call `FetchGooglePhotosAlbums()` without Google Photos "
-        "Wallpaper integration enabled.");
-    std::move(callback).Run(
-        ash::personalization_app::mojom::FetchGooglePhotosAlbumsResponse::New(
-            absl::nullopt, absl::nullopt));
-    return;
-  }
-
   if (!is_google_photos_enterprise_enabled_) {
     mojo::ReportBadMessage(
         "Cannot call `FetchGooglePhotosAlbums()` without confirming that the "
@@ -296,7 +286,7 @@
 
 void PersonalizationAppWallpaperProviderImpl::FetchGooglePhotosEnabled(
     FetchGooglePhotosEnabledCallback callback) {
-  if (!ash::features::IsWallpaperGooglePhotosIntegrationEnabled()) {
+  if (!IsEligibleForGooglePhotos()) {
     mojo::ReportBadMessage(
         "Cannot call `FetchGooglePhotosEnabled()` without Google Photos "
         "Wallpaper integration enabled.");
@@ -322,16 +312,6 @@
     const absl::optional<std::string>& album_id,
     const absl::optional<std::string>& resume_token,
     FetchGooglePhotosPhotosCallback callback) {
-  if (!ash::features::IsWallpaperGooglePhotosIntegrationEnabled()) {
-    mojo::ReportBadMessage(
-        "Cannot call `FetchGooglePhotosPhotos()` without Google Photos "
-        "Wallpaper integration enabled.");
-    std::move(callback).Run(
-        ash::personalization_app::mojom::FetchGooglePhotosPhotosResponse::New(
-            absl::nullopt, absl::nullopt));
-    return;
-  }
-
   if (!is_google_photos_enterprise_enabled_) {
     mojo::ReportBadMessage(
         "Cannot call `FetchGooglePhotosPhotos()` without confirming that the "
diff --git a/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl_unittest.cc b/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl_unittest.cc
index 9b41e7e..c1c47a1 100644
--- a/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl_unittest.cc
+++ b/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl_unittest.cc
@@ -223,25 +223,11 @@
 
 }  // namespace
 
-class PersonalizationAppWallpaperProviderImplTest
-    : public testing::Test,
-      public testing::WithParamInterface<bool /* google_photos_enabled */> {
+class PersonalizationAppWallpaperProviderImplTest : public testing::Test {
  public:
   PersonalizationAppWallpaperProviderImplTest()
       : scoped_user_manager_(std::make_unique<ash::FakeChromeUserManager>()),
-        profile_manager_(TestingBrowserProcess::GetGlobal()) {
-    std::vector<base::test::FeatureRef> disabled_features;
-    std::vector<base::test::FeatureRef> enabled_features;
-
-    // Conditionally enable/disable Google Photos integration based on test
-    // parameterization.
-    (GooglePhotosEnabled() ? enabled_features : disabled_features)
-        .push_back(ash::features::kWallpaperGooglePhotosIntegration);
-
-    // Note: `scoped_feature_list_` should be initialized before `SetUp()`
-    // (see crbug.com/846380).
-    scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features);
-  }
+        profile_manager_(TestingBrowserProcess::GetGlobal()) {}
 
   PersonalizationAppWallpaperProviderImplTest(
       const PersonalizationAppWallpaperProviderImplTest&) = delete;
@@ -293,10 +279,6 @@
         {image_info.asset_id, image_info});
   }
 
-  // Returns true if the test should run with the Google Photos Wallpaper
-  // integration enabled, false otherwise.
-  bool GooglePhotosEnabled() const { return GetParam(); }
-
   TestWallpaperController* test_wallpaper_controller() {
     return &test_wallpaper_controller_;
   }
@@ -360,11 +342,7 @@
   std::unique_ptr<PersonalizationAppWallpaperProviderImpl> wallpaper_provider_;
 };
 
-INSTANTIATE_TEST_SUITE_P(All,
-                         PersonalizationAppWallpaperProviderImplTest,
-                         /*google_photos_enabled=*/::testing::Values(false));
-
-TEST_P(PersonalizationAppWallpaperProviderImplTest, SelectWallpaper) {
+TEST_F(PersonalizationAppWallpaperProviderImplTest, SelectWallpaper) {
   test_wallpaper_controller()->ClearCounts();
 
   auto image_info = GetDefaultImageInfo();
@@ -390,7 +368,7 @@
       test_wallpaper_controller()->wallpaper_info().value());
 }
 
-TEST_P(PersonalizationAppWallpaperProviderImplTest, PreviewWallpaper) {
+TEST_F(PersonalizationAppWallpaperProviderImplTest, PreviewWallpaper) {
   test_wallpaper_controller()->ClearCounts();
 
   auto image_info = GetDefaultImageInfo();
@@ -416,7 +394,7 @@
       test_wallpaper_controller()->wallpaper_info().value());
 }
 
-TEST_P(PersonalizationAppWallpaperProviderImplTest,
+TEST_F(PersonalizationAppWallpaperProviderImplTest,
        ObserveWallpaperFiresWhenBound) {
   test_wallpaper_controller()->ShowWallpaperImage(
       CreateSolidImageSkia(/*width=*/1, /*height=*/1, SK_ColorBLACK));
@@ -449,7 +427,7 @@
             current->layout);
 }
 
-TEST_P(PersonalizationAppWallpaperProviderImplTest, SetCurrentWallpaperLayout) {
+TEST_F(PersonalizationAppWallpaperProviderImplTest, SetCurrentWallpaperLayout) {
   auto* ctrl = test_wallpaper_controller();
 
   EXPECT_EQ(ctrl->update_current_wallpaper_layout_count(), 0);
@@ -463,7 +441,7 @@
   EXPECT_EQ(ctrl->update_current_wallpaper_layout_layout(), layout);
 }
 
-TEST_P(PersonalizationAppWallpaperProviderImplTest,
+TEST_F(PersonalizationAppWallpaperProviderImplTest,
        CallsMaybeStartHatsTimerOnDestruction) {
   // Insert a wallpaper image info to indicate that the user opened the
   // wallpaper app and requested wallpapers.
@@ -476,7 +454,7 @@
   ResetWallpaperProvider();
 }
 
-TEST_P(PersonalizationAppWallpaperProviderImplTest,
+TEST_F(PersonalizationAppWallpaperProviderImplTest,
        DoesNotCallMaybeStartHatsTimerIfNoWallpaperFetched) {
   EXPECT_CALL(*MockPersonalizationAppManager(),
               MaybeStartHatsTimer(HatsSurveyType::kWallpaper))
@@ -485,7 +463,7 @@
   ResetWallpaperProvider();
 }
 
-TEST_P(PersonalizationAppWallpaperProviderImplTest, GetWallpaperAsJpegBytes) {
+TEST_F(PersonalizationAppWallpaperProviderImplTest, GetWallpaperAsJpegBytes) {
   test_wallpaper_controller()->ShowWallpaperImage(
       CreateSolidImageSkia(/*width=*/1, /*height=*/1, SK_ColorRED));
 
@@ -511,7 +489,7 @@
   EXPECT_TRUE(expected_jpeg_bytes->Equals(jpeg_bytes));
 }
 
-TEST_P(PersonalizationAppWallpaperProviderImplTest,
+TEST_F(PersonalizationAppWallpaperProviderImplTest,
        SetDailyRefreshCollectionId) {
   const std::string collection_id = "collection_id";
 
@@ -544,14 +522,12 @@
                 profile())));
 
     EXPECT_CALL(*google_photos_enabled_fetcher, AddRequestAndStartIfNecessary)
-        .Times(GooglePhotosEnabled() ? num_fetches : 0);
+        .Times(num_fetches);
 
     for (size_t i = 0; i < num_fetches; ++i) {
       wallpaper_provider_remote()->get()->FetchGooglePhotosEnabled(
-          base::BindLambdaForTesting([this](GooglePhotosEnablementState state) {
-            EXPECT_EQ(state, GooglePhotosEnabled()
-                                 ? GooglePhotosEnablementState::kEnabled
-                                 : GooglePhotosEnablementState::kError);
+          base::BindLambdaForTesting([](GooglePhotosEnablementState state) {
+            EXPECT_EQ(state, GooglePhotosEnablementState::kEnabled);
           }));
     }
     wallpaper_provider_remote()->FlushForTesting();
@@ -570,12 +546,7 @@
   const std::string kResumeToken = "token";
 };
 
-INSTANTIATE_TEST_SUITE_P(
-    All,
-    PersonalizationAppWallpaperProviderImplGooglePhotosTest,
-    /*google_photos_enabled=*/::testing::Bool());
-
-TEST_P(PersonalizationAppWallpaperProviderImplGooglePhotosTest, FetchAlbums) {
+TEST_F(PersonalizationAppWallpaperProviderImplGooglePhotosTest, FetchAlbums) {
   // Mock a fetcher for the albums query.
   auto* const google_photos_albums_fetcher = static_cast<
       ::testing::NiceMock<wallpaper_handlers::MockGooglePhotosAlbumsFetcher>*>(
@@ -588,7 +559,7 @@
   EXPECT_CALL(*google_photos_albums_fetcher,
               AddRequestAndStartIfNecessary(absl::make_optional(kResumeToken),
                                             ::testing::_))
-      .Times(GooglePhotosEnabled() ? kNumFetches : 0);
+      .Times(kNumFetches);
 
   // Test fetching Google Photos albums before fetching the enterprise setting.
   // No requests should be made.
@@ -608,23 +579,22 @@
   FetchGooglePhotosEnabled();
   for (size_t i = 0; i < kNumFetches; ++i) {
     wallpaper_provider_remote()->get()->FetchGooglePhotosAlbums(
-        kResumeToken,
-        base::BindLambdaForTesting(
-            [this](ash::personalization_app::mojom::
-                       FetchGooglePhotosAlbumsResponsePtr response) {
-              EXPECT_EQ(response->albums.has_value(), GooglePhotosEnabled());
-            }));
+        kResumeToken, base::BindLambdaForTesting(
+                          [](ash::personalization_app::mojom::
+                                 FetchGooglePhotosAlbumsResponsePtr response) {
+                            EXPECT_TRUE(response->albums.has_value());
+                          }));
   }
   wallpaper_provider_remote()->FlushForTesting();
 }
 
-TEST_P(PersonalizationAppWallpaperProviderImplGooglePhotosTest, FetchEnabled) {
+TEST_F(PersonalizationAppWallpaperProviderImplGooglePhotosTest, FetchEnabled) {
   // Simulate the client making multiple requests for the same information to
   // test that all callbacks for that query are called.
   FetchGooglePhotosEnabled(kNumFetches);
 }
 
-TEST_P(PersonalizationAppWallpaperProviderImplGooglePhotosTest, FetchPhotos) {
+TEST_F(PersonalizationAppWallpaperProviderImplGooglePhotosTest, FetchPhotos) {
   // Mock a fetcher for the photos query.
   auto* const google_photos_photos_fetcher = static_cast<
       ::testing::NiceMock<wallpaper_handlers::MockGooglePhotosPhotosFetcher>*>(
@@ -640,7 +610,7 @@
               AddRequestAndStartIfNecessary(
                   absl::make_optional(item_id), absl::make_optional(album_id),
                   absl::make_optional(kResumeToken), false, ::testing::_))
-      .Times(GooglePhotosEnabled() ? kNumFetches : 0);
+      .Times(kNumFetches);
 
   // Test fetching Google Photos photos before fetching the enterprise setting.
   // No requests should be made.
@@ -663,15 +633,15 @@
     wallpaper_provider_remote()->get()->FetchGooglePhotosPhotos(
         item_id, album_id, kResumeToken,
         base::BindLambdaForTesting(
-            [this](ash::personalization_app::mojom::
-                       FetchGooglePhotosPhotosResponsePtr response) {
-              EXPECT_EQ(response->photos.has_value(), GooglePhotosEnabled());
+            [](ash::personalization_app::mojom::
+                   FetchGooglePhotosPhotosResponsePtr response) {
+              EXPECT_TRUE(response->photos.has_value());
             }));
   }
   wallpaper_provider_remote()->FlushForTesting();
 }
 
-TEST_P(PersonalizationAppWallpaperProviderImplGooglePhotosTest,
+TEST_F(PersonalizationAppWallpaperProviderImplGooglePhotosTest,
        ParseAlbumsAbsentAlbum) {
   using ash::personalization_app::mojom::FetchGooglePhotosAlbumsResponse;
   using ash::personalization_app::mojom::GooglePhotosAlbumPtr;
@@ -702,7 +672,7 @@
             absl::nullopt);
 }
 
-TEST_P(PersonalizationAppWallpaperProviderImplGooglePhotosTest,
+TEST_F(PersonalizationAppWallpaperProviderImplGooglePhotosTest,
        ParseAlbumsInvalidAlbum) {
   using ash::personalization_app::mojom::FetchGooglePhotosAlbumsResponse;
   using ash::personalization_app::mojom::GooglePhotosAlbumPtr;
@@ -746,7 +716,7 @@
   }
 }
 
-TEST_P(PersonalizationAppWallpaperProviderImplGooglePhotosTest,
+TEST_F(PersonalizationAppWallpaperProviderImplGooglePhotosTest,
        ParseAlbumsValidAlbum) {
   using ash::personalization_app::mojom::FetchGooglePhotosAlbumsResponse;
   using ash::personalization_app::mojom::GooglePhotosAlbum;
@@ -779,7 +749,7 @@
             absl::make_optional<size_t>(valid_albums_vector.size()));
 }
 
-TEST_P(PersonalizationAppWallpaperProviderImplGooglePhotosTest, ParseEnabled) {
+TEST_F(PersonalizationAppWallpaperProviderImplGooglePhotosTest, ParseEnabled) {
   using ash::personalization_app::mojom::GooglePhotosEnablementState;
 
   // Mock a fetcher to parse constructed responses.
@@ -822,7 +792,7 @@
             absl::make_optional<size_t>(1u));
 }
 
-TEST_P(PersonalizationAppWallpaperProviderImplGooglePhotosTest,
+TEST_F(PersonalizationAppWallpaperProviderImplGooglePhotosTest,
        ParsePhotosAbsentPhoto) {
   using ash::personalization_app::mojom::FetchGooglePhotosPhotosResponse;
   using ash::personalization_app::mojom::GooglePhotosPhotoPtr;
@@ -855,7 +825,7 @@
             absl::optional<size_t>());
 }
 
-TEST_P(PersonalizationAppWallpaperProviderImplGooglePhotosTest,
+TEST_F(PersonalizationAppWallpaperProviderImplGooglePhotosTest,
        ParsePhotosInvalidPhoto) {
   using ash::personalization_app::mojom::FetchGooglePhotosPhotosResponse;
   using ash::personalization_app::mojom::GooglePhotosPhotoPtr;
@@ -904,7 +874,7 @@
   }
 }
 
-TEST_P(PersonalizationAppWallpaperProviderImplGooglePhotosTest,
+TEST_F(PersonalizationAppWallpaperProviderImplGooglePhotosTest,
        ParsePhotosValidPhoto) {
   using ash::personalization_app::mojom::FetchGooglePhotosPhotosResponse;
   using ash::personalization_app::mojom::GooglePhotosPhoto;
@@ -978,11 +948,10 @@
       absl::make_optional<size_t>(valid_photos_vector_without_location.size()));
 }
 
-TEST_P(PersonalizationAppWallpaperProviderImplGooglePhotosTest,
+TEST_F(PersonalizationAppWallpaperProviderImplGooglePhotosTest,
        SelectGooglePhotosPhoto) {
   test_wallpaper_controller()->ClearCounts();
   const std::string photo_id = "OmnisVirLupus";
-  bool feature_enabled = GooglePhotosEnabled();
 
   // Test selecting a wallpaper before fetching the enterprise setting.
   wallpaper_provider_remote()->get()->SelectGooglePhotosPhoto(
@@ -1006,28 +975,24 @@
   wallpaper_provider_remote()->get()->SelectGooglePhotosPhoto(
       photo_id, ash::WallpaperLayout::WALLPAPER_LAYOUT_CENTER_CROPPED,
       /*preview_mode=*/false,
-      base::BindLambdaForTesting([feature_enabled](bool success) {
-        EXPECT_EQ(success, feature_enabled);
-      }));
+      base::BindLambdaForTesting([](bool success) { EXPECT_TRUE(success); }));
   wallpaper_provider_remote()->FlushForTesting();
 
-  EXPECT_EQ(feature_enabled ? 1 : 0,
+  EXPECT_EQ(1,
             test_wallpaper_controller()->set_google_photos_wallpaper_count());
-  EXPECT_EQ(feature_enabled,
-            ash::WallpaperInfo(
+  EXPECT_EQ(ash::WallpaperInfo(
                 {AccountId::FromUserEmailGaiaId(kFakeTestEmail, kTestGaiaId),
                  photo_id, /*daily_refresh_enabled=*/false,
                  ash::WallpaperLayout::WALLPAPER_LAYOUT_CENTER_CROPPED,
-                 /*preview_mode=*/false, "dedup_key"}) ==
-                test_wallpaper_controller()->wallpaper_info().value_or(
-                    ash::WallpaperInfo()));
+                 /*preview_mode=*/false, "dedup_key"}),
+            test_wallpaper_controller()->wallpaper_info().value_or(
+                ash::WallpaperInfo()));
 }
 
-TEST_P(PersonalizationAppWallpaperProviderImplGooglePhotosTest,
+TEST_F(PersonalizationAppWallpaperProviderImplGooglePhotosTest,
        SelectGooglePhotosAlbum) {
   test_wallpaper_controller()->ClearCounts();
   const std::string album_id = "OmnisVirLupus";
-  bool feature_enabled = GooglePhotosEnabled();
 
   // Test selecting an album before fetching the enterprise setting.
   wallpaper_provider_remote()->get()->SelectGooglePhotosAlbum(
@@ -1040,21 +1005,19 @@
   // Test selecting an album after fetching the enterprise setting.
   FetchGooglePhotosEnabled();
   wallpaper_provider_remote()->get()->SelectGooglePhotosAlbum(
-      album_id,
-      base::BindLambdaForTesting(
-          [feature_enabled](mojom::SetDailyRefreshResponsePtr response) {
-            EXPECT_EQ(response->success, feature_enabled);
-            EXPECT_EQ(response->force_refresh, feature_enabled);
-          }));
+      album_id, base::BindLambdaForTesting(
+                    [](mojom::SetDailyRefreshResponsePtr response) {
+                      EXPECT_TRUE(response->success);
+                      EXPECT_TRUE(response->force_refresh);
+                    }));
   wallpaper_provider_remote()->FlushForTesting();
 }
 
-TEST_P(PersonalizationAppWallpaperProviderImplGooglePhotosTest,
+TEST_F(PersonalizationAppWallpaperProviderImplGooglePhotosTest,
        SelectGooglePhotosAlbum_WithoutForcingRefresh) {
   test_wallpaper_controller()->ClearCounts();
   const std::string album_id = "OmnisVirLupus";
   const std::string photo_id = "DummyPhotoId";
-  bool feature_enabled = GooglePhotosEnabled();
 
   // Test selecting an album before fetching the enterprise setting.
   wallpaper_provider_remote()->get()->SelectGooglePhotosAlbum(
@@ -1070,21 +1033,17 @@
   wallpaper_provider_remote()->get()->SelectGooglePhotosPhoto(
       photo_id, ash::WallpaperLayout::WALLPAPER_LAYOUT_CENTER_CROPPED,
       /*preview_mode=*/false,
-      base::BindLambdaForTesting([feature_enabled](bool success) {
-        EXPECT_EQ(success, feature_enabled);
-      }));
+      base::BindLambdaForTesting([](bool success) { EXPECT_TRUE(success); }));
   wallpaper_provider_remote()->FlushForTesting();
 
   AddToAlbumIdMap(album_id, photo_id);
   test_wallpaper_controller()->add_dedup_key_to_wallpaper_info(photo_id);
   wallpaper_provider_remote()->get()->SelectGooglePhotosAlbum(
-      album_id,
-      base::BindLambdaForTesting(
-          [feature_enabled](mojom::SetDailyRefreshResponsePtr response) {
-            EXPECT_EQ(response->success, feature_enabled);
-            if (feature_enabled)
-              EXPECT_FALSE(response->force_refresh);
-          }));
+      album_id, base::BindLambdaForTesting(
+                    [](mojom::SetDailyRefreshResponsePtr response) {
+                      EXPECT_TRUE(response->success);
+                      EXPECT_FALSE(response->force_refresh);
+                    }));
   wallpaper_provider_remote()->FlushForTesting();
 }
 
diff --git a/chrome/browser/ash/web_applications/system_web_app_install_utils.cc b/chrome/browser/ash/web_applications/system_web_app_install_utils.cc
index 0f00def..6c3a2f7a 100644
--- a/chrome/browser/ash/web_applications/system_web_app_install_utils.cc
+++ b/chrome/browser/ash/web_applications/system_web_app_install_utils.cc
@@ -4,9 +4,13 @@
 
 #include "chrome/browser/ash/web_applications/system_web_app_install_utils.h"
 
+#include "ash/shell.h"
+#include "ash/style/color_util.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/resource/resource_bundle.h"
-#include "ui/chromeos/styles/cros_styles.h"
+#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
+#include "ui/color/color_id.h"
+#include "ui/color/color_provider_source.h"
 
 namespace web_app {
 
@@ -24,8 +28,21 @@
 }
 
 SkColor GetDefaultBackgroundColor(const bool use_dark_mode) {
-  return cros_styles::ResolveColor(cros_styles::ColorName::kBgColor,
-                                   use_dark_mode);
+  // TODO(b/255842593): If windows can ever have different ColorProviders, this
+  // should be deleted as we'll need to move this logic into
+  // web_app_browser_controller instead.
+  ui::ColorProviderSource* color_provider_source =
+      ash::ColorUtil::GetColorProviderSourceForWindow(
+          ash::Shell::GetPrimaryRootWindow());
+  DCHECK(color_provider_source);
+  const ui::ColorProvider* color_provider =
+      color_provider_source->GetColorProvider();
+  DCHECK(color_provider);
+
+  ui::ColorId color_id =
+      use_dark_mode ? cros_tokens::kBgColorDark : cros_tokens::kBgColorLight;
+
+  return color_provider->GetColor(color_id);
 }
 
 }  // namespace web_app
diff --git a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
index 9ebc3b6..1b3fed2 100644
--- a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
+++ b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
@@ -425,9 +425,11 @@
     input = &empty_input;
   const TemplateURLService* template_url_service = GetTemplateURLService();
   return AutocompleteMatch::GURLToStrippedGURL(
-             url1, *input, template_url_service, std::u16string()) ==
+             url1, *input, template_url_service, std::u16string(),
+             /*keep_search_intent_params=*/false) ==
          AutocompleteMatch::GURLToStrippedGURL(
-             url2, *input, template_url_service, std::u16string());
+             url2, *input, template_url_service, std::u16string(),
+             /*keep_search_intent_params=*/false);
 }
 
 void ChromeAutocompleteProviderClient::OpenSharingHub() {
diff --git a/chrome/browser/autocomplete/tab_matcher_desktop.cc b/chrome/browser/autocomplete/tab_matcher_desktop.cc
index 34a098d..0016062 100644
--- a/chrome/browser/autocomplete/tab_matcher_desktop.cc
+++ b/chrome/browser/autocomplete/tab_matcher_desktop.cc
@@ -4,10 +4,12 @@
 
 #include "chrome/browser/autocomplete/tab_matcher_desktop.h"
 
+#include "base/feature_list.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "components/omnibox/browser/autocomplete_match.h"
+#include "components/omnibox/common/omnibox_features.h"
 #include "content/public/browser/web_contents_user_data.h"
 
 namespace {
@@ -24,14 +26,18 @@
   void UpdateLastCommittedStrippedURL(
       int last_committed_index,
       const GURL& last_committed_url,
-      const TemplateURLService* template_url_service) {
+      const TemplateURLService* template_url_service,
+      const bool keep_search_intent_params) {
     if (last_committed_url.is_valid()) {
       last_committed_entry_index_ = last_committed_index;
-      // Use blank input since we will re-use this stripped URL with other
-      // inputs.
+      // Use a blank input as the stripped URL will be reused with other inputs.
+      // Also keep the search intent params. Otherwise, this can result in over
+      // triggering of the Switch to Tab action on plain-text suggestions for
+      // open entity SRPs, or vice versa, on entity suggestions for open
+      // plain-text SRPs.
       last_committed_stripped_url_ = AutocompleteMatch::GURLToStrippedGURL(
           last_committed_url, AutocompleteInput(), template_url_service,
-          std::u16string());
+          std::u16string(), keep_search_intent_params);
     }
   }
 
@@ -59,10 +65,20 @@
   const AutocompleteInput empty_input;
   if (!input)
     input = &empty_input;
+
+  // Use a blank input as the stripped URL will be reused with other inputs.
+  // Also keep the search intent params. Otherwise, this can result in over
+  // triggering of the Switch to Tab action on plain-text suggestions for
+  // open entity SRPs, or vice versa, on entity suggestions for open plain-text
+  // SRPs.
+  const bool keep_search_intent_params = base::FeatureList::IsEnabled(
+      omnibox::kDisambiguateTabMatchingForEntitySuggestions);
   const GURL stripped_url = AutocompleteMatch::GURLToStrippedGURL(
-      url, *input, template_url_service_, std::u16string());
+      url, *input, template_url_service_, std::u16string(),
+      keep_search_intent_params);
   for (auto* web_contents : GetOpenTabs()) {
-    if (IsStrippedURLEqualToWebContentsURL(stripped_url, web_contents))
+    if (IsStrippedURLEqualToWebContentsURL(stripped_url, web_contents,
+                                           keep_search_intent_params))
       return true;
   }
   return false;
@@ -91,7 +107,8 @@
 
 bool TabMatcherDesktop::IsStrippedURLEqualToWebContentsURL(
     const GURL& stripped_url,
-    content::WebContents* web_contents) const {
+    content::WebContents* web_contents,
+    const bool keep_search_intent_params) const {
   AutocompleteClientWebContentsUserData::CreateForWebContents(web_contents);
   AutocompleteClientWebContentsUserData* user_data =
       AutocompleteClientWebContentsUserData::FromWebContents(web_contents);
@@ -100,7 +117,8 @@
       web_contents->GetController().GetLastCommittedEntryIndex()) {
     user_data->UpdateLastCommittedStrippedURL(
         web_contents->GetController().GetLastCommittedEntryIndex(),
-        web_contents->GetLastCommittedURL(), template_url_service_);
+        web_contents->GetLastCommittedURL(), template_url_service_,
+        keep_search_intent_params);
   }
   return stripped_url == user_data->GetLastCommittedStrippedURL();
 }
diff --git a/chrome/browser/autocomplete/tab_matcher_desktop.h b/chrome/browser/autocomplete/tab_matcher_desktop.h
index 79e16b57..fa92693 100644
--- a/chrome/browser/autocomplete/tab_matcher_desktop.h
+++ b/chrome/browser/autocomplete/tab_matcher_desktop.h
@@ -26,7 +26,8 @@
  private:
   bool IsStrippedURLEqualToWebContentsURL(
       const GURL& stripped_url,
-      content::WebContents* web_contents) const;
+      content::WebContents* web_contents,
+      const bool keep_search_intent_params) const;
 
   base::raw_ptr<const TemplateURLService> template_url_service_;
   raw_ptr<Profile> profile_{};
diff --git a/chrome/browser/autocomplete/tab_matcher_desktop_unittest.cc b/chrome/browser/autocomplete/tab_matcher_desktop_unittest.cc
index 546924a..aede00d7 100644
--- a/chrome/browser/autocomplete/tab_matcher_desktop_unittest.cc
+++ b/chrome/browser/autocomplete/tab_matcher_desktop_unittest.cc
@@ -58,3 +58,52 @@
 
   other_browser->tab_strip_model()->CloseAllTabs();
 }
+
+TEST_F(TabMatcherDesktopTest, IsTabOpenUsesCanonicalSearchURL) {
+  TemplateURLService turl_service(kServiceInitializers, 2);
+  TabMatcherDesktop matcher(&turl_service, profile());
+
+  TemplateURLData data;
+  data.SetURL("http://example.com/search?q={searchTerms}");
+  data.search_intent_params = {"intent"};
+  TemplateURL turl(data);
+  auto* default_turl = turl_service.Add(std::make_unique<TemplateURL>(data));
+  turl_service.SetUserSelectedDefaultSearchProvider(default_turl);
+
+  {
+    TemplateURLRef::SearchTermsArgs search_terms_args(u"foo");
+    search_terms_args.additional_query_params = "wiz=baz";
+    std::string foo_url = default_turl->url_ref().ReplaceSearchTerms(
+        search_terms_args, turl_service.search_terms_data());
+    EXPECT_EQ("http://example.com/search?wiz=baz&q=foo", foo_url);
+    AddTab(browser(), GURL(foo_url));
+    // The last tab is active. IsTabOpenWithURL() does not match the active tab.
+    AddTab(browser(), GURL("http://active.chromium.org"));
+
+    EXPECT_TRUE(matcher.IsTabOpenWithURL(
+        GURL("http://example.com/search?q=foo"), nullptr));
+    EXPECT_TRUE(matcher.IsTabOpenWithURL(
+        GURL("http://example.com/search?wiz=baz&q=foo"), nullptr));
+    EXPECT_FALSE(matcher.IsTabOpenWithURL(
+        GURL("http://example.com/search?wiz=baz&intent=INTENT&q=foo"),
+        nullptr));
+  }
+  {
+    TemplateURLRef::SearchTermsArgs search_terms_args(u"bar");
+    search_terms_args.additional_query_params = "intent=INTENT";
+    std::string bar_url = default_turl->url_ref().ReplaceSearchTerms(
+        search_terms_args, turl_service.search_terms_data());
+    EXPECT_EQ("http://example.com/search?intent=INTENT&q=bar", bar_url);
+    AddTab(browser(), GURL(bar_url));
+    // The last tab is active. IsTabOpenWithURL() does not match the active tab.
+    AddTab(browser(), GURL("http://active.chromium.org"));
+
+    EXPECT_FALSE(matcher.IsTabOpenWithURL(
+        GURL("http://example.com/search?q=bar"), nullptr));
+    EXPECT_FALSE(matcher.IsTabOpenWithURL(
+        GURL("http://example.com/search?wiz=baz&q=bar"), nullptr));
+    EXPECT_TRUE(matcher.IsTabOpenWithURL(
+        GURL("http://example.com/search?wiz=baz&intent=INTENT&q=bar"),
+        nullptr));
+  }
+}
diff --git a/chrome/browser/creator/android/creator_api_bridge.cc b/chrome/browser/creator/android/creator_api_bridge.cc
index 182f1ac..744b614 100644
--- a/chrome/browser/creator/android/creator_api_bridge.cc
+++ b/chrome/browser/creator/android/creator_api_bridge.cc
@@ -24,14 +24,14 @@
 base::android::ScopedJavaLocalRef<jobject> ToJava(JNIEnv* env,
                                                   const Creator& creator) {
   return Java_Creator_Constructor(
-      env, url::GURLAndroid::FromNativeGURL(env, creator.url),
+      env, base::android::ConvertUTF16ToJavaString(env, creator.url),
       base::android::ConvertUTF16ToJavaString(env, creator.title));
 }
 
 // TODO(crbug/1374058): Replace this with actual access to creator api stub.
 void DoGetCreator(std::string web_channel_id,
                   base::OnceCallback<void(Creator)> callback) {
-  std::move(callback).Run(Creator{GURL("example.com"), u"Example Domain"});
+  std::move(callback).Run(Creator{u"alexainsley.com", u"Alex Ainsley"});
 }
 
 }  // namespace
diff --git a/chrome/browser/creator/android/java/res/layout/creator_activity.xml b/chrome/browser/creator/android/java/res/layout/creator_activity.xml
index f3562ab..d8c6ecd 100644
--- a/chrome/browser/creator/android/java/res/layout/creator_activity.xml
+++ b/chrome/browser/creator/android/java/res/layout/creator_activity.xml
@@ -15,8 +15,7 @@
       android:id="@+id/action_bar"
       android:layout_width="match_parent"
       android:layout_height="?attr/actionBarSize"
-      style="@style/CreatorActivityNoActionBar"
-      app:title="@string/cormorant_creator_activity" />
+      style="@style/CreatorActivityNoActionBar" />
   <include
       layout="@layout/creator_profile"
       android:id="@+id/creator_profile"
diff --git a/chrome/browser/creator/android/java/res/layout/creator_profile.xml b/chrome/browser/creator/android/java/res/layout/creator_profile.xml
index 5696f04..6b7e536 100644
--- a/chrome/browser/creator/android/java/res/layout/creator_profile.xml
+++ b/chrome/browser/creator/android/java/res/layout/creator_profile.xml
@@ -15,7 +15,7 @@
       android:layout_weight="1"
       android:layout_width="0dp"
       android:layout_height="match_parent"
-      android:layout_marginStart="16dp" >
+      android:layout_marginStart="5dp" >
     <TextView
         android:id="@+id/creator_name"
         android:layout_width="wrap_content"
diff --git a/chrome/browser/creator/android/java/res/values/styles.xml b/chrome/browser/creator/android/java/res/values/styles.xml
index d20cad6d..c5593910 100644
--- a/chrome/browser/creator/android/java/res/values/styles.xml
+++ b/chrome/browser/creator/android/java/res/values/styles.xml
@@ -14,7 +14,7 @@
         <item name="android:paddingStart">12dp</item>
         <item name="android:paddingEnd">24dp</item>
         <item name="android:drawablePadding">15dp</item>
-        <item name="android:layout_marginEnd">16dp</item>
+        <item name="android:layout_marginEnd">5dp</item>
         <item name="android:textAppearance">@style/TextAppearance.Button.Text.Filled</item>
         <item name="buttonTextColor">?attr/globalFilledButtonTextColor</item>
         <item name="buttonColor">?attr/globalFilledButtonBgColor</item>
@@ -25,7 +25,7 @@
         <item name="android:paddingStart">12dp</item>
         <item name="android:paddingEnd">20dp</item>
         <item name="android:drawablePadding">5dp</item>
-        <item name="android:layout_marginEnd">16dp</item>
+        <item name="android:layout_marginEnd">5dp</item>
         <item name="android:textAppearance">@style/TextAppearance.Button.Text.Blue</item>
         <item name="buttonTextColor">@macro/default_text_color_secondary</item>
         <item name="buttonColor">@android:color/white</item>
diff --git a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorApiBridge.java b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorApiBridge.java
index 1587da3..4ade1d6 100644
--- a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorApiBridge.java
+++ b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorApiBridge.java
@@ -8,19 +8,18 @@
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.NativeMethods;
-import org.chromium.url.GURL;
 
 /**
- * A Java API for connecting to creator component.
+ * A Java API for connecting to creator component
  */
 @JNINamespace("creator")
 public class CreatorApiBridge {
     public static class Creator {
-        public final GURL url;
+        public final String url;
         public final String title;
 
         @CalledByNative("Creator")
-        public Creator(GURL url, String title) {
+        public Creator(String url, String title) {
             this.url = url;
             this.title = title;
         }
diff --git a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorMediator.java b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorMediator.java
index b8944ceb..0127d2c 100644
--- a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorMediator.java
+++ b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorMediator.java
@@ -12,6 +12,8 @@
 import org.chromium.chrome.browser.feed.webfeed.WebFeedBridge;
 import org.chromium.ui.modelutil.PropertyModel;
 
+import java.nio.charset.StandardCharsets;
+
 /**
  * Sets up the Mediator for Cormorant Creator surface.  It is based on the doc at
  * https://chromium.googlesource.com/chromium/src/+/HEAD/docs/ui/android/mvc_simple_list_tutorial.md
@@ -19,6 +21,7 @@
 public class CreatorMediator {
     private Context mContext;
     private Creator mCreator;
+    private byte[] mWebFeedId;
     private String mTitle;
     private String mUrl;
     private PropertyModel mCreatorProfileModel;
@@ -27,6 +30,8 @@
     CreatorMediator(Context context, PropertyModel creatorProfileModel) {
         mContext = context;
         mCreatorProfileModel = creatorProfileModel;
+        mWebFeedId = mCreatorProfileModel.get(CreatorProfileProperties.WEB_FEED_ID_KEY);
+        getCreator();
 
         // Set Follow OnClick Action
         mCreatorProfileModel.set(
@@ -38,8 +43,7 @@
     }
 
     private void followClickHandler() {
-        WebFeedBridge.followFromId(
-                mCreatorProfileModel.get(CreatorProfileProperties.WEB_FEED_ID_KEY),
+        WebFeedBridge.followFromId(mWebFeedId,
                 /*isDurable=*/false, WebFeedBridge.CHANGE_REASON_WEB_PAGE_MENU, (result) -> {
                     if (result.requestStatus == SUCCESS) {
                         mCreatorProfileModel.set(CreatorProfileProperties.IS_FOLLOWED_KEY, true);
@@ -48,7 +52,7 @@
     }
 
     private void followingClickHandler() {
-        WebFeedBridge.unfollow(mCreatorProfileModel.get(CreatorProfileProperties.WEB_FEED_ID_KEY),
+        WebFeedBridge.unfollow(mWebFeedId,
                 /*isDurable=*/false, WebFeedBridge.CHANGE_REASON_WEB_PAGE_MENU, (result) -> {
                     if (result.requestStatus == SUCCESS) {
                         mCreatorProfileModel.set(CreatorProfileProperties.IS_FOLLOWED_KEY, false);
@@ -57,10 +61,13 @@
     }
 
     private void getCreator() {
-        CreatorApiBridge.getCreator("test", this::onGetCreator);
+        CreatorApiBridge.getCreator(
+                new String(mWebFeedId, StandardCharsets.UTF_8), this::onGetCreator);
     }
 
     private void onGetCreator(Creator creator) {
         mCreator = creator;
+        mCreatorProfileModel.set(CreatorProfileProperties.TITLE_KEY, mCreator.title);
+        mCreatorProfileModel.set(CreatorProfileProperties.URL_KEY, mCreator.url);
     }
 }
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_apitest.cc b/chrome/browser/extensions/api/developer_private/developer_private_apitest.cc
index 07c8b32..cd5e27044 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_apitest.cc
+++ b/chrome/browser/extensions/api/developer_private/developer_private_apitest.cc
@@ -6,7 +6,6 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/path_service.h"
 #include "base/strings/stringprintf.h"
-#include "base/test/scoped_feature_list.h"
 #include "chrome/browser/devtools/devtools_window.h"
 #include "chrome/browser/devtools/devtools_window_testing.h"
 #include "chrome/browser/extensions/api/developer_private/developer_private_api.h"
@@ -24,7 +23,6 @@
 #include "extensions/browser/extension_host_test_helper.h"
 #include "extensions/browser/offscreen_document_host.h"
 #include "extensions/browser/process_manager.h"
-#include "extensions/common/extension_features.h"
 #include "extensions/common/manifest_handlers/background_info.h"
 #include "extensions/common/mojom/view_type.mojom.h"
 #include "extensions/test/result_catcher.h"
@@ -284,23 +282,9 @@
   EXPECT_TRUE(DevToolsWindow::FindDevToolsWindow(service_worker_host.get()));
 }
 
-class DeveloperPrivateOffscreenDocumentApiTest
-    : public DeveloperPrivateApiTest {
- public:
-  DeveloperPrivateOffscreenDocumentApiTest() {
-    feature_list_.InitAndEnableFeature(
-        extensions_features::kExtensionsOffscreenDocuments);
-  }
-  ~DeveloperPrivateOffscreenDocumentApiTest() override = default;
-
- private:
-  base::test::ScopedFeatureList feature_list_;
-};
-
 // Test that offscreen documents show up in the list of inspectable views and
 // can be inspected.
-IN_PROC_BROWSER_TEST_F(DeveloperPrivateOffscreenDocumentApiTest,
-                       InspectOffscreenDocument) {
+IN_PROC_BROWSER_TEST_F(DeveloperPrivateApiTest, InspectOffscreenDocument) {
   static constexpr char kManifest[] =
       R"({
            "name": "Offscreen Document Test",
diff --git a/chrome/browser/extensions/api/terminal/terminal_private_api.cc b/chrome/browser/extensions/api/terminal/terminal_private_api.cc
index 731e849..a8161c6f 100644
--- a/chrome/browser/extensions/api/terminal/terminal_private_api.cc
+++ b/chrome/browser/extensions/api/terminal/terminal_private_api.cc
@@ -60,7 +60,7 @@
 #include "extensions/browser/app_window/app_window.h"
 #include "extensions/browser/app_window/app_window_registry.h"
 #include "extensions/browser/event_router.h"
-#include "extensions/browser/extension_system.h"
+#include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extensions_browser_client.h"
 #include "extensions/common/constants.h"
 #include "ui/display/types/display_constants.h"
@@ -742,10 +742,10 @@
       base::FeatureList::IsEnabled(chromeos::features::kTerminalMultiProfile));
   info.SetBoolKey(
       "sftp", base::FeatureList::IsEnabled(chromeos::features::kTerminalSftp));
-  info.SetBoolKey("tast", extensions::ExtensionSystem::Get(browser_context())
-                              ->extension_service()
-                              ->IsExtensionEnabled(
-                                  extension_misc::kGuestModeTestExtensionId));
+  info.SetBoolKey("tast",
+                  extensions::ExtensionRegistry::Get(browser_context())
+                      ->enabled_extensions()
+                      .Contains(extension_misc::kGuestModeTestExtensionId));
   info.SetBoolKey("tmux_integration",
                   base::FeatureList::IsEnabled(
                       chromeos::features::kTerminalTmuxIntegration));
diff --git a/chrome/browser/extensions/extension_csp_bypass_browsertest.cc b/chrome/browser/extensions/extension_csp_bypass_browsertest.cc
index 602b5a9..5ddca9a8 100644
--- a/chrome/browser/extensions/extension_csp_bypass_browsertest.cc
+++ b/chrome/browser/extensions/extension_csp_bypass_browsertest.cc
@@ -133,8 +133,11 @@
   EXPECT_TRUE(CanLoadScript(ext_without_permission));
 
   // chrome-extension:-URLs can never bypass CSP in WebUI.
+  // TODO(crbug.com/1098690): Find a way to make this test work for pages that
+  // do use TrustedTypes. In the meantime, just use a WebUI that has not
+  // enabled TrustedTypes yet.
   ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(),
-                                           GURL(chrome::kChromeUISettingsURL)));
+                                           GURL(chrome::kChromeUIWelcomeURL)));
 
   EXPECT_FALSE(CanLoadScript(component_ext_with_permission));
   EXPECT_FALSE(CanLoadScript(component_ext_without_permission));
diff --git a/chrome/browser/extensions/tab_helper.h b/chrome/browser/extensions/tab_helper.h
index 38935207..02be54a 100644
--- a/chrome/browser/extensions/tab_helper.h
+++ b/chrome/browser/extensions/tab_helper.h
@@ -37,8 +37,6 @@
 class ExtensionActionRunner;
 class Extension;
 
-extern const char kIsPrerender2DisabledKey[];
-
 // Per-tab extension helper. Also handles non-extension apps.
 class TabHelper : public content::WebContentsObserver,
                   public ExtensionFunctionDispatcher::Delegate,
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 4ba956d..32fe02fe 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -6938,11 +6938,6 @@
     "expiry_milestone": 98
   },
   {
-    "name": "wallpaper-google-photos-integration",
-    "owners": ["dmblack@google.com", "assistive-eng@google.com"],
-    "expiry_milestone": 105
-  },
-  {
     "name": "web-apps-crosapi",
     "owners": [ "mxcai", "ericwilligers", "chromeos-apps-foundation-team@google.com" ],
     "expiry_milestone": 115
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 7c926c42..a2f8ddd 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -3111,11 +3111,6 @@
     "Allows users to minimize all active windows to preview their current "
     "wallpaper";
 
-const char kWallpaperGooglePhotosIntegrationName[] =
-    "Enable Google Photos wallpaper integration";
-const char kWallpaperGooglePhotosIntegrationDescription[] =
-    "Allows users to select their wallpaper from Google Photos";
-
 const char kWallpaperPerDeskName[] =
     "Enable setting different wallpapers per desk";
 const char kWallpaperPerDeskDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index d8ff874..fffe79a2 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1768,9 +1768,6 @@
 extern const char kWallpaperFullScreenPreviewName[];
 extern const char kWallpaperFullScreenPreviewDescription[];
 
-extern const char kWallpaperGooglePhotosIntegrationName[];
-extern const char kWallpaperGooglePhotosIntegrationDescription[];
-
 extern const char kWallpaperPerDeskName[];
 extern const char kWallpaperPerDeskDescription[];
 
diff --git a/chrome/browser/lookalikes/lookalike_url_navigation_throttle_browsertest.cc b/chrome/browser/lookalikes/lookalike_url_navigation_throttle_browsertest.cc
index 02fc86c..a89c110 100644
--- a/chrome/browser/lookalikes/lookalike_url_navigation_throttle_browsertest.cc
+++ b/chrome/browser/lookalikes/lookalike_url_navigation_throttle_browsertest.cc
@@ -1115,7 +1115,8 @@
         NavigationSuggestionEvent::kMatchSiteEngagement);
 
     ukm_urls.push_back(kNavigatedUrl);
-    CheckUkm(ukm_urls, "MatchType", LookalikeUrlMatchType::kSiteEngagement);
+    CheckUkm(ukm_urls, "MatchType",
+             LookalikeUrlMatchType::kSkeletonMatchSiteEngagement);
   }
 }
 
@@ -1218,7 +1219,7 @@
       NavigationSuggestionEvent::kMatchSiteEngagement);
 
   CheckUkm({kNavigatedUrl}, "MatchType",
-           LookalikeUrlMatchType::kSiteEngagement);
+           LookalikeUrlMatchType::kSkeletonMatchSiteEngagement);
 }
 
 // Similar to Idn_SiteEngagement_Match, but tests a single domain. Also checks
@@ -1249,7 +1250,8 @@
         NavigationSuggestionEvent::kMatchSiteEngagement);
 
     ukm_urls.push_back(kNavigatedUrl);
-    CheckUkm(ukm_urls, "MatchType", LookalikeUrlMatchType::kSiteEngagement);
+    CheckUkm(ukm_urls, "MatchType",
+             LookalikeUrlMatchType::kSkeletonMatchSiteEngagement);
   }
 
   // Incognito shouldn't record metrics because there are no engaged sites.
@@ -1274,7 +1276,8 @@
         incognito, histograms, kNavigatedUrl, kEngagedUrl,
         NavigationSuggestionEvent::kMatchSiteEngagement);
     ukm_urls.push_back(kNavigatedUrl);
-    CheckUkm(ukm_urls, "MatchType", LookalikeUrlMatchType::kSiteEngagement);
+    CheckUkm(ukm_urls, "MatchType",
+             LookalikeUrlMatchType::kSkeletonMatchSiteEngagement);
   }
 
   // Main profile shouldn't record metrics because there are no engaged sites.
@@ -1351,7 +1354,7 @@
       NavigationSuggestionEvent::kMatchSiteEngagement);
 
   CheckUkm({kNavigatedUrl}, "MatchType",
-           LookalikeUrlMatchType::kSiteEngagement);
+           LookalikeUrlMatchType::kSkeletonMatchSiteEngagement);
 }
 
 // Navigate to lookalike domains that redirect to benign domains and ensure that
diff --git a/chrome/browser/media/history/media_history_store.cc b/chrome/browser/media/history/media_history_store.cc
index 97964289..fbad38dd 100644
--- a/chrome/browser/media/history/media_history_store.cc
+++ b/chrome/browser/media/history/media_history_store.cc
@@ -9,7 +9,6 @@
 #include "base/callback.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
-#include "base/metrics/histogram_functions.h"
 #include "base/strings/stringprintf.h"
 #include "build/build_config.h"
 #include "chrome/browser/media/history/media_history_images_table.h"
@@ -132,21 +131,6 @@
 
 namespace media_history {
 
-const char MediaHistoryStore::kInitResultHistogramName[] =
-    "Media.History.Init.Result";
-
-const char MediaHistoryStore::kInitResultAfterDeleteHistogramName[] =
-    "Media.History.Init.ResultAfterDelete";
-
-const char MediaHistoryStore::kPlaybackWriteResultHistogramName[] =
-    "Media.History.Playback.WriteResult";
-
-const char MediaHistoryStore::kSessionWriteResultHistogramName[] =
-    "Media.History.Session.WriteResult";
-
-const char MediaHistoryStore::kDatabaseSizeKbHistogramName[] =
-    "Media.History.DatabaseSize";
-
 MediaHistoryStore::MediaHistoryStore(
     Profile* profile,
     scoped_refptr<base::UpdateableSequencedTaskRunner> db_task_runner)
@@ -194,57 +178,31 @@
   sql::Transaction transaction(DB());
   if (!transaction.Begin()) {
     LOG(ERROR) << "Failed to begin the transaction.";
-
-    base::UmaHistogramEnumeration(
-        MediaHistoryStore::kPlaybackWriteResultHistogramName,
-        MediaHistoryStore::PlaybackWriteResult::kFailedToEstablishTransaction);
-
     return;
   }
 
   // TODO(https://crbug.com/1052436): Remove the separate origin.
   auto origin = url::Origin::Create(watch_time->origin);
   if (origin != url::Origin::Create(watch_time->url)) {
-    base::UmaHistogramEnumeration(
-        MediaHistoryStore::kPlaybackWriteResultHistogramName,
-        MediaHistoryStore::PlaybackWriteResult::kFailedToWriteBadOrigin);
-
     return;
   }
 
   if (!CreateOriginId(origin)) {
-    base::UmaHistogramEnumeration(
-        MediaHistoryStore::kPlaybackWriteResultHistogramName,
-        MediaHistoryStore::PlaybackWriteResult::kFailedToWriteOrigin);
-
     return;
   }
 
   if (!playback_table_->SavePlayback(*watch_time)) {
-    base::UmaHistogramEnumeration(
-        MediaHistoryStore::kPlaybackWriteResultHistogramName,
-        MediaHistoryStore::PlaybackWriteResult::kFailedToWritePlayback);
-
     return;
   }
 
   if (watch_time->has_audio && watch_time->has_video) {
     if (!origin_table_->IncrementAggregateAudioVideoWatchTime(
             origin, watch_time->cumulative_watch_time)) {
-      base::UmaHistogramEnumeration(
-          MediaHistoryStore::kPlaybackWriteResultHistogramName,
-          MediaHistoryStore::PlaybackWriteResult::
-              kFailedToIncrementAggreatedWatchtime);
-
       return;
     }
   }
 
   transaction.Commit();
-
-  base::UmaHistogramEnumeration(
-      MediaHistoryStore::kPlaybackWriteResultHistogramName,
-      MediaHistoryStore::PlaybackWriteResult::kSuccess);
 }
 
 void MediaHistoryStore::Initialize(const bool should_reset) {
@@ -253,11 +211,6 @@
   if (should_reset) {
     if (!sql::Database::Delete(db_path_)) {
       LOG(ERROR) << "Failed to delete the old database.";
-
-      base::UmaHistogramEnumeration(
-          MediaHistoryStore::kInitResultHistogramName,
-          MediaHistoryStore::InitResult::kFailedToDeleteOldDatabase);
-
       return;
     }
   }
@@ -265,7 +218,7 @@
   if (IsCancelled())
     return;
 
-  auto result = InitializeInternal();
+  bool result = InitializeInternal();
 
   if (IsCancelled()) {
     meta_table_.reset();
@@ -273,31 +226,24 @@
     return;
   }
 
-  base::UmaHistogramEnumeration(MediaHistoryStore::kInitResultHistogramName,
-                                result);
-
   // In some edge cases the DB might be corrupted and unrecoverable so we should
   // delete the database and recreate it.
-  if (result != InitResult::kSuccess) {
+  if (!result) {
     db_ = std::make_unique<sql::Database>();
     meta_table_ = std::make_unique<sql::MetaTable>();
 
     sql::Database::Delete(db_path_);
-
-    base::UmaHistogramEnumeration(
-        MediaHistoryStore::kInitResultAfterDeleteHistogramName,
-        InitializeInternal());
   }
 }
 
-MediaHistoryStore::InitResult MediaHistoryStore::InitializeInternal() {
+bool MediaHistoryStore::InitializeInternal() {
   DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
 
   if (db_path_.empty()) {
     if (IsCancelled() || !db_ || !db_->OpenInMemory()) {
       LOG(ERROR) << "Failed to open the in-memory database.";
 
-      return MediaHistoryStore::InitResult::kFailedToOpenDatabase;
+      return false;
     }
   } else {
     base::File::Error err;
@@ -305,20 +251,20 @@
         !base::CreateDirectoryAndGetError(db_path_.DirName(), &err)) {
       LOG(ERROR) << "Failed to create the directory.";
 
-      return MediaHistoryStore::InitResult::kFailedToCreateDirectory;
+      return false;
     }
 
     if (IsCancelled() || !db_ || !db_->Open(db_path_)) {
       LOG(ERROR) << "Failed to open the database.";
 
-      return MediaHistoryStore::InitResult::kFailedToOpenDatabase;
+      return false;
     }
   }
 
   if (IsCancelled() || !db_ || !db_->Execute("PRAGMA foreign_keys=1")) {
     LOG(ERROR) << "Failed to enable foreign keys on the media history store.";
 
-    return MediaHistoryStore::InitResult::kFailedNoForeignKeys;
+    return false;
   }
 
   if (IsCancelled() || !db_ || !meta_table_ ||
@@ -326,55 +272,45 @@
                          kCompatibleVersionNumber)) {
     LOG(ERROR) << "Failed to create the meta table.";
 
-    return MediaHistoryStore::InitResult::kFailedToCreateMetaTable;
+    return false;
   }
 
   if (IsCancelled() || !db_) {
     LOG(ERROR) << "Failed to begin the transaction.";
 
-    return MediaHistoryStore::InitResult::kFailedToEstablishTransaction;
+    return false;
   }
 
   sql::Transaction transaction(db_.get());
   if (!transaction.Begin()) {
     LOG(ERROR) << "Failed to begin the transaction.";
 
-    return MediaHistoryStore::InitResult::kFailedToEstablishTransaction;
+    return false;
   }
 
   sql::InitStatus status = CreateOrUpgradeIfNeeded();
   if (status != sql::INIT_OK) {
     LOG(ERROR) << "Failed to create or update the media history store.";
 
-    return MediaHistoryStore::InitResult::kFailedDatabaseTooNew;
+    return false;
   }
 
   status = InitializeTables();
   if (status != sql::INIT_OK) {
     LOG(ERROR) << "Failed to initialize the media history store tables.";
 
-    return MediaHistoryStore::InitResult::kFailedInitializeTables;
+    return false;
   }
 
   if (IsCancelled() || !db_ || !transaction.Commit()) {
     LOG(ERROR) << "Failed to commit transaction.";
 
-    return MediaHistoryStore::InitResult::kFailedToCommitTransaction;
+    return false;
   }
 
   initialization_successful_ = true;
 
-  // Get the size in bytes.
-  int64_t file_size = 0;
-  base::GetFileSize(db_path_, &file_size);
-
-  // Record the size in KB.
-  if (file_size > 0) {
-    base::UmaHistogramMemoryKB(MediaHistoryStore::kDatabaseSizeKbHistogramName,
-                               file_size / 1000);
-  }
-
-  return MediaHistoryStore::InitResult::kSuccess;
+  return true;
 }
 
 sql::InitStatus MediaHistoryStore::CreateOrUpgradeIfNeeded() {
@@ -537,28 +473,17 @@
   sql::Transaction transaction(DB());
   if (!transaction.Begin()) {
     LOG(ERROR) << "Failed to begin the transaction.";
-
-    base::UmaHistogramEnumeration(
-        MediaHistoryStore::kSessionWriteResultHistogramName,
-        MediaHistoryStore::SessionWriteResult::kFailedToEstablishTransaction);
-
     return;
   }
 
   auto origin = url::Origin::Create(url);
   if (!CreateOriginId(origin)) {
-    base::UmaHistogramEnumeration(
-        MediaHistoryStore::kSessionWriteResultHistogramName,
-        MediaHistoryStore::SessionWriteResult::kFailedToWriteOrigin);
     return;
   }
 
   auto session_id =
       session_table_->SavePlaybackSession(url, origin, metadata, position);
   if (!session_id) {
-    base::UmaHistogramEnumeration(
-        MediaHistoryStore::kSessionWriteResultHistogramName,
-        MediaHistoryStore::SessionWriteResult::kFailedToWriteSession);
     return;
   }
 
@@ -566,9 +491,6 @@
     auto image_id =
         images_table_->SaveOrGetImage(image.src, origin, image.type);
     if (!image_id) {
-      base::UmaHistogramEnumeration(
-          MediaHistoryStore::kSessionWriteResultHistogramName,
-          MediaHistoryStore::SessionWriteResult::kFailedToWriteImage);
       return;
     }
 
@@ -584,10 +506,6 @@
   }
 
   transaction.Commit();
-
-  base::UmaHistogramEnumeration(
-      MediaHistoryStore::kSessionWriteResultHistogramName,
-      MediaHistoryStore::SessionWriteResult::kSuccess);
 }
 
 std::vector<mojom::MediaHistoryPlaybackSessionRowPtr>
diff --git a/chrome/browser/media/history/media_history_store.h b/chrome/browser/media/history/media_history_store.h
index 49a0a57..35b0207 100644
--- a/chrome/browser/media/history/media_history_store.h
+++ b/chrome/browser/media/history/media_history_store.h
@@ -55,54 +55,6 @@
       base::RepeatingCallback<bool(const base::TimeDelta& duration,
                                    const base::TimeDelta& position)>;
 
-  static const char kInitResultHistogramName[];
-  static const char kInitResultAfterDeleteHistogramName[];
-  static const char kPlaybackWriteResultHistogramName[];
-  static const char kSessionWriteResultHistogramName[];
-  static const char kDatabaseSizeKbHistogramName[];
-
-  // When we initialize the database we store the result in
-  // |kInitResultHistogramName|. Do not change the numbering since this
-  // is recorded.
-  enum class InitResult {
-    kSuccess = 0,
-    kFailedNoForeignKeys = 1,
-    kFailedDatabaseTooNew = 2,
-    kFailedInitializeTables = 3,
-    kFailedToCreateDirectory = 4,
-    kFailedToOpenDatabase = 5,
-    kFailedToEstablishTransaction = 6,
-    kFailedToCreateMetaTable = 7,
-    kFailedToCommitTransaction = 8,
-    kFailedToDeleteOldDatabase = 9,
-    kMaxValue = kFailedToDeleteOldDatabase,
-  };
-
-  // If we write a playback into the database then we record the result to
-  // |kPlaybackWriteResultHistogramName|. Do not change the numbering since this
-  // is recorded.
-  enum class PlaybackWriteResult {
-    kSuccess = 0,
-    kFailedToEstablishTransaction = 1,
-    kFailedToWriteOrigin = 2,
-    kFailedToWritePlayback = 3,
-    kFailedToIncrementAggreatedWatchtime = 4,
-    kFailedToWriteBadOrigin = 5,
-    kMaxValue = kFailedToWriteBadOrigin,
-  };
-
-  // If we write a session into the database then we record the result to
-  // |kSessionWriteResultHistogramName|. Do not change the numbering since this
-  // is recorded.
-  enum class SessionWriteResult {
-    kSuccess = 0,
-    kFailedToEstablishTransaction = 1,
-    kFailedToWriteOrigin = 2,
-    kFailedToWriteSession = 3,
-    kFailedToWriteImage = 4,
-    kMaxValue = kFailedToWriteImage,
-  };
-
  protected:
   friend class MediaHistoryKeyedService;
 
@@ -112,7 +64,7 @@
   // |should_reset| is true then this will delete and reset the DB.
   void Initialize(const bool should_reset);
 
-  InitResult InitializeInternal();
+  bool InitializeInternal();
   sql::InitStatus CreateOrUpgradeIfNeeded();
   sql::InitStatus InitializeTables();
   sql::Database* DB();
diff --git a/chrome/browser/media/history/media_history_store_unittest.cc b/chrome/browser/media/history/media_history_store_unittest.cc
index f385fc1f..51a9227 100644
--- a/chrome/browser/media/history/media_history_store_unittest.cc
+++ b/chrome/browser/media/history/media_history_store_unittest.cc
@@ -12,7 +12,6 @@
 #include "base/task/thread_pool.h"
 #include "base/task/thread_pool/pooled_sequenced_task_runner.h"
 #include "base/test/bind.h"
-#include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/test_timeouts.h"
 #include "build/build_config.h"
@@ -64,8 +63,6 @@
  public:
   MediaHistoryStoreUnitTest() = default;
   void SetUp() override {
-    base::HistogramTester histogram_tester;
-
     // Set up the profile.
     TestingProfile::Builder profile_builder;
     profile_builder.AddTestingFactory(
@@ -83,10 +80,6 @@
     // tearing down the temporary directory.
     WaitForDB();
 
-    histogram_tester.ExpectBucketCount(
-        MediaHistoryStore::kInitResultHistogramName,
-        MediaHistoryStore::InitResult::kSuccess, 1);
-
     // Set up the media history store for OTR.
     otr_service_ = std::make_unique<MediaHistoryKeyedService>(
         profile_->GetPrimaryOTRProfile(/*create_if_needed=*/true));
@@ -204,8 +197,6 @@
                     TestState::kSavingBrowserHistoryDisabled));
 
 TEST_P(MediaHistoryStoreUnitTest, SavePlayback) {
-  base::HistogramTester histogram_tester;
-
   const auto now_before = (base::Time::Now() - base::Minutes(1)).ToJsTime();
 
   // Create a media player watch time and save it to the playbacks table.
@@ -264,10 +255,6 @@
   // The OTR service should have the same data.
   EXPECT_EQ(origins, GetOriginRowsSync(otr_service()));
   EXPECT_EQ(playbacks, GetPlaybackRowsSync(otr_service()));
-
-  histogram_tester.ExpectBucketCount(
-      MediaHistoryStore::kPlaybackWriteResultHistogramName,
-      MediaHistoryStore::PlaybackWriteResult::kSuccess, IsReadOnly() ? 0 : 2);
 }
 
 TEST_P(MediaHistoryStoreUnitTest, SavePlayback_BadOrigin) {
@@ -347,8 +334,6 @@
 }
 
 TEST_P(MediaHistoryStoreUnitTest, UrlShouldBeUniqueForSessions) {
-  base::HistogramTester histogram_tester;
-
   GURL url_a("https://www.google.com");
   GURL url_b("https://www.example.org");
 
@@ -414,10 +399,6 @@
     // The OTR service should have the same data.
     EXPECT_EQ(sessions, GetPlaybackSessionsSync(otr_service(), 5));
   }
-
-  histogram_tester.ExpectBucketCount(
-      MediaHistoryStore::kSessionWriteResultHistogramName,
-      MediaHistoryStore::SessionWriteResult::kSuccess, IsReadOnly() ? 0 : 3);
 }
 
 TEST_P(MediaHistoryStoreUnitTest, SavePlayback_IncrementAggregateWatchtime) {
diff --git a/chrome/browser/metrics/power/battery_discharge_reporter.cc b/chrome/browser/metrics/power/battery_discharge_reporter.cc
index 3c6a40f..61bd158 100644
--- a/chrome/browser/metrics/power/battery_discharge_reporter.cc
+++ b/chrome/browser/metrics/power/battery_discharge_reporter.cc
@@ -82,8 +82,8 @@
   // suffix.
   const std::vector<const char*> long_interval_suffixes{
       "", long_interval_scenario_params.histogram_suffix};
-  ReportAlignedBatteryHistograms(sampling_event_delta, battery_discharge,
-                                 is_initial_interval_, long_interval_suffixes);
+  ReportBatteryHistograms(sampling_event_delta, battery_discharge,
+                          is_initial_interval_, long_interval_suffixes);
   is_initial_interval_ = false;
 }
 
diff --git a/chrome/browser/metrics/power/battery_discharge_reporter_unittest.cc b/chrome/browser/metrics/power/battery_discharge_reporter_unittest.cc
index 91c226ca..5c22859 100644
--- a/chrome/browser/metrics/power/battery_discharge_reporter_unittest.cc
+++ b/chrome/browser/metrics/power/battery_discharge_reporter_unittest.cc
@@ -104,6 +104,33 @@
       const BatteryDischargeReporterTest& rhs) = delete;
   ~BatteryDischargeReporterTest() override = default;
 
+  // Tests that the right BatteryDischargeMode histogram sample is emitted given
+  // the battery states before and after an interval.
+  void TestBatteryDischargeMode(
+      const absl::optional<base::BatteryLevelProvider::BatteryState>&
+          previous_battery_state,
+      const absl::optional<base::BatteryLevelProvider::BatteryState>&
+          new_battery_state,
+      BatteryDischargeMode expected_mode) {
+    TestUsageScenarioDataStoreImpl usage_scenario_data_store;
+
+    base::BatteryStateSampler battery_state_sampler(
+        std::make_unique<NoopSamplingEventSource>(),
+        std::make_unique<NoopBatteryLevelProvider>());
+    BatteryDischargeReporter battery_discharge_reporter(
+        &battery_state_sampler, &usage_scenario_data_store);
+
+    battery_discharge_reporter.OnBatteryStateSampled(previous_battery_state);
+    task_environment_.FastForwardBy(base::Minutes(1));
+    battery_discharge_reporter.OnBatteryStateSampled(new_battery_state);
+
+    const std::vector<const char*> suffixes(
+        {"", ".Initial", ".ZeroWindow", ".ZeroWindow.Initial"});
+    ExpectHistogramSamples(&histogram_tester_, suffixes,
+                           {{kBatteryDischargeModeHistogramName,
+                             static_cast<int>(expected_mode)}});
+  }
+
  protected:
   content::BrowserTaskEnvironment task_environment_{
       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
@@ -253,3 +280,145 @@
   histogram_tester_.ExpectTotalCount(kBatteryDischargeRateRelativeHistogramName,
                                      1);
 }
+
+TEST_F(BatteryDischargeReporterTest, RetrievalError) {
+  TestBatteryDischargeMode(absl::nullopt, absl::nullopt,
+                           BatteryDischargeMode::kRetrievalError);
+}
+
+TEST_F(BatteryDischargeReporterTest, StateChanged_Battery) {
+  TestBatteryDischargeMode(
+      base::BatteryLevelProvider::BatteryState{
+          .battery_count = 0,
+      },
+      base::BatteryLevelProvider::BatteryState{
+          .battery_count = 1,
+      },
+      BatteryDischargeMode::kStateChanged);
+}
+
+TEST_F(BatteryDischargeReporterTest, StateChanged_PluggedIn) {
+  TestBatteryDischargeMode(
+      base::BatteryLevelProvider::BatteryState{
+          .battery_count = 1,
+          .is_external_power_connected = true,
+      },
+      base::BatteryLevelProvider::BatteryState{
+          .battery_count = 1,
+          .is_external_power_connected = false,
+      },
+      BatteryDischargeMode::kStateChanged);
+}
+
+TEST_F(BatteryDischargeReporterTest, NoBattery) {
+  TestBatteryDischargeMode(
+      base::BatteryLevelProvider::BatteryState{
+          .battery_count = 0,
+      },
+      base::BatteryLevelProvider::BatteryState{
+          .battery_count = 0,
+      },
+      BatteryDischargeMode::kNoBattery);
+}
+
+TEST_F(BatteryDischargeReporterTest, PluggedIn) {
+  TestBatteryDischargeMode(
+      base::BatteryLevelProvider::BatteryState{
+          .battery_count = 1,
+          .is_external_power_connected = true,
+      },
+      base::BatteryLevelProvider::BatteryState{
+          .battery_count = 1,
+          .is_external_power_connected = true,
+      },
+      BatteryDischargeMode::kPluggedIn);
+}
+
+TEST_F(BatteryDischargeReporterTest, MultipleBatteries) {
+  TestBatteryDischargeMode(
+      base::BatteryLevelProvider::BatteryState{
+          .battery_count = 2,
+          .is_external_power_connected = false,
+      },
+      base::BatteryLevelProvider::BatteryState{
+          .battery_count = 2,
+          .is_external_power_connected = false,
+      },
+      BatteryDischargeMode::kMultipleBatteries);
+}
+
+TEST_F(BatteryDischargeReporterTest, InsufficientResolution) {
+  TestBatteryDischargeMode(
+      base::BatteryLevelProvider::BatteryState{
+          .battery_count = 1,
+          .is_external_power_connected = false,
+          .charge_unit =
+              base::BatteryLevelProvider::BatteryLevelUnit::kRelative,
+      },
+      base::BatteryLevelProvider::BatteryState{
+          .battery_count = 1,
+          .is_external_power_connected = false,
+          .charge_unit =
+              base::BatteryLevelProvider::BatteryLevelUnit::kRelative,
+      },
+      BatteryDischargeMode::kInsufficientResolution);
+}
+
+#if BUILDFLAG(IS_MAC)
+TEST_F(BatteryDischargeReporterTest, MacFullyCharged) {
+  TestBatteryDischargeMode(
+      base::BatteryLevelProvider::BatteryState{
+          .battery_count = 1,
+          .is_external_power_connected = false,
+          .current_capacity = 100,
+          .full_charged_capacity = 100,
+          .charge_unit = base::BatteryLevelProvider::BatteryLevelUnit::kMWh,
+      },
+      base::BatteryLevelProvider::BatteryState{
+          .battery_count = 1,
+          .is_external_power_connected = false,
+          .current_capacity = 99,
+          .full_charged_capacity = 100,
+          .charge_unit = base::BatteryLevelProvider::BatteryLevelUnit::kMWh,
+      },
+      BatteryDischargeMode::kMacFullyCharged);
+}
+#endif  // BUILDFLAG(IS_MAC)
+
+TEST_F(BatteryDischargeReporterTest, FullChargedCapacityIsZero) {
+  TestBatteryDischargeMode(
+      base::BatteryLevelProvider::BatteryState{
+          .battery_count = 1,
+          .is_external_power_connected = false,
+          .current_capacity = 10,
+          .full_charged_capacity = 0,
+          .charge_unit = base::BatteryLevelProvider::BatteryLevelUnit::kMWh,
+      },
+      base::BatteryLevelProvider::BatteryState{
+          .battery_count = 1,
+          .is_external_power_connected = false,
+          .current_capacity = 10,
+          .full_charged_capacity = 0,
+          .charge_unit = base::BatteryLevelProvider::BatteryLevelUnit::kMWh,
+      },
+      BatteryDischargeMode::kFullChargedCapacityIsZero);
+}
+
+TEST_F(BatteryDischargeReporterTest, BatteryLevelIncreased) {
+  TestBatteryDischargeMode(
+      base::BatteryLevelProvider::BatteryState{
+          .battery_count = 1,
+          .is_external_power_connected = false,
+          .current_capacity = 40,
+          .full_charged_capacity = 100,
+          .charge_unit = base::BatteryLevelProvider::BatteryLevelUnit::kMWh,
+      },
+      base::BatteryLevelProvider::BatteryState{
+          .battery_count = 1,
+          .is_external_power_connected = false,
+          .current_capacity = 50,
+          .full_charged_capacity = 100,
+          .charge_unit = base::BatteryLevelProvider::BatteryLevelUnit::kMWh,
+      },
+      BatteryDischargeMode::kBatteryLevelIncreased);
+}
diff --git a/chrome/browser/metrics/power/power_metrics.cc b/chrome/browser/metrics/power/power_metrics.cc
index 54c8cfa..1eeaac4 100644
--- a/chrome/browser/metrics/power/power_metrics.cc
+++ b/chrome/browser/metrics/power/power_metrics.cc
@@ -16,16 +16,11 @@
 
 namespace {
 
-constexpr const char* kBatteryDischargeRateHistogramName =
-    "Power.BatteryDischargeRate2";
-constexpr const char* kBatteryDischargeModeHistogramName =
-    "Power.BatteryDischargeMode2";
-
-constexpr const char* kAlignedBatteryDischargeRateMilliwattsHistogramName =
+constexpr const char* kBatteryDischargeRateMilliwattsHistogramName =
     "Power.BatteryDischargeRateMilliwatts5";
-constexpr const char* kAlignedBatteryDischargeRateRelativeHistogramName =
+constexpr const char* kBatteryDischargeRateRelativeHistogramName =
     "Power.BatteryDischargeRateRelative5";
-constexpr const char* kAlignedBatteryDischargeModeHistogramName =
+constexpr const char* kBatteryDischargeModeHistogramName =
     "Power.BatteryDischargeMode5";
 
 #if BUILDFLAG(IS_MAC)
@@ -177,8 +172,9 @@
   const auto discharge_rate_mw = CalculateDischargeRateMilliwatts(
       previous_battery_state, new_battery_state, interval_duration);
 
-  if (discharge_rate_relative < 0 || discharge_rate_mw < 0)
+  if (discharge_rate_relative < 0 || discharge_rate_mw < 0) {
     return {BatteryDischargeMode::kBatteryLevelIncreased, absl::nullopt};
+  }
   return {BatteryDischargeMode::kDischarging, discharge_rate_mw,
           discharge_rate_relative};
 }
@@ -186,24 +182,6 @@
 void ReportBatteryHistograms(
     base::TimeDelta interval_duration,
     BatteryDischarge battery_discharge,
-    const std::vector<const char*>& scenario_suffixes) {
-  for (const char* scenario_suffix : scenario_suffixes) {
-    base::UmaHistogramEnumeration(
-        base::StrCat({kBatteryDischargeModeHistogramName, scenario_suffix}),
-        battery_discharge.mode);
-
-    if (battery_discharge.mode == BatteryDischargeMode::kDischarging) {
-      DCHECK(battery_discharge.rate_relative.has_value());
-      base::UmaHistogramCounts1000(
-          base::StrCat({kBatteryDischargeRateHistogramName, scenario_suffix}),
-          *battery_discharge.rate_relative);
-    }
-  }
-}
-
-void ReportAlignedBatteryHistograms(
-    base::TimeDelta interval_duration,
-    BatteryDischarge battery_discharge,
     bool is_initial_interval,
     const std::vector<const char*>& scenario_suffixes) {
   const char* interval_type_suffixes[] = {
@@ -212,19 +190,19 @@
   for (const char* scenario_suffix : scenario_suffixes) {
     for (const char* interval_type_suffix : interval_type_suffixes) {
       base::UmaHistogramEnumeration(
-          base::StrCat({kAlignedBatteryDischargeModeHistogramName,
-                        scenario_suffix, interval_type_suffix}),
+          base::StrCat({kBatteryDischargeModeHistogramName, scenario_suffix,
+                        interval_type_suffix}),
           battery_discharge.mode);
 
       if (battery_discharge.mode == BatteryDischargeMode::kDischarging) {
         DCHECK(battery_discharge.rate_milliwatts.has_value());
         base::UmaHistogramCounts100000(
-            base::StrCat({kAlignedBatteryDischargeRateMilliwattsHistogramName,
+            base::StrCat({kBatteryDischargeRateMilliwattsHistogramName,
                           scenario_suffix, interval_type_suffix}),
             *battery_discharge.rate_milliwatts);
         DCHECK(battery_discharge.rate_relative.has_value());
         base::UmaHistogramCounts1000(
-            base::StrCat({kAlignedBatteryDischargeRateRelativeHistogramName,
+            base::StrCat({kBatteryDischargeRateRelativeHistogramName,
                           scenario_suffix, interval_type_suffix}),
             *battery_discharge.rate_relative);
       }
diff --git a/chrome/browser/metrics/power/power_metrics.h b/chrome/browser/metrics/power/power_metrics.h
index 00cf194..c9fd6af 100644
--- a/chrome/browser/metrics/power/power_metrics.h
+++ b/chrome/browser/metrics/power/power_metrics.h
@@ -61,17 +61,9 @@
 // Report battery metrics to histograms with |scenario_suffixes|.
 void ReportBatteryHistograms(base::TimeDelta interval_duration,
                              BatteryDischarge battery_discharge,
+                             bool is_initial_interval,
                              const std::vector<const char*>& scenario_suffixes);
 
-// Report battery metrics to histograms with |scenario_suffixes|. The difference
-// with the above version is that when possible, the intervals are aligned with
-// battery discharge notifications from the OS (MacOS only for now).
-void ReportAlignedBatteryHistograms(
-    base::TimeDelta interval_duration,
-    BatteryDischarge battery_discharge,
-    bool is_initial_interval,
-    const std::vector<const char*>& scenario_suffixes);
-
 #if BUILDFLAG(IS_MAC)
 void ReportShortIntervalHistograms(
     const char* scenario_suffix,
diff --git a/chrome/browser/metrics/power/power_metrics_reporter.cc b/chrome/browser/metrics/power/power_metrics_reporter.cc
index b3e430d..b495992 100644
--- a/chrome/browser/metrics/power/power_metrics_reporter.cc
+++ b/chrome/browser/metrics/power/power_metrics_reporter.cc
@@ -32,12 +32,6 @@
 constexpr const char* kBatterySamplingDelayHistogramName =
     "Power.BatterySamplingDelay";
 
-bool IsWithinTolerance(base::TimeDelta value,
-                       base::TimeDelta expected,
-                       base::TimeDelta tolerance) {
-  return (value - expected).magnitude() < tolerance;
-}
-
 // Calculates the UKM bucket |value| falls in and returns it. This uses an
 // exponential bucketing approach with an exponent base of 1.3, resulting in
 // 17 buckets for an interval of 120 seconds.
@@ -348,22 +342,6 @@
   // Report UKMs.
   ReportBatteryUKMs(long_interval_data, aggregated_process_metrics,
                     interval_duration, battery_discharge);
-
-  // Ratio by which the time elapsed can deviate from
-  // |kLongPowerMetricsIntervalDuration| without invalidating this sample.
-  // TODO(pmonette): Change to DCHECK after ensuring this never triggers.
-  CHECK_GE(interval_duration, kLongPowerMetricsIntervalDuration);
-  constexpr double kTolerableTimeElapsedRatio = 0.10;
-  if (battery_discharge.mode == BatteryDischargeMode::kDischarging &&
-      !IsWithinTolerance(
-          interval_duration, kLongPowerMetricsIntervalDuration,
-          kLongPowerMetricsIntervalDuration * kTolerableTimeElapsedRatio)) {
-    battery_discharge.mode = BatteryDischargeMode::kInvalidInterval;
-  }
-
-  ReportBatteryHistograms(
-      interval_duration, battery_discharge,
-      {"", GetLongIntervalScenario(long_interval_data).histogram_suffix});
 }
 
 void PowerMetricsReporter::ReportBatteryUKMs(
diff --git a/chrome/browser/metrics/power/power_metrics_reporter_unittest.cc b/chrome/browser/metrics/power/power_metrics_reporter_unittest.cc
index b239e87..709a7a36 100644
--- a/chrome/browser/metrics/power/power_metrics_reporter_unittest.cc
+++ b/chrome/browser/metrics/power/power_metrics_reporter_unittest.cc
@@ -29,14 +29,6 @@
 
 namespace {
 
-constexpr const char* kBatteryDischargeRateHistogramName =
-    "Power.BatteryDischargeRate2";
-constexpr const char* kBatteryDischargeModeHistogramName =
-    "Power.BatteryDischargeMode2";
-
-constexpr double kTolerableTimeElapsedRatio = 0.10;
-constexpr double kTolerablePositiveDrift = 1 + kTolerableTimeElapsedRatio;
-
 base::BatteryLevelProvider::BatteryState MakeBatteryDischargingState(
     int battery_percent) {
   return base::BatteryLevelProvider::BatteryState{
@@ -327,43 +319,6 @@
 }
 #endif
 
-TEST_F(PowerMetricsReporterUnitTest, BatteryDischargeCaptureIsTooLate) {
-  ProcessMonitor::Metrics aggregated_process_metrics = {};
-  process_monitor_.SetMetricsToReturn(aggregated_process_metrics);
-
-  // Pretend that the battery has dropped by 2%.
-  battery_states_.push(MakeBatteryDischargingState(48));
-
-  const base::TimeDelta kTooLate =
-      kLongPowerMetricsIntervalDuration * kTolerablePositiveDrift +
-      base::Microseconds(1);
-  process_monitor_.ForceSampleAllProcessesIn(power_metrics_reporter_.get(),
-                                             &task_environment_, kTooLate);
-
-  histogram_tester_.ExpectTotalCount(kBatteryDischargeRateHistogramName, 0);
-  histogram_tester_.ExpectUniqueSample(kBatteryDischargeModeHistogramName,
-                                       BatteryDischargeMode::kInvalidInterval,
-                                       1);
-}
-
-TEST_F(PowerMetricsReporterUnitTest, BatteryDischargeCaptureIsLate) {
-  ProcessMonitor::Metrics aggregated_process_metrics = {};
-  process_monitor_.SetMetricsToReturn(aggregated_process_metrics);
-
-  // Pretend that the battery has dropped by 2%.
-  battery_states_.push(MakeBatteryDischargingState(48));
-
-  const base::TimeDelta kLate =
-      kLongPowerMetricsIntervalDuration * kTolerablePositiveDrift -
-      base::Microseconds(1);
-  process_monitor_.ForceSampleAllProcessesIn(power_metrics_reporter_.get(),
-                                             &task_environment_, kLate);
-
-  histogram_tester_.ExpectTotalCount(kBatteryDischargeRateHistogramName, 1);
-  histogram_tester_.ExpectUniqueSample(kBatteryDischargeModeHistogramName,
-                                       BatteryDischargeMode::kDischarging, 1);
-}
-
 TEST_F(PowerMetricsReporterUnitTest, UKMs) {
   int fake_value = 42;
 
@@ -490,11 +445,6 @@
           fake_interval_data.longest_visible_origin_duration));
   test_ukm_recorder_.ExpectEntryMetric(
       entries[0], UkmEntry::kDeviceSleptDuringIntervalName, false);
-
-  histogram_tester_.ExpectUniqueSample(kBatteryDischargeRateHistogramName, 2500,
-                                       1);
-  histogram_tester_.ExpectUniqueSample(kBatteryDischargeModeHistogramName,
-                                       BatteryDischargeMode::kDischarging, 1);
 }
 
 TEST_F(PowerMetricsReporterUnitTest, UKMsBrowserShuttingDown) {
@@ -565,10 +515,6 @@
   test_ukm_recorder_.ExpectEntryMetric(
       entries[0], UkmEntry::kBatteryDischargeModeName,
       static_cast<int64_t>(BatteryDischargeMode::kPluggedIn));
-
-  histogram_tester_.ExpectTotalCount(kBatteryDischargeRateHistogramName, 0);
-  histogram_tester_.ExpectUniqueSample(kBatteryDischargeModeHistogramName,
-                                       BatteryDischargeMode::kPluggedIn, 1);
 }
 
 TEST_F(PowerMetricsReporterUnitTest, UKMsBatteryStateChanges) {
@@ -599,10 +545,6 @@
   test_ukm_recorder_.ExpectEntryMetric(
       entries[0], UkmEntry::kBatteryDischargeModeName,
       static_cast<int64_t>(BatteryDischargeMode::kStateChanged));
-
-  histogram_tester_.ExpectTotalCount(kBatteryDischargeRateHistogramName, 0);
-  histogram_tester_.ExpectUniqueSample(kBatteryDischargeModeHistogramName,
-                                       BatteryDischargeMode::kStateChanged, 1);
 }
 
 TEST_F(PowerMetricsReporterUnitTest, UKMsBatteryStateUnavailable) {
@@ -626,11 +568,6 @@
   test_ukm_recorder_.ExpectEntryMetric(
       entries[0], UkmEntry::kBatteryDischargeModeName,
       static_cast<int64_t>(BatteryDischargeMode::kRetrievalError));
-
-  histogram_tester_.ExpectTotalCount(kBatteryDischargeRateHistogramName, 0);
-  histogram_tester_.ExpectUniqueSample(kBatteryDischargeModeHistogramName,
-                                       BatteryDischargeMode::kRetrievalError,
-                                       1);
 }
 
 TEST_F(PowerMetricsReporterUnitTest, UKMsNoBattery) {
@@ -664,10 +601,6 @@
   test_ukm_recorder_.ExpectEntryMetric(
       entries[0], UkmEntry::kBatteryDischargeModeName,
       static_cast<int64_t>(BatteryDischargeMode::kNoBattery));
-
-  histogram_tester_.ExpectTotalCount(kBatteryDischargeRateHistogramName, 0);
-  histogram_tester_.ExpectUniqueSample(kBatteryDischargeModeHistogramName,
-                                       BatteryDischargeMode::kNoBattery, 1);
 }
 
 #if BUILDFLAG(IS_MAC)
@@ -695,11 +628,6 @@
   test_ukm_recorder_.ExpectEntryMetric(
       entries[0], UkmEntry::kBatteryDischargeModeName,
       static_cast<int64_t>(BatteryDischargeMode::kMacFullyCharged));
-
-  histogram_tester_.ExpectTotalCount(kBatteryDischargeRateHistogramName, 0);
-  histogram_tester_.ExpectUniqueSample(kBatteryDischargeModeHistogramName,
-                                       BatteryDischargeMode::kMacFullyCharged,
-                                       1);
 }
 #endif  // BUILDFLAG(IS_MAC)
 
@@ -725,11 +653,6 @@
   test_ukm_recorder_.ExpectEntryMetric(
       entries[0], UkmEntry::kBatteryDischargeModeName,
       static_cast<int64_t>(BatteryDischargeMode::kBatteryLevelIncreased));
-
-  histogram_tester_.ExpectTotalCount(kBatteryDischargeRateHistogramName, 0);
-  histogram_tester_.ExpectUniqueSample(
-      kBatteryDischargeModeHistogramName,
-      BatteryDischargeMode::kBatteryLevelIncreased, 1);
 }
 
 TEST_F(PowerMetricsReporterUnitTest, UKMsNoTab) {
diff --git a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionController.java b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionController.java
index 6b3ddef..99fdc70a 100644
--- a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionController.java
+++ b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionController.java
@@ -138,10 +138,11 @@
      * permission request directly and when to show a rationale beforehand.
      * @param contextual Whether this request is made in context. True for requesting from features
      *        using notifications, false for invoking on startup.
+     * @return True if any UI was shown (either rationale dialog or OS prompt), false otherwise.
      */
-    public void requestPermissionIfNeeded(boolean contextual) {
+    public boolean requestPermissionIfNeeded(boolean contextual) {
         if (!BuildInfo.isAtLeastT() || !BuildInfo.targetsAtLeastT()) {
-            return;
+            return false;
         }
 
         // Record the state of the notification permission before trying to ask but after verifying
@@ -150,7 +151,7 @@
 
         @PermissionRequestMode
         int requestMode = shouldRequestPermission();
-        if (requestMode == PermissionRequestMode.DO_NOT_REQUEST) return;
+        if (requestMode == PermissionRequestMode.DO_NOT_REQUEST) return false;
 
         SharedPreferencesManager.getInstance().incrementInt(
                 ChromePreferenceKeys.NOTIFICATION_PERMISSION_REQUEST_COUNT);
@@ -168,6 +169,7 @@
                 }
             });
         }
+        return true;
     }
 
     @PermissionRequestMode
diff --git a/chrome/browser/policy/messaging_layer/upload/fake_upload_client.cc b/chrome/browser/policy/messaging_layer/upload/fake_upload_client.cc
index e8a8ba0..9de877e7 100644
--- a/chrome/browser/policy/messaging_layer/upload/fake_upload_client.cc
+++ b/chrome/browser/policy/messaging_layer/upload/fake_upload_client.cc
@@ -113,8 +113,7 @@
       std::move(encryption_key_attached_cb));
 
   ReportingServerConnector::UploadEncryptedReport(
-      std::move(request_result.value()), base::Value::Dict(),
-      std::move(response_cb));
+      std::move(request_result.value()), std::move(response_cb));
   return Status::StatusOK();
 }
 
diff --git a/chrome/browser/policy/messaging_layer/upload/record_handler_impl.cc b/chrome/browser/policy/messaging_layer/upload/record_handler_impl.cc
index a222921..dac7ff70 100644
--- a/chrome/browser/policy/messaging_layer/upload/record_handler_impl.cc
+++ b/chrome/browser/policy/messaging_layer/upload/record_handler_impl.cc
@@ -23,8 +23,6 @@
 #include "chrome/browser/policy/messaging_layer/upload/event_upload_size_controller.h"
 #include "chrome/browser/policy/messaging_layer/upload/record_upload_request_builder.h"
 #include "chrome/browser/policy/messaging_layer/util/reporting_server_connector.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/profiles/reporting_util.h"
 #include "components/reporting/proto/synced/record.pb.h"
 #include "components/reporting/proto/synced/record_constants.pb.h"
 #include "components/reporting/resources/resource_interface.h"
@@ -194,9 +192,7 @@
           [](base::Value::Dict request,
              ReportingServerConnector::ResponseCallback response_cb) {
             ReportingServerConnector::UploadEncryptedReport(
-                std::move(request),
-                GetContext(ProfileManager::GetPrimaryUserProfile()),
-                std::move(response_cb));
+                std::move(request), std::move(response_cb));
           },
           std::move(request_result.value()), std::move(response_cb)));
 }
diff --git a/chrome/browser/policy/messaging_layer/util/reporting_server_connector.cc b/chrome/browser/policy/messaging_layer/util/reporting_server_connector.cc
index 34e265b..002bc57 100644
--- a/chrome/browser/policy/messaging_layer/util/reporting_server_connector.cc
+++ b/chrome/browser/policy/messaging_layer/util/reporting_server_connector.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/profiles/reporting_util.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "components/policy/core/common/cloud/cloud_policy_client.h"
 #include "components/policy/core/common/cloud/cloud_policy_client_registration_helper.h"
@@ -194,7 +195,6 @@
 // static
 void ReportingServerConnector::UploadEncryptedReport(
     base::Value::Dict merging_payload,
-    absl::optional<base::Value::Dict> context,
     ResponseCallback callback) {
   // This function should be called on the UI task runner, and if it isn't, it
   // reschedules itself to do so.
@@ -202,11 +202,25 @@
     ::content::GetUIThreadTaskRunner({})->PostTask(
         FROM_HERE,
         base::BindOnce(&ReportingServerConnector::UploadEncryptedReport,
-                       std::move(merging_payload), std::move(context),
-                       std::move(callback)));
+                       std::move(merging_payload), std::move(callback)));
     return;
   }
   // Now we are on UI task runner.
+
+  // Acquire context for the upload.
+  Profile* profile = nullptr;
+#if BUILDFLAG(IS_CHROMEOS)
+  profile = ProfileManager::GetPrimaryUserProfile();
+#else
+  if (g_browser_process) {
+    auto* const profile_manager = g_browser_process->profile_manager();
+    if (profile_manager) {
+      profile = profile_manager->GetLastUsedProfileIfLoaded();
+    }
+  }
+#endif
+  auto context = GetContext(profile);
+
   // The `policy::CloudPolicyClient` object is retrieved in two different ways
   // for ChromeOS and non-ChromeOS browsers.
   ReportingServerConnector* const connector = GetInstance();
diff --git a/chrome/browser/policy/messaging_layer/util/reporting_server_connector.h b/chrome/browser/policy/messaging_layer/util/reporting_server_connector.h
index 6a7bd83..261f365 100644
--- a/chrome/browser/policy/messaging_layer/util/reporting_server_connector.h
+++ b/chrome/browser/policy/messaging_layer/util/reporting_server_connector.h
@@ -14,7 +14,6 @@
 #include "components/policy/core/common/cloud/cloud_policy_core.h"
 #include "components/reporting/util/status.h"
 #include "components/reporting/util/statusor.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace reporting {
 
@@ -47,7 +46,6 @@
   // the upload fails). The `callback` will be called when the operation
   // completes or fails.
   static void UploadEncryptedReport(base::Value::Dict merging_payload,
-                                    absl::optional<base::Value::Dict> context,
                                     ResponseCallback callback);
 
  private:
diff --git a/chrome/browser/policy/messaging_layer/util/reporting_server_connector_unittest.cc b/chrome/browser/policy/messaging_layer/util/reporting_server_connector_unittest.cc
index 881308f..1461e98 100644
--- a/chrome/browser/policy/messaging_layer/util/reporting_server_connector_unittest.cc
+++ b/chrome/browser/policy/messaging_layer/util/reporting_server_connector_unittest.cc
@@ -77,7 +77,7 @@
       FROM_HERE,
       base::BindOnce(&ReportingServerConnector::UploadEncryptedReport,
                      /*merging_payload=*/base::Value::Dict(),
-                     /*context=*/absl::nullopt, response_event.cb()));
+                     response_event.cb()));
   EXPECT_OK(response_event.result());
 }
 
@@ -90,7 +90,7 @@
       FROM_HERE,
       base::BindOnce(&ReportingServerConnector::UploadEncryptedReport,
                      /*merging_payload=*/base::Value::Dict(),
-                     /*context=*/absl::nullopt, response_event.cb()));
+                     response_event.cb()));
   EXPECT_OK(response_event.result());
 }
 }  // namespace reporting
diff --git a/chrome/browser/reputation/local_heuristics.cc b/chrome/browser/reputation/local_heuristics.cc
index ef3aced..c5561a4 100644
--- a/chrome/browser/reputation/local_heuristics.cc
+++ b/chrome/browser/reputation/local_heuristics.cc
@@ -92,7 +92,7 @@
       // For now, no safety tip is shown for domain names that fail spoof checks
       // and don't have a suggested URL.
       return false;
-    case LookalikeUrlMatchType::kSiteEngagement:
+    case LookalikeUrlMatchType::kSkeletonMatchSiteEngagement:
     case LookalikeUrlMatchType::kSkeletonMatchTop500:
       // We should only ever reach these cases when the lookalike interstitial
       // is disabled. Now that interstitial is fully launched, this only happens
diff --git a/chrome/browser/resource_coordinator/resource_coordinator_parts.cc b/chrome/browser/resource_coordinator/resource_coordinator_parts.cc
index f97e7cfd..24eca74 100644
--- a/chrome/browser/resource_coordinator/resource_coordinator_parts.cc
+++ b/chrome/browser/resource_coordinator/resource_coordinator_parts.cc
@@ -5,14 +5,12 @@
 #include "chrome/browser/resource_coordinator/resource_coordinator_parts.h"
 
 #include "build/build_config.h"
-#include "components/performance_manager/performance_manager_impl.h"
 
 namespace resource_coordinator {
 
 ResourceCoordinatorParts::ResourceCoordinatorParts()
 #if !BUILDFLAG(IS_ANDROID)
-    : tab_manager_(&tab_load_tracker_),
-      tab_lifecycle_unit_source_(tab_manager_.usage_clock())
+    : tab_lifecycle_unit_source_(tab_manager_.usage_clock())
 #endif
 {
 #if !BUILDFLAG(IS_ANDROID)
diff --git a/chrome/browser/resource_coordinator/resource_coordinator_parts.h b/chrome/browser/resource_coordinator/resource_coordinator_parts.h
index 632925b..12363e8 100644
--- a/chrome/browser/resource_coordinator/resource_coordinator_parts.h
+++ b/chrome/browser/resource_coordinator/resource_coordinator_parts.h
@@ -58,8 +58,8 @@
   }
 
  private:
-  // This should be declared before |tab_memory_metrics_reporter_| and
-  // |tab_manager_| as they both depend on this at shutdown.
+  // This should be declared before |tab_memory_metrics_reporter_| because it
+  // depends on this at shutdown.
   TabLoadTracker tab_load_tracker_;
 
   // Created on demand the first time it's being accessed.
diff --git a/chrome/browser/resource_coordinator/tab_manager.cc b/chrome/browser/resource_coordinator/tab_manager.cc
index fcbb750..480e058d 100644
--- a/chrome/browser/resource_coordinator/tab_manager.cc
+++ b/chrome/browser/resource_coordinator/tab_manager.cc
@@ -40,7 +40,6 @@
 #include "chrome/browser/resource_coordinator/tab_lifecycle_unit_external.h"
 #include "chrome/browser/resource_coordinator/tab_manager_features.h"
 #include "chrome/browser/resource_coordinator/tab_manager_resource_coordinator_signal_observer.h"
-#include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h"
 #include "chrome/browser/resource_coordinator/time.h"
 #include "chrome/browser/sessions/session_restore.h"
 #include "chrome/browser/ui/browser.h"
@@ -97,14 +96,6 @@
   ~TabManagerSessionRestoreObserver() { SessionRestore::RemoveObserver(this); }
 
   // SessionRestoreObserver implementation:
-  void OnSessionRestoreStartedLoadingTabs() override {
-    tab_manager_->OnSessionRestoreStartedLoadingTabs();
-  }
-
-  void OnSessionRestoreFinishedLoadingTabs() override {
-    tab_manager_->OnSessionRestoreFinishedLoadingTabs();
-  }
-
   void OnWillRestoreTab(WebContents* web_contents) override {
     tab_manager_->OnWillRestoreTab(web_contents);
   }
@@ -113,25 +104,16 @@
   raw_ptr<TabManager> tab_manager_;
 };
 
-TabManager::TabManager(TabLoadTracker* tab_load_tracker)
-    : browser_tab_strip_tracker_(this, nullptr),
-      is_session_restore_loading_tabs_(false),
-      restored_tab_count_(0u),
-      tab_load_tracker_(tab_load_tracker) {
+TabManager::TabManager() {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   delegate_ =
       std::make_unique<TabManagerDelegate>(weak_ptr_factory_.GetWeakPtr());
 #endif
-  browser_tab_strip_tracker_.Init();
   session_restore_observer_ =
       std::make_unique<TabManagerSessionRestoreObserver>(this);
-
-  tab_load_tracker_->AddObserver(this);
 }
 
-TabManager::~TabManager() {
-  tab_load_tracker_->RemoveObserver(this);
-}
+TabManager::~TabManager() = default;
 
 void TabManager::Start() {
   // On Linux, there is no tab discarding because MemoryPressureMonitor is not
@@ -248,16 +230,6 @@
   return tab_count;
 }
 
-// static
-bool TabManager::IsTabInSessionRestore(WebContents* web_contents) {
-  return GetWebContentsData(web_contents)->is_in_session_restore();
-}
-
-// static
-bool TabManager::IsTabRestoredInForeground(WebContents* web_contents) {
-  return GetWebContentsData(web_contents)->is_restored_in_foreground();
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 // TabManager, private:
 
@@ -324,39 +296,6 @@
 }
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-void TabManager::OnTabStripModelChanged(
-    TabStripModel* tab_strip_model,
-    const TabStripModelChange& change,
-    const TabStripSelectionChange& selection) {
-  if (change.type() == TabStripModelChange::kReplaced) {
-    auto* replace = change.GetReplace();
-    WebContentsData::CopyState(replace->old_contents, replace->new_contents);
-  }
-}
-
-void TabManager::OnStartTracking(content::WebContents* web_contents,
-                                 LoadingState loading_state) {
-  GetWebContentsData(web_contents)->SetTabLoadingState(loading_state);
-}
-
-void TabManager::OnLoadingStateChange(content::WebContents* web_contents,
-                                      LoadingState old_loading_state,
-                                      LoadingState new_loading_state) {
-  GetWebContentsData(web_contents)->SetTabLoadingState(new_loading_state);
-}
-
-void TabManager::OnStopTracking(content::WebContents* web_contents,
-                                LoadingState loading_state) {
-  GetWebContentsData(web_contents)->SetTabLoadingState(loading_state);
-}
-
-// static
-TabManager::WebContentsData* TabManager::GetWebContentsData(
-    content::WebContents* contents) {
-  WebContentsData::CreateForWebContents(contents);
-  return WebContentsData::FromWebContents(contents);
-}
-
 // TODO(jamescook): This should consider tabs with references to other tabs,
 // such as tabs created with JavaScript window.open(). Potentially consider
 // discarding the entire set together, or use that in the priority computation.
@@ -381,25 +320,7 @@
   return nullptr;
 }
 
-void TabManager::OnSessionRestoreStartedLoadingTabs() {
-  DCHECK(!is_session_restore_loading_tabs_);
-  is_session_restore_loading_tabs_ = true;
-}
-
-void TabManager::OnSessionRestoreFinishedLoadingTabs() {
-  DCHECK(is_session_restore_loading_tabs_);
-  is_session_restore_loading_tabs_ = false;
-  restored_tab_count_ = 0u;
-}
-
 void TabManager::OnWillRestoreTab(WebContents* contents) {
-  WebContentsData* data = GetWebContentsData(contents);
-  DCHECK(!data->is_in_session_restore());
-  data->SetIsInSessionRestore(true);
-  data->SetIsRestoredInForeground(contents->GetVisibility() !=
-                                  content::Visibility::HIDDEN);
-  restored_tab_count_++;
-
   // TabUIHelper is initialized in TabHelpers::AttachTabHelpers. But this place
   // gets called earlier than that. So for restored tabs, also initialize their
   // TabUIHelper here.
diff --git a/chrome/browser/resource_coordinator/tab_manager.h b/chrome/browser/resource_coordinator/tab_manager.h
index b53d439..b546ae05 100644
--- a/chrome/browser/resource_coordinator/tab_manager.h
+++ b/chrome/browser/resource_coordinator/tab_manager.h
@@ -23,17 +23,13 @@
 #include "chrome/browser/resource_coordinator/lifecycle_unit_source_observer.h"
 #include "chrome/browser/resource_coordinator/lifecycle_unit_state.mojom-forward.h"
 #include "chrome/browser/resource_coordinator/tab_lifecycle_observer.h"
-#include "chrome/browser/resource_coordinator/tab_load_tracker.h"
 #include "chrome/browser/resource_coordinator/tab_manager_features.h"
 #include "chrome/browser/resource_coordinator/usage_clock.h"
 #include "chrome/browser/sessions/session_restore_observer.h"
-#include "chrome/browser/ui/browser_tab_strip_tracker.h"
-#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "content/public/browser/navigation_throttle.h"
 #include "ui/gfx/native_widget_types.h"
 
 class GURL;
-class TabStripModel;
 
 namespace content {
 class WebContents;
@@ -57,18 +53,14 @@
 //
 // TODO(fdoray): Rename to LifecycleManager. https://crbug.com/775644
 class TabManager : public LifecycleUnitObserver,
-                   public LifecycleUnitSourceObserver,
-                   public TabLoadTracker::Observer,
-                   public TabStripModelObserver {
+                   public LifecycleUnitSourceObserver {
  public:
   // Forward declaration of resource coordinator signal observer.
   class ResourceCoordinatorSignalObserver;
 
-  class WebContentsData;
-
   using TabDiscardDoneCB = base::ScopedClosureRunner;
 
-  explicit TabManager(TabLoadTracker* tab_load_tracker);
+  TabManager();
 
   TabManager(const TabManager&) = delete;
   TabManager& operator=(const TabManager&) = delete;
@@ -108,28 +100,11 @@
   void AddObserver(TabLifecycleObserver* observer);
   void RemoveObserver(TabLifecycleObserver* observer);
 
-  // Return whether tabs are being loaded during session restore.
-  bool IsSessionRestoreLoadingTabs() const {
-    return is_session_restore_loading_tabs_;
-  }
-
   // Returns the number of tabs open in all browser instances.
   int GetTabCount() const;
 
-  // Returns the number of restored tabs during session restore. This is
-  // non-zero only during session restore.
-  int restored_tab_count() const { return restored_tab_count_; }
-
   UsageClock* usage_clock() { return &usage_clock_; }
 
-  // Returns true if the tab was created by session restore and has not finished
-  // the first navigation.
-  static bool IsTabInSessionRestore(content::WebContents* web_contents);
-
-  // Returns true if the tab was created by session restore and initially in
-  // foreground.
-  static bool IsTabRestoredInForeground(content::WebContents* web_contents);
-
  private:
   friend class TabManagerStatsCollectorTest;
 
@@ -181,25 +156,6 @@
   void UnregisterMemoryPressureListener();
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-  // TabStripModelObserver:
-  void OnTabStripModelChanged(
-      TabStripModel* tab_strip_model,
-      const TabStripModelChange& change,
-      const TabStripSelectionChange& selection) override;
-
-  // TabLoadTracker::Observer:
-  void OnStartTracking(content::WebContents* web_contents,
-                       LoadingState loading_state) override;
-  void OnLoadingStateChange(content::WebContents* web_contents,
-                            LoadingState old_loading_state,
-                            LoadingState new_loading_state) override;
-  void OnStopTracking(content::WebContents* web_contents,
-                      LoadingState loading_state) override;
-
-  // Returns the WebContentsData associated with |contents|. Also takes care of
-  // creating one if needed.
-  static WebContentsData* GetWebContentsData(content::WebContents* contents);
-
   // Discards the less important LifecycleUnit that supports discarding under
   // |reason|.
   content::WebContents* DiscardTabImpl(
@@ -229,22 +185,12 @@
   std::unique_ptr<TabManagerDelegate> delegate_;
 #endif
 
-  // Responsible for automatically registering this class as an observer of all
-  // TabStripModels. Automatically tracks browsers as they come and go.
-  BrowserTabStripTracker browser_tab_strip_tracker_;
-
-  bool is_session_restore_loading_tabs_;
-  size_t restored_tab_count_;
-
   class TabManagerSessionRestoreObserver;
   std::unique_ptr<TabManagerSessionRestoreObserver> session_restore_observer_;
 
   // A clock that advances when Chrome is in use.
   UsageClock usage_clock_;
 
-  // The tab load tracker observed by this instance.
-  const raw_ptr<TabLoadTracker> tab_load_tracker_;
-
   // Weak pointer factory used for posting delayed tasks.
   base::WeakPtrFactory<TabManager> weak_ptr_factory_{this};
 };
diff --git a/chrome/browser/resource_coordinator/tab_manager_browsertest.cc b/chrome/browser/resource_coordinator/tab_manager_browsertest.cc
index 9a5e8d8..cadfc2f5 100644
--- a/chrome/browser/resource_coordinator/tab_manager_browsertest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_browsertest.cc
@@ -26,7 +26,6 @@
 #include "chrome/browser/resource_coordinator/tab_lifecycle_unit_external.h"
 #include "chrome/browser/resource_coordinator/tab_manager.h"
 #include "chrome/browser/resource_coordinator/tab_manager_features.h"
-#include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h"
 #include "chrome/browser/resource_coordinator/time.h"
 #include "chrome/browser/resource_coordinator/utils.h"
 #include "chrome/browser/ui/browser.h"
diff --git a/chrome/browser/resource_coordinator/tab_manager_resource_coordinator_signal_observer.cc b/chrome/browser/resource_coordinator/tab_manager_resource_coordinator_signal_observer.cc
index fc9332e..4d9942a 100644
--- a/chrome/browser/resource_coordinator/tab_manager_resource_coordinator_signal_observer.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_resource_coordinator_signal_observer.cc
@@ -8,7 +8,6 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/resource_coordinator/resource_coordinator_parts.h"
 #include "chrome/browser/resource_coordinator/tab_load_tracker.h"
-#include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h"
 #include "chrome/browser/resource_coordinator/utils.h"
 #include "components/performance_manager/public/graph/graph_operations.h"
 #include "content/public/browser/browser_task_traits.h"
diff --git a/chrome/browser/resource_coordinator/tab_manager_unittest.cc b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
index 04a6fc13..8562bea4 100644
--- a/chrome/browser/resource_coordinator/tab_manager_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
@@ -30,7 +30,6 @@
 #include "chrome/browser/resource_coordinator/tab_lifecycle_unit_external.h"
 #include "chrome/browser/resource_coordinator/tab_manager_features.h"
 #include "chrome/browser/resource_coordinator/tab_manager_resource_coordinator_signal_observer.h"
-#include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h"
 #include "chrome/browser/resource_coordinator/time.h"
 #include "chrome/browser/resource_coordinator/utils.h"
 #include "chrome/browser/sessions/tab_loader.h"
@@ -182,18 +181,6 @@
   tab_strip2->CloseAllTabs();
 }
 
-TEST_F(TabManagerTest, IsTabRestoredInForeground) {
-  std::unique_ptr<WebContents> contents = CreateWebContents();
-  contents->WasShown();
-  tab_manager_->OnWillRestoreTab(contents.get());
-  EXPECT_TRUE(tab_manager_->IsTabRestoredInForeground(contents.get()));
-
-  contents = CreateWebContents();
-  contents->WasHidden();
-  tab_manager_->OnWillRestoreTab(contents.get());
-  EXPECT_FALSE(tab_manager_->IsTabRestoredInForeground(contents.get()));
-}
-
 TEST_F(TabManagerTest, GetSortedLifecycleUnits) {
   auto window = std::make_unique<TestBrowserWindow>();
   Browser::CreateParams params(profile(), true);
diff --git a/chrome/browser/resource_coordinator/tab_manager_web_contents_data.cc b/chrome/browser/resource_coordinator/tab_manager_web_contents_data.cc
deleted file mode 100644
index df71dd4..0000000
--- a/chrome/browser/resource_coordinator/tab_manager_web_contents_data.cc
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2015 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h"
-
-#include "base/metrics/histogram_macros.h"
-#include "base/time/time.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/resource_coordinator/tab_manager.h"
-#include "chrome/browser/resource_coordinator/time.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/navigation_handle.h"
-#include "content/public/browser/web_contents.h"
-
-using base::TimeTicks;
-using content::WebContents;
-
-namespace resource_coordinator {
-
-TabManager::WebContentsData::WebContentsData(content::WebContents* web_contents)
-    : WebContentsObserver(web_contents),
-      content::WebContentsUserData<TabManager::WebContentsData>(*web_contents) {
-}
-
-TabManager::WebContentsData::~WebContentsData() {}
-
-void TabManager::WebContentsData::DidFinishNavigation(
-    content::NavigationHandle* navigation_handle) {
-  SetIsInSessionRestore(false);
-}
-
-void TabManager::WebContentsData::WebContentsDestroyed() {
-  // If Chrome is shutting down, ignore this event.
-  if (g_browser_process->IsShuttingDown())
-    return;
-  SetIsInSessionRestore(false);
-}
-
-// static
-void TabManager::WebContentsData::CopyState(
-    content::WebContents* old_contents,
-    content::WebContents* new_contents) {
-  // Only copy if an existing state is found.
-  if (FromWebContents(old_contents)) {
-    CreateForWebContents(new_contents);
-    FromWebContents(new_contents)->tab_data_ =
-        FromWebContents(old_contents)->tab_data_;
-  }
-}
-
-TabManager::WebContentsData::Data::Data()
-    : tab_loading_state(TabLoadTracker::LoadingState::UNLOADED),
-      is_in_session_restore(false),
-      is_restored_in_foreground(false) {}
-
-bool TabManager::WebContentsData::Data::operator==(const Data& right) const {
-  return tab_loading_state == right.tab_loading_state &&
-         is_in_session_restore == right.is_in_session_restore &&
-         is_restored_in_foreground == right.is_restored_in_foreground;
-}
-
-bool TabManager::WebContentsData::Data::operator!=(const Data& right) const {
-  return !(*this == right);
-}
-
-WEB_CONTENTS_USER_DATA_KEY_IMPL(TabManager::WebContentsData);
-
-}  // namespace resource_coordinator
diff --git a/chrome/browser/resource_coordinator/tab_manager_web_contents_data.h b/chrome/browser/resource_coordinator/tab_manager_web_contents_data.h
deleted file mode 100644
index 9bde6b0..0000000
--- a/chrome/browser/resource_coordinator/tab_manager_web_contents_data.h
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2015 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_MANAGER_WEB_CONTENTS_DATA_H_
-#define CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_MANAGER_WEB_CONTENTS_DATA_H_
-
-#include "base/gtest_prod_util.h"
-#include "chrome/browser/resource_coordinator/tab_load_tracker.h"
-#include "chrome/browser/resource_coordinator/tab_manager.h"
-#include "content/public/browser/navigation_handle.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "content/public/browser/web_contents_user_data.h"
-
-namespace content {
-class WebContents;
-}
-
-namespace resource_coordinator {
-
-// Internal class used by TabManager to record the needed data for
-// WebContentses.
-// TODO(michaelpg): Merge implementation into
-// TabActivityWatcher::WebContentsData and expose necessary properties publicly.
-class TabManager::WebContentsData
-    : public content::WebContentsObserver,
-      public content::WebContentsUserData<TabManager::WebContentsData> {
- public:
-  using LoadingState = resource_coordinator::TabLoadTracker::LoadingState;
-
-  explicit WebContentsData(content::WebContents* web_contents);
-
-  WebContentsData(const WebContentsData&) = delete;
-  WebContentsData& operator=(const WebContentsData&) = delete;
-
-  ~WebContentsData() override;
-
-  // WebContentsObserver implementation:
-  void DidFinishNavigation(
-      content::NavigationHandle* navigation_handle) override;
-  void WebContentsDestroyed() override;
-
-  // Copies the discard state from |old_contents| to |new_contents|.
-  static void CopyState(content::WebContents* old_contents,
-                        content::WebContents* new_contents);
-
-  // Sets the tab loading state.
-  void SetTabLoadingState(LoadingState state) {
-    tab_data_.tab_loading_state = state;
-  }
-
-  // Returns the loading state of the tab.
-  LoadingState tab_loading_state() const { return tab_data_.tab_loading_state; }
-
-  void SetIsInSessionRestore(bool is_in_session_restore) {
-    tab_data_.is_in_session_restore = is_in_session_restore;
-  }
-
-  bool is_in_session_restore() const { return tab_data_.is_in_session_restore; }
-
-  void SetIsRestoredInForeground(bool is_restored_in_foreground) {
-    tab_data_.is_restored_in_foreground = is_restored_in_foreground;
-  }
-
-  bool is_restored_in_foreground() const {
-    return tab_data_.is_restored_in_foreground;
-  }
-
- private:
-  friend class content::WebContentsUserData<TabManager::WebContentsData>;
-  // Needed to access tab_data_.
-  FRIEND_TEST_ALL_PREFIXES(TabManagerWebContentsDataTest, CopyState);
-  FRIEND_TEST_ALL_PREFIXES(TabManagerWebContentsDataTest, TabLoadingState);
-
-  struct Data {
-    Data();
-    bool operator==(const Data& right) const;
-    bool operator!=(const Data& right) const;
-
-    // Current loading state of this tab.
-    LoadingState tab_loading_state;
-    // True if the tab was created by session restore. Remains true until the
-    // end of the first navigation or the tab is closed.
-    bool is_in_session_restore;
-    // True if the tab was created by session restore and initially foreground.
-    bool is_restored_in_foreground;
-  };
-
-  // Contains all the needed data for the tab.
-  Data tab_data_;
-  WEB_CONTENTS_USER_DATA_KEY_DECL();
-};
-
-}  // namespace resource_coordinator
-
-#endif  // CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_MANAGER_WEB_CONTENTS_DATA_H_
diff --git a/chrome/browser/resource_coordinator/tab_manager_web_contents_data_unittest.cc b/chrome/browser/resource_coordinator/tab_manager_web_contents_data_unittest.cc
deleted file mode 100644
index 91e6d67..0000000
--- a/chrome/browser/resource_coordinator/tab_manager_web_contents_data_unittest.cc
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright 2015 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h"
-
-#include "base/memory/raw_ptr.h"
-#include "base/test/metrics/histogram_tester.h"
-#include "base/test/simple_test_tick_clock.h"
-#include "chrome/browser/resource_coordinator/time.h"
-#include "chrome/test/base/chrome_render_view_host_test_harness.h"
-#include "chrome/test/base/testing_profile.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/test/web_contents_tester.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-using content::WebContents;
-using content::WebContentsTester;
-
-namespace resource_coordinator {
-namespace {
-
-constexpr TabLoadTracker::LoadingState UNLOADED =
-    TabLoadTracker::LoadingState::UNLOADED;
-constexpr TabLoadTracker::LoadingState LOADING =
-    TabLoadTracker::LoadingState::LOADING;
-constexpr TabLoadTracker::LoadingState LOADED =
-    TabLoadTracker::LoadingState::LOADED;
-
-class TabManagerWebContentsDataTest : public ChromeRenderViewHostTestHarness {
- public:
-  TabManagerWebContentsDataTest()
-      : scoped_set_tick_clock_for_testing_(&test_clock_) {
-    // Fast-forward time to prevent the first call to NowTicks() in a test from
-    // returning a null TimeTicks.
-    test_clock_.Advance(base::Milliseconds(1));
-  }
-
-  void SetUp() override {
-    ChromeRenderViewHostTestHarness::SetUp();
-    tab_data_ = CreateWebContentsAndTabData(&web_contents_);
-  }
-
-  void TearDown() override {
-    web_contents_.reset();
-    ChromeRenderViewHostTestHarness::TearDown();
-  }
-
-  TabManager::WebContentsData* tab_data() { return tab_data_; }
-
-  base::SimpleTestTickClock& test_clock() { return test_clock_; }
-
-  TabManager::WebContentsData* CreateWebContentsAndTabData(
-      std::unique_ptr<WebContents>* web_contents) {
-    *web_contents =
-        WebContentsTester::CreateTestWebContents(browser_context(), nullptr);
-    TabManager::WebContentsData::CreateForWebContents(web_contents->get());
-    return TabManager::WebContentsData::FromWebContents(web_contents->get());
-  }
-
- private:
-  std::unique_ptr<WebContents> web_contents_;
-  raw_ptr<TabManager::WebContentsData> tab_data_;
-  base::SimpleTestTickClock test_clock_;
-  ScopedSetTickClockForTesting scoped_set_tick_clock_for_testing_;
-};
-
-const char kDefaultUrl[] = "https://www.google.com";
-
-}  // namespace
-
-TEST_F(TabManagerWebContentsDataTest, TabLoadingState) {
-  EXPECT_EQ(UNLOADED, tab_data()->tab_loading_state());
-  tab_data()->SetTabLoadingState(LOADING);
-  EXPECT_EQ(LOADING, tab_data()->tab_loading_state());
-  tab_data()->SetTabLoadingState(LOADED);
-  EXPECT_EQ(LOADED, tab_data()->tab_loading_state());
-}
-
-TEST_F(TabManagerWebContentsDataTest, CopyState) {
-  tab_data()->SetTabLoadingState(LOADED);
-  tab_data()->SetIsInSessionRestore(true);
-  tab_data()->SetIsRestoredInForeground(true);
-
-  std::unique_ptr<WebContents> web_contents2;
-  auto* tab_data2 = CreateWebContentsAndTabData(&web_contents2);
-
-  EXPECT_NE(tab_data()->tab_data_, tab_data2->tab_data_);
-  TabManager::WebContentsData::CopyState(tab_data()->web_contents(),
-                                         tab_data2->web_contents());
-  EXPECT_EQ(tab_data()->tab_data_, tab_data2->tab_data_);
-}
-
-TEST_F(TabManagerWebContentsDataTest, IsInSessionRestoreWithTabLoading) {
-  EXPECT_FALSE(tab_data()->is_in_session_restore());
-  tab_data()->SetIsInSessionRestore(true);
-  EXPECT_TRUE(tab_data()->is_in_session_restore());
-
-  WebContents* contents = tab_data()->web_contents();
-  WebContentsTester::For(contents)->NavigateAndCommit(GURL(kDefaultUrl));
-  WebContentsTester::For(contents)->TestSetIsLoading(false);
-  EXPECT_FALSE(tab_data()->is_in_session_restore());
-}
-
-TEST_F(TabManagerWebContentsDataTest, IsInSessionRestoreWithTabClose) {
-  EXPECT_FALSE(tab_data()->is_in_session_restore());
-  tab_data()->SetIsInSessionRestore(true);
-  EXPECT_TRUE(tab_data()->is_in_session_restore());
-
-  tab_data()->WebContentsDestroyed();
-  EXPECT_FALSE(tab_data()->is_in_session_restore());
-}
-
-TEST_F(TabManagerWebContentsDataTest, IsTabRestoredInForeground) {
-  EXPECT_FALSE(tab_data()->is_restored_in_foreground());
-  tab_data()->SetIsRestoredInForeground(true);
-  EXPECT_TRUE(tab_data()->is_restored_in_foreground());
-}
-
-}  // namespace resource_coordinator
diff --git a/chrome/browser/resources/about_nacl/about_nacl.ts b/chrome/browser/resources/about_nacl/about_nacl.ts
index 66be29b..a701c65c 100644
--- a/chrome/browser/resources/about_nacl/about_nacl.ts
+++ b/chrome/browser/resources/about_nacl/about_nacl.ts
@@ -6,7 +6,7 @@
 
 import {assert} from 'chrome://resources/js/assert_ts.js';
 import {sendWithPromise} from 'chrome://resources/js/cr.js';
-import {$} from 'chrome://resources/js/util.js';
+import {getRequiredElement} from 'chrome://resources/js/util_ts.js';
 
 type NaclInfo = Array<{key: string, value: string}>;
 
@@ -18,8 +18,8 @@
  */
 function initialize() {
   sendWithPromise('requestNaClInfo').then((response: {naclInfo: NaclInfo}) => {
-    $('loading-message').hidden = true;
-    $('body-container').hidden = false;
+    getRequiredElement('loading-message').hidden = true;
+    getRequiredElement('body-container').hidden = false;
 
     const bind = document.body.querySelector<DomBindElement>('dom-bind');
     assert(bind);
diff --git a/chrome/browser/resources/accessibility/accessibility.ts b/chrome/browser/resources/accessibility/accessibility.ts
index 0557c93..6267e84 100644
--- a/chrome/browser/resources/accessibility/accessibility.ts
+++ b/chrome/browser/resources/accessibility/accessibility.ts
@@ -6,7 +6,7 @@
 
 import {assert} from 'chrome://resources/js/assert_ts.js';
 import {addWebUiListener} from 'chrome://resources/js/cr.js';
-import {$} from 'chrome://resources/js/util.js';
+import {$, getRequiredElement} from 'chrome://resources/js/util_ts.js';
 
 // Note: keep these values in sync with the values in
 // ui/accessibility/ax_mode.h
@@ -164,9 +164,10 @@
 }
 
 function requestTree(data: BrowserData|PageData|WidgetData, element: Element) {
-  const allow = ($('filter-allow') as HTMLInputElement).value;
-  const allowEmpty = ($('filter-allow-empty') as HTMLInputElement).value;
-  const deny = ($('filter-deny') as HTMLInputElement).value;
+  const allow = getRequiredElement<HTMLInputElement>('filter-allow').value;
+  const allowEmpty =
+      getRequiredElement<HTMLInputElement>('filter-allow-empty').value;
+  const deny = getRequiredElement<HTMLInputElement>('filter-deny').value;
   window.localStorage['chrome-accessibility-filter-allow'] = allow;
   window.localStorage['chrome-accessibility-filter-allow-empty'] = allowEmpty;
   window.localStorage['chrome-accessibility-filter-deny'] = deny;
@@ -177,7 +178,8 @@
   // function with the result.
   const requestType = element.id.split(':')[1] as RequestType;
   if (data.type === 'browser') {
-    const delay = ($('native-ui-delay') as HTMLInputElement).valueAsNumber;
+    const delay =
+        getRequiredElement<HTMLInputElement>('native-ui-delay').valueAsNumber;
     setTimeout(() => {
       browserProxy.requestNativeUITree(
           (data as BrowserData).sessionId, requestType, allow, allowEmpty,
@@ -236,7 +238,7 @@
   bindCheckbox('html', data.html);
   bindCheckbox('internal', data.internal);
 
-  $('pages').textContent = '';
+  getRequiredElement('pages').textContent = '';
 
   const pages = data.pages;
   for (let i = 0; i < pages.length; i++) {
@@ -256,15 +258,15 @@
       // window). If this is not the case, and Views Accessibility is enabled,
       // the only possibility is that Views Accessibility is not enabled for
       // the current platform. Display a message to the user to indicate this.
-      $('widgets-not-supported').style.display = 'block';
+      getRequiredElement('widgets-not-supported').style.display = 'block';
     } else {
       for (let i = 0; i < widgets.length; i++) {
         addToWidgetsList(widgets[i]!);
       }
     }
   } else {
-    $('widgets').style.display = 'none';
-    $('widgets-header').style.display = 'none';
+    getRequiredElement('widgets').style.display = 'none';
+    getRequiredElement('widgets-header').style.display = 'none';
   }
 
   // Cache filters so they're easily accessible on page refresh.
@@ -272,10 +274,11 @@
   const allowEmpty =
       window.localStorage['chrome-accessibility-filter-allow-empty'];
   const deny = window.localStorage['chrome-accessibility-filter-deny'];
-  ($('filter-allow') as HTMLInputElement).value = allow ? allow : '*';
-  ($('filter-allow-empty') as HTMLInputElement).value =
+  getRequiredElement<HTMLInputElement>('filter-allow').value =
+      allow ? allow : '*';
+  getRequiredElement<HTMLInputElement>('filter-allow-empty').value =
       allowEmpty ? allowEmpty : '';
-  ($('filter-deny') as HTMLInputElement).value = deny ? deny : '';
+  getRequiredElement<HTMLInputElement>('filter-deny').value = deny ? deny : '';
 
   addWebUiListener('copyTree', copyTree);
   addWebUiListener('showOrRefreshTree', showOrRefreshTree);
@@ -283,7 +286,7 @@
 }
 
 function bindCheckbox(name: string, value: EnabledStatus) {
-  const checkbox = $(name) as HTMLInputElement;
+  const checkbox = getRequiredElement<HTMLInputElement>(name);
   if (value === 'on') {
     checkbox.checked = true;
   }
@@ -305,7 +308,7 @@
   row.id = id;
   formatRow(row, data, null);
 
-  const pages = $('pages');
+  const pages = getRequiredElement('pages');
   pages.appendChild(row);
 }
 
@@ -316,7 +319,7 @@
   row.id = id;
   formatRow(row, data, null);
 
-  const browsers = $('browsers');
+  const browsers = getRequiredElement('browsers');
   browsers.appendChild(row);
 }
 
@@ -327,7 +330,7 @@
   row.id = id;
   formatRow(row, data, null);
 
-  const widgets = $('widgets');
+  const widgets = getRequiredElement('widgets');
   widgets.appendChild(row);
 }
 
@@ -501,7 +504,7 @@
   hide.textContent = 'Hide accessibility tree';
   hide.id = id + ':hideTree';
   hide.addEventListener('click', function() {
-    const show = $(id + ':showOrRefreshTree');
+    const show = getRequiredElement(id + ':showOrRefreshTree');
     show.textContent = 'Show accessibility tree';
     show.setAttribute('aria-expanded', 'false');
     show.focus();
@@ -565,7 +568,7 @@
 
   row.textContent = '';
   formatRow(row, data, 'showOrRefreshTree');
-  $(id + ':showOrRefreshTree').focus();
+  getRequiredElement(id + ':showOrRefreshTree').focus();
 }
 
 // WebUI listener handler for the 'startOrStopEvents' event.
@@ -578,7 +581,7 @@
 
   row.textContent = '';
   formatRow(row, data, null);
-  $(id + ':startOrStopEvents').focus();
+  getRequiredElement(id + ':startOrStopEvents').focus();
 }
 
 // WebUI listener handler for the 'copyTree' event.
@@ -593,6 +596,7 @@
   if ('tree' in data) {
     navigator.clipboard.writeText(data.tree!)
         .then(() => {
+          assert(copy);
           copy.textContent = 'Copied to clipboard!';
           setTimeout(() => {
             copy.textContent = 'Copy accessibility tree';
@@ -609,7 +613,7 @@
   // If the tree is currently shown, update it since it may have changed.
   if (tree && tree.style.display !== 'none') {
     showOrRefreshTree(data);
-    $(id + ':copyTree').focus();
+    getRequiredElement(id + ':copyTree').focus();
   }
 }
 
diff --git a/chrome/browser/resources/bookmarks/folder_node.ts b/chrome/browser/resources/bookmarks/folder_node.ts
index 721b52e..1bb58993 100644
--- a/chrome/browser/resources/bookmarks/folder_node.ts
+++ b/chrome/browser/resources/bookmarks/folder_node.ts
@@ -11,7 +11,7 @@
 import './strings.m.js';
 
 import {assert} from 'chrome://resources/js/assert_ts.js';
-import {isRTL} from 'chrome://resources/js/util.js';
+import {isRTL} from 'chrome://resources/js/util_ts.js';
 import {microTask, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {changeFolderOpen, selectFolder} from './actions.js';
diff --git a/chrome/browser/resources/bookmarks/list.ts b/chrome/browser/resources/bookmarks/list.ts
index 3ae3147..95de693 100644
--- a/chrome/browser/resources/bookmarks/list.ts
+++ b/chrome/browser/resources/bookmarks/list.ts
@@ -15,7 +15,7 @@
 import {ListPropertyUpdateMixin} from 'chrome://resources/cr_elements/list_property_update_mixin.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {PluralStringProxyImpl} from 'chrome://resources/js/plural_string_proxy.js';
-import {getDeepActiveElement} from 'chrome://resources/js/util.js';
+import {getDeepActiveElement} from 'chrome://resources/js/util_ts.js';
 import {IronListElement} from 'chrome://resources/polymer/v3_0/iron-list/iron-list.js';
 import {microTask, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output.js
index 034e0a8f..9e4f037 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output.js
@@ -625,17 +625,7 @@
     return true;
   }
 
-  /**
-   * Renders the given range using optional context previous range and event
-   * type.
-   * @param {!CursorRange} range
-   * @param {CursorRange} prevRange
-   * @param {!outputTypes.OutputEventType} type
-   * @param {!Array<Spannable>} buff Buffer to receive rendered output.
-   * @param {!OutputFormatLogger} formatLog
-   * @param {{suppressStartEndAncestry: (boolean|undefined)}} optionalArgs
-   * @private
-   */
+  /** @override */
   render_(range, prevRange, type, buff, formatLog, optionalArgs = {}) {
     if (prevRange && !prevRange.isValid()) {
       prevRange = null;
@@ -680,52 +670,6 @@
   }
 
   /** @override */
-  formatDescendants_(data, token) {
-    const buff = data.outputBuffer;
-    const node = data.node;
-    const formatLog = data.outputFormatLogger;
-
-    if (!node) {
-      return;
-    }
-
-    let leftmost = node;
-    let rightmost = node;
-    if (AutomationPredicate.leafOrStaticText(node)) {
-      // Find any deeper leaves, if any, by starting from one level
-      // down.
-      leftmost = node.firstChild;
-      rightmost = node.lastChild;
-      if (!leftmost || !rightmost) {
-        return;
-      }
-    }
-
-    // Construct a range to the leftmost and rightmost leaves. This
-    // range gets rendered below which results in output that is the
-    // same as if a user navigated through the entire subtree of |node|.
-    leftmost = AutomationUtil.findNodePre(
-        leftmost, Dir.FORWARD, AutomationPredicate.leafOrStaticText);
-    rightmost = AutomationUtil.findNodePre(
-        rightmost, Dir.BACKWARD, AutomationPredicate.leafOrStaticText);
-    if (!leftmost || !rightmost) {
-      return;
-    }
-
-    const subrange = new CursorRange(
-        new Cursor(leftmost, CURSOR_NODE_INDEX),
-        new Cursor(rightmost, CURSOR_NODE_INDEX));
-    let prev = null;
-    if (node) {
-      prev = CursorRange.fromNode(node);
-    }
-    formatLog.writeToken(token);
-    this.render_(
-        subrange, prev, outputTypes.OutputCustomEvent.NAVIGATE, buff, formatLog,
-        {suppressStartEndAncestry: true});
-  }
-
-  /** @override */
   formatJoinedDescendants_(data, token, options) {
     const buff = data.outputBuffer;
     const node = data.node;
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output_formatter.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output_formatter.js
index d5424d0..4bfe306 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output_formatter.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output_formatter.js
@@ -5,6 +5,11 @@
 /**
  * @fileoverview Class that formats the parsed output tree.
  */
+import {AutomationPredicate} from '../../../common/automation_predicate.js';
+import {AutomationUtil} from '../../../common/automation_util.js';
+import {constants} from '../../../common/constants.js';
+import {Cursor, CURSOR_NODE_INDEX} from '../../../common/cursors/cursor.js';
+import {CursorRange} from '../../../common/cursors/range.js';
 import {Msgs} from '../../common/msgs.js';
 
 import {OutputFormatParserObserver} from './output_format_parser.js';
@@ -12,6 +17,7 @@
 import {OutputInterface} from './output_interface.js';
 import * as outputTypes from './output_types.js';
 
+const Dir = constants.Dir;
 const NameFromType = chrome.automation.NameFromType;
 const RoleType = chrome.automation.RoleType;
 const StateType = chrome.automation.StateType;
@@ -70,7 +76,7 @@
     } else if (token === 'find') {
       this.formatFind_(this.params_, token, tree);
     } else if (token === 'descendants') {
-      this.output_.formatDescendants_(this.params_, token);
+      this.formatDescendants_(this.params_, token);
     } else if (token === 'joinedDescendants') {
       this.output_.formatJoinedDescendants_(this.params_, token, options);
     } else if (token === 'role') {
@@ -198,6 +204,56 @@
   /**
    * @param {!outputTypes.OutputFormattingData} data
    * @param {string} token
+   * @private
+   */
+  formatDescendants_(data, token) {
+    const buff = data.outputBuffer;
+    const node = data.node;
+    const formatLog = data.outputFormatLogger;
+
+    if (!node) {
+      return;
+    }
+
+    let leftmost = node;
+    let rightmost = node;
+    if (AutomationPredicate.leafOrStaticText(node)) {
+      // Find any deeper leaves, if any, by starting from one level
+      // down.
+      leftmost = node.firstChild;
+      rightmost = node.lastChild;
+      if (!leftmost || !rightmost) {
+        return;
+      }
+    }
+
+    // Construct a range to the leftmost and rightmost leaves. This
+    // range gets rendered below which results in output that is the
+    // same as if a user navigated through the entire subtree of |node|.
+    leftmost = AutomationUtil.findNodePre(
+        leftmost, Dir.FORWARD, AutomationPredicate.leafOrStaticText);
+    rightmost = AutomationUtil.findNodePre(
+        rightmost, Dir.BACKWARD, AutomationPredicate.leafOrStaticText);
+    if (!leftmost || !rightmost) {
+      return;
+    }
+
+    const subrange = new CursorRange(
+        new Cursor(leftmost, CURSOR_NODE_INDEX),
+        new Cursor(rightmost, CURSOR_NODE_INDEX));
+    let prev = null;
+    if (node) {
+      prev = CursorRange.fromNode(node);
+    }
+    formatLog.writeToken(token);
+    this.output_.render_(
+        subrange, prev, outputTypes.OutputCustomEvent.NAVIGATE, buff, formatLog,
+        {suppressStartEndAncestry: true});
+  }
+
+  /**
+   * @param {!outputTypes.OutputFormattingData} data
+   * @param {string} token
    * @param {!{annotation: Array<*>, isUnique: (boolean|undefined)}} options
    * @private
    */
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output_interface.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output_interface.js
index 9f44e58..c3db5ab 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output_interface.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output_interface.js
@@ -5,12 +5,15 @@
 /**
  * @fileoverview Interface for the central output class for ChromeVox.
  */
+import {CursorRange} from '../../../common/cursors/range.js';
 import {Spannable} from '../../common/spannable.js';
 
 import {OutputFormatTree} from './output_format_tree.js';
-import {OutputAction, OutputFormattingData} from './output_types.js';
+import {OutputFormatLogger} from './output_logger.js';
+import * as outputTypes from './output_types.js';
 
 const AutomationNode = chrome.automation.AutomationNode;
+const EventType = chrome.automation.EventType;
 
 /** @interface */
 export class OutputInterface {
@@ -34,40 +37,40 @@
    * Find the earcon for a given node (including ancestry).
    * @param {!AutomationNode} node
    * @param {!AutomationNode=} opt_prevNode
-   * @return {OutputAction}
+   * @return {outputTypes.OutputAction}
    */
   findEarcon_(node, opt_prevNode) {}
 
   /**
    * Format the node given the format specifier.
-   * @param {!OutputFormattingData} params All the required and
+   * @param {!outputTypes.OutputFormattingData} params All the required and
    *     optional parameters for formatting.
    */
   format_(params) {}
 
   /**
-   * @param {!OutputFormattingData} data
+   * @param {!outputTypes.OutputFormattingData} data
    * @param {string} token
    * @param {!{annotation: Array<*>, isUnique: (boolean|undefined)}} options
    */
   formatAsFieldAccessor_(data, token, options) {}
 
   /**
-   * @param {!OutputFormattingData} data
+   * @param {!outputTypes.OutputFormattingData} data
    * @param {string} token
    * @param {!{annotation: Array<*>, isUnique: (boolean|undefined)}} options
    */
   formatAsStateValue_(data, token, options) {}
 
   /**
-   * @param {!OutputFormattingData} data
+   * @param {!outputTypes.OutputFormattingData} data
    * @param {string} token
    * @param {!{annotation: Array<*>, isUnique: (boolean|undefined)}} options
    */
   formatCellIndexText_(data, token, options) {}
 
   /**
-   * @param {!OutputFormattingData} data
+   * @param {!outputTypes.OutputFormattingData} data
    * @param {string} token
    * @param {!OutputFormatTree} tree
    * @param {!{annotation: Array<*>, isUnique: (boolean|undefined)}} options
@@ -75,32 +78,26 @@
   formatCustomFunction_(data, token, tree, options) {}
 
   /**
-   * @param {!OutputFormattingData} data
-   * @param {string} token
-   */
-  formatDescendants_(data, token) {}
-
-  /**
-   * @param {!OutputFormattingData} data
+   * @param {!outputTypes.OutputFormattingData} data
    * @param {string} token
    * @param {!{annotation: Array<*>, isUnique: (boolean|undefined)}} options
    */
   formatInputType_(data, token, options) {}
 
   /**
-   * @param {!OutputFormattingData} data
+   * @param {!outputTypes.OutputFormattingData} data
    * @param {string} token
    * @param {!{annotation: Array<*>, isUnique: (boolean|undefined)}} options
    */
   formatJoinedDescendants_(data, token, options) {}
 
   /**
-   * @param {!OutputFormattingData} data
+   * @param {!outputTypes.OutputFormattingData} data
    */
   formatListNestedLevel_(data) {}
 
   /**
-   * @param {!OutputFormattingData} data
+   * @param {!outputTypes.OutputFormattingData} data
    * @param {string} token
    * @param {!OutputFormatTree} tree
    * @param {!{annotation: Array<*>, isUnique: (boolean|undefined)}} options
@@ -108,7 +105,7 @@
   formatMessage_(data, token, tree, options) {}
 
   /**
-   * @param {!OutputFormattingData} data
+   * @param {!outputTypes.OutputFormattingData} data
    * @param {string} token
    * @param {!OutputFormatTree} tree
    * @param {!{annotation: Array<*>, isUnique: (boolean|undefined)}} options
@@ -116,37 +113,49 @@
   formatNode_(data, token, tree, options) {}
 
   /**
-   * @param {!OutputFormattingData} data
+   * @param {!outputTypes.OutputFormattingData} data
    */
   formatPhoneticReading_(data) {}
 
   /**
-   * @param {!OutputFormattingData} data
+   * @param {!outputTypes.OutputFormattingData} data
    */
   formatPrecedingBullet_(data) {}
 
   /**
-   * @param {!OutputFormattingData} data
+   * @param {!outputTypes.OutputFormattingData} data
    * @param {string} token
    * @param {!{annotation: Array<*>, isUnique: (boolean|undefined)}} options
    */
   formatRole_(data, token, options) {}
 
   /**
-   * @param {!OutputFormattingData} data
+   * @param {!outputTypes.OutputFormattingData} data
    * @param {string} token
    * @param {!{annotation: Array<*>, isUnique: (boolean|undefined)}} options
    */
   formatTableCellIndex_(data, token, options) {}
 
   /**
-   * @param {!OutputFormattingData} data
+   * @param {!outputTypes.OutputFormattingData} data
    * @param {string} token
    * @param {!{annotation: Array<*>, isUnique: (boolean|undefined)}} options
    */
   formatTextContent_(data, token, options) {}
 
   /**
+   * Renders the given range using optional context previous range and event
+   * type.
+   * @param {!CursorRange} range
+   * @param {CursorRange} prevRange
+   * @param {EventType|outputTypes.OutputEventType} type
+   * @param {!Array<Spannable>} buff Buffer to receive rendered output.
+   * @param {!OutputFormatLogger} formatLog
+   * @param {{suppressStartEndAncestry: (boolean|undefined)}} optionalArgs
+   */
+  render_(range, prevRange, type, buff, formatLog, optionalArgs) {}
+
+  /**
    * @param {string} token
    * @return {boolean}
    */
diff --git a/chrome/browser/resources/chromeos/audio/audio.ts b/chrome/browser/resources/chromeos/audio/audio.ts
index e726ecb..d2e9cb7 100644
--- a/chrome/browser/resources/chromeos/audio/audio.ts
+++ b/chrome/browser/resources/chromeos/audio/audio.ts
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {$} from 'chrome://resources/js/util.js';
+import {$, getRequiredElement} from 'chrome://resources/js/util_ts.js';
 
 import {DevicePage} from './device_page.js';
 import {FeedbackPage} from './feedback_page.js';
@@ -32,10 +32,10 @@
     pageNavigator.showPage(devicePage.pageName);
   }
 
-  $('output-btn').addEventListener('click', function() {
+  getRequiredElement('output-btn').addEventListener('click', function() {
     pageNavigator.showPage(outputPage.pageName);
   });
-  $('input-btn').addEventListener('click', function() {
+  getRequiredElement('input-btn').addEventListener('click', function() {
     pageNavigator.showPage(inputPage.pageName);
   });
   pageNavigator.showPage(window.location.hash.substr(1));
diff --git a/chrome/browser/resources/chromeos/audio/audio_player.ts b/chrome/browser/resources/chromeos/audio/audio_player.ts
index 619224c8..e999bce0 100644
--- a/chrome/browser/resources/chromeos/audio/audio_player.ts
+++ b/chrome/browser/resources/chromeos/audio/audio_player.ts
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {$} from 'chrome://resources/js/util.js';
+import {getRequiredElement} from 'chrome://resources/js/util_ts.js';
 
 import {AudioSample, OutputPage} from './output_page.js';
 import {PageNavigator} from './page.js';
@@ -22,7 +22,8 @@
     this.sampleIdx = 0;
     this.audioContext = null;
     this.timerId = null;
-    const clone = ($('audioPlayer-template') as HTMLTemplateElement)
+    const clone =
+        getRequiredElement<HTMLTemplateElement>('audioPlayer-template')
                       .content.cloneNode(true);
     this.audioDiv = (clone as HTMLElement).querySelector('div')!;
     this.audioPlay =
diff --git a/chrome/browser/resources/chromeos/audio/device_page.ts b/chrome/browser/resources/chromeos/audio/device_page.ts
index a1efc1e..aebe6e2 100644
--- a/chrome/browser/resources/chromeos/audio/device_page.ts
+++ b/chrome/browser/resources/chromeos/audio/device_page.ts
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {$} from 'chrome://resources/js/util.js';
+import {getRequiredElement} from 'chrome://resources/js/util_ts.js';
 
 import {DeviceData, PageCallbackRouter, PageHandlerRemote} from './audio.mojom-webui.js';
 import {AudioBroker} from './audio_broker.js';
@@ -24,16 +24,16 @@
     this.router = AudioBroker.getInstance().callbackRouter;
     this.mojoHandler = AudioBroker.getInstance().handler;
     this.deviceTable = new DeviceTable();
-    $('deviceTable').appendChild(this.deviceTable);
+    getRequiredElement('deviceTable').appendChild(this.deviceTable);
     this.setUpAudioDevices();
     this.setUpButtons();
   }
 
   setUpButtons() {
-    $('banner-feedback').addEventListener('click', () => {
+    getRequiredElement('banner-feedback').addEventListener('click', () => {
       PageNavigator.getInstance().showPage('feedback');
     });
-    $('no-device-feedback').addEventListener('click', () => {
+    getRequiredElement('no-device-feedback').addEventListener('click', () => {
       PageNavigator.getInstance().showPage('feedback');
     });
   }
diff --git a/chrome/browser/resources/chromeos/audio/device_table.ts b/chrome/browser/resources/chromeos/audio/device_table.ts
index b8ef8ed..362a351 100644
--- a/chrome/browser/resources/chromeos/audio/device_table.ts
+++ b/chrome/browser/resources/chromeos/audio/device_table.ts
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {$} from 'chrome://resources/js/util.js';
+import {$, getRequiredElement} from 'chrome://resources/js/util_ts.js';
 import {DeviceData} from './audio.mojom-webui.js';
 import {DeviceMap} from './device_page.js';
 
@@ -12,7 +12,8 @@
   constructor() {
     super();
     this.devices = {};
-    const clone = ($('deviceTable-template') as HTMLTemplateElement)
+    const clone =
+        getRequiredElement<HTMLTemplateElement>('deviceTable-template')
                       .content.cloneNode(true);
     const thead = (clone as HTMLTableElement).querySelector('thead')!;
     this.appendChild(thead);
@@ -30,7 +31,7 @@
   setDeviceVolume(nodeId: number, volume: number) {
     if (nodeId in this.devices) {
       (this.devices[nodeId] as DeviceData).volumeGainPercent = volume;
-      const row = $(String(nodeId)) as HTMLTableRowElement;
+      const row = $<HTMLTableRowElement>(String(nodeId));
       if (row && row.cells[3]) {
         row.cells[3].textContent = String(volume) + '%';
       }
@@ -40,7 +41,7 @@
   setDeviceMuteState(nodeId: number, isMuted: boolean) {
     if (nodeId in this.devices) {
       (this.devices[nodeId] as DeviceData).isMuted = isMuted;
-      const row = $(String(nodeId)) as HTMLTableRowElement;
+      const row = $<HTMLTableRowElement>(String(nodeId));
       if (row && row.cells[4]) {
         row.cells[4].textContent = String(isMuted);
       }
@@ -88,7 +89,7 @@
     if (hasMuted) {
       this.updateWarningBanner('muted');
     } else {
-      $('warning-banner').hidden = true;
+      getRequiredElement('warning-banner').hidden = true;
     }
   }
 
@@ -103,19 +104,19 @@
     if (allInactive) {
       this.updateWarningBanner('inactive');
     } else {
-      $('warning-banner').hidden = true;
+      getRequiredElement('warning-banner').hidden = true;
     }
   }
 
   updateWarningBanner(reason: string) {
-    $('warning-banner').hidden = false;
+    getRequiredElement('warning-banner').hidden = false;
     if (reason === 'inactive') {
-      $('warning-msg').innerHTML =
+      getRequiredElement('warning-msg').innerHTML =
           'Warning: There is no detected active audio device. ' +
           'Have a device connected but cannot see it on the table or marked as active?';
     }
     if (reason === 'muted') {
-      $('warning-msg').innerHTML =
+      getRequiredElement('warning-msg').innerHTML =
           'Warning: One or more of your active devices is muted. ' +
           'Please try unmuting it by toggling the audio setting. ' +
           'Have unmuted the device but still see it marked as muted?';
diff --git a/chrome/browser/resources/chromeos/audio/feedback_page.ts b/chrome/browser/resources/chromeos/audio/feedback_page.ts
index 1aee92c8..3ebce18c 100644
--- a/chrome/browser/resources/chromeos/audio/feedback_page.ts
+++ b/chrome/browser/resources/chromeos/audio/feedback_page.ts
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {$} from 'chrome://resources/js/util.js';
+import {getRequiredElement} from 'chrome://resources/js/util_ts.js';
 
 import {AudioBroker} from './audio_broker.js';
 import {InputPage} from './input_page.js';
@@ -31,10 +31,10 @@
   }
 
   registerButtons() {
-    $('copy-btn').addEventListener('click', () => {
+    getRequiredElement('copy-btn').addEventListener('click', () => {
       navigator.clipboard.writeText(this.audioInfoString);
     });
-    $('submit-btn').addEventListener('click', () => {
+    getRequiredElement('submit-btn').addEventListener('click', () => {
       AudioBroker.getInstance().handler.openFeedbackDialog();
     });
   }
@@ -43,13 +43,15 @@
     if (this.inputFeedbackMap.has('audioUrl')) {
       const url = this.inputFeedbackMap.get('audioUrl');
       if (url) {
-        const downloadBtn = $('download-btn') as HTMLAnchorElement;
-        const inputAudio = $('test-input-audio') as HTMLAudioElement;
+        const downloadBtn =
+            getRequiredElement<HTMLAnchorElement>('download-btn');
+        const inputAudio =
+            getRequiredElement<HTMLAudioElement>('test-input-audio');
         inputAudio.src = url;
         downloadBtn.href = url;
         downloadBtn.download =
             'test_input_' + new Date().toISOString() + '.wav';
-        $('input-replay').hidden = false;
+        getRequiredElement('input-replay').hidden = false;
       }
     }
   }
@@ -70,7 +72,8 @@
     3. Any specific behavior you notice during the testing process?: \n
     4. audio info: `;
     this.audioInfoString = guidedQuestions + infoString;
-    ($('audio-info') as HTMLTextAreaElement).value = this.audioInfoString;
+    getRequiredElement<HTMLTextAreaElement>('audio-info').value =
+        this.audioInfoString;
   }
 
   mapToObject(map: Map<string, any>) {
diff --git a/chrome/browser/resources/chromeos/audio/input_page.ts b/chrome/browser/resources/chromeos/audio/input_page.ts
index ae71b57..8631adf 100644
--- a/chrome/browser/resources/chromeos/audio/input_page.ts
+++ b/chrome/browser/resources/chromeos/audio/input_page.ts
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {$} from 'chrome://resources/js/util.js';
+import {getRequiredElement} from 'chrome://resources/js/util_ts.js';
 
 import {AudioBroker} from './audio_broker.js';
 import {Page, PageNavigator} from './page.js';
@@ -51,7 +51,8 @@
   updateActiveInputDevice() {
     const handler = AudioBroker.getInstance().handler;
     handler.getActiveInputDeviceName().then(({deviceName}) => {
-      $('active-input').innerHTML = deviceName ?? 'No active input device';
+      getRequiredElement('active-input').innerHTML =
+          deviceName ?? 'No active input device';
     });
   }
 
@@ -62,11 +63,11 @@
     }> =
         [
           {
-            canvas: $('channel-l') as HTMLCanvasElement,
+            canvas: getRequiredElement<HTMLCanvasElement>('channel-l'),
             analyser: this.analyserLeft,
           },
           {
-            canvas: $('channel-r') as HTMLCanvasElement,
+            canvas: getRequiredElement<HTMLCanvasElement>('channel-r'),
             analyser: this.analyserRight,
           },
         ];
@@ -152,8 +153,8 @@
 
   record(source: MediaStream) {
     let chunks: Blob[] = [];
-    const recordButton = $('record-btn');
-    const clipSection = $('audio-file');
+    const recordButton = getRequiredElement('record-btn');
+    const clipSection = getRequiredElement('audio-file');
     this.mediaRecorder = new MediaRecorder(source);
 
     recordButton.onclick = () => {
@@ -188,8 +189,8 @@
 
   startRecord() {
     if (this.mediaRecorder) {
-      const recordButton = $('record-btn');
-      const clipSection = $('audio-file');
+      const recordButton = getRequiredElement('record-btn');
+      const clipSection = getRequiredElement('audio-file');
       this.recordClicked = true;
       this.mediaRecorder.start();
       this.startTimer();
@@ -203,13 +204,13 @@
 
   stopRecord() {
     if (this.mediaRecorder) {
-      const recordButton = $('record-btn');
+      const recordButton = getRequiredElement('record-btn');
       this.recordClicked = false;
       this.mediaRecorder.stop();
       this.stopTimer();
       recordButton.className = 'on-record';
       recordButton.textContent = 'Record';
-      $('input-qs').hidden = false;
+      getRequiredElement('input-qs').hidden = false;
     }
   }
 
@@ -217,7 +218,7 @@
     var startTime = Date.now();
     this.intervalId = window.setInterval(() => {
       var delta = Date.now() - startTime;
-      $('counter').innerHTML =
+      getRequiredElement('counter').innerHTML =
           String(Math.floor(delta / 1000)) + ':' + String(delta % 1000);
     }, 200);
   }
@@ -225,16 +226,16 @@
   stopTimer() {
     if (this.intervalId) {
       clearInterval(this.intervalId);
-      $('counter').innerHTML = '';
+      getRequiredElement('counter').innerHTML = '';
     }
   }
 
   setUpButtons() {
-    $('input-yes').addEventListener('click', () => {
+    getRequiredElement('input-yes').addEventListener('click', () => {
       this.testInputFeedback.set('Can Hear Clearly', 'true');
       PageNavigator.getInstance().showPage('feedback');
     });
-    $('input-no').addEventListener('click', () => {
+    getRequiredElement('input-no').addEventListener('click', () => {
       this.testInputFeedback.set('Can Hear Clearly', 'false');
       PageNavigator.getInstance().showPage('feedback');
     });
diff --git a/chrome/browser/resources/chromeos/audio/output_page.ts b/chrome/browser/resources/chromeos/audio/output_page.ts
index 5206697..7630db5 100644
--- a/chrome/browser/resources/chromeos/audio/output_page.ts
+++ b/chrome/browser/resources/chromeos/audio/output_page.ts
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {$} from 'chrome://resources/js/util.js';
+import {getRequiredElement} from 'chrome://resources/js/util_ts.js';
 
 import {AudioBroker} from './audio_broker.js';
 import {AudioPlayer} from './audio_player.js';
@@ -75,9 +75,10 @@
     const handler = AudioBroker.getInstance().handler;
     handler.getActiveOutputDeviceName().then(({deviceName}) => {
       if (deviceName) {
-        $('active-output').innerHTML = deviceName;
+        getRequiredElement('active-output').innerHTML = deviceName;
       } else {
-        $('active-output').innerHTML = 'No active output device';
+        getRequiredElement('active-output').innerHTML =
+            'No active output device';
       }
     });
   }
@@ -88,7 +89,7 @@
 
   createAudioPlayer() {
     const audioPlayer = new AudioPlayer(audiosSamples);
-    $('audio-player').appendChild(audioPlayer);
+    getRequiredElement('audio-player').appendChild(audioPlayer);
   }
 
   static getInstance() {
diff --git a/chrome/browser/resources/chromeos/audio/page.ts b/chrome/browser/resources/chromeos/audio/page.ts
index 51547c6..d2fe521 100644
--- a/chrome/browser/resources/chromeos/audio/page.ts
+++ b/chrome/browser/resources/chromeos/audio/page.ts
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {$} from 'chrome://resources/js/util.js';
+import {getRequiredElement} from 'chrome://resources/js/util_ts.js';
 
 export class Page {
   pageName: string;
@@ -14,12 +14,12 @@
 
   showPage() {
     this.visible = true;
-    $(this.pageName).hidden = false;
+    getRequiredElement(this.pageName).hidden = false;
   }
 
   hidePage() {
     this.visible = false;
-    $(this.pageName).hidden = true;
+    getRequiredElement(this.pageName).hidden = true;
   }
 }
 
diff --git a/chrome/browser/resources/components/components.ts b/chrome/browser/resources/components/components.ts
index 21104581..7904fd79 100644
--- a/chrome/browser/resources/components/components.ts
+++ b/chrome/browser/resources/components/components.ts
@@ -8,7 +8,7 @@
 import {addWebUiListener, sendWithPromise} from 'chrome://resources/js/cr.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {isChromeOS} from 'chrome://resources/js/platform.js';
-import {$} from 'chrome://resources/js/util.js';
+import {$, getRequiredElement} from 'chrome://resources/js/util_ts.js';
 
 declare global {
   class JsEvalContext {
@@ -51,8 +51,9 @@
   const output =
       document.body.querySelector<HTMLElement>(
                        '#component-template')!.cloneNode(true) as HTMLElement;
-  $('component-placeholder').innerHTML = trustedTypes.emptyHTML;
-  $('component-placeholder').appendChild(output);
+  getRequiredElement('component-placeholder').innerHTML =
+      trustedTypes.emptyHTML;
+  getRequiredElement('component-placeholder').appendChild(output);
   jstProcess(input, output);
   output.removeAttribute('hidden');
 
@@ -88,7 +89,7 @@
  * @param componentsData Detailed info about installed components.
  */
 function returnComponentsData(componentsData: ComponentsData) {
-  const bodyContainer = $('body-container');
+  const bodyContainer = getRequiredElement('body-container');
   const body = document.body;
 
   bodyContainer.style.visibility = 'hidden';
@@ -160,12 +161,12 @@
   assert(component);
 
   const status = event.event;
-  $('status-' + id).textContent = status;
+  getRequiredElement('status-' + id).textContent = status;
   component.status = status;
 
   if (event.version) {
     const version = event.version;
-    $('version-' + id).textContent = version;
+    getRequiredElement('version-' + id).textContent = version;
     component.version = version;
   }
 }
@@ -176,7 +177,7 @@
  *     update.
  */
 function handleCheckUpdate(node: HTMLElement) {
-  $('status-' + String(node.id)).textContent =
+  getRequiredElement('status-' + String(node.id)).textContent =
       loadTimeData.getString('checkingLabel');
 
   // Tell the C++ ComponentssDOMHandler to check for update.
diff --git a/chrome/browser/resources/conflicts/about_conflicts.ts b/chrome/browser/resources/conflicts/about_conflicts.ts
index b170a3d..e1d5248e 100644
--- a/chrome/browser/resources/conflicts/about_conflicts.ts
+++ b/chrome/browser/resources/conflicts/about_conflicts.ts
@@ -6,7 +6,7 @@
 
 import {assert} from 'chrome://resources/js/assert_ts.js';
 import {sendWithPromise} from 'chrome://resources/js/cr.js';
-import {$} from 'chrome://resources/js/util.js';
+import {getRequiredElement} from 'chrome://resources/js/util_ts.js';
 
 interface ModuleData {
   code_id: string;
@@ -68,8 +68,8 @@
   if (window.location.hash.length > 1) {
     filterModuleListData();
   }
-  $('loading-message').style.visibility = 'hidden';
-  $('body-container').style.visibility = 'visible';
+  getRequiredElement('loading-message').style.visibility = 'hidden';
+  getRequiredElement('body-container').style.visibility = 'visible';
 }
 
 // Get data and have it displayed upon loading.
diff --git a/chrome/browser/resources/downloads/item.ts b/chrome/browser/resources/downloads/item.ts
index f329cc3..620b05d0 100644
--- a/chrome/browser/resources/downloads/item.ts
+++ b/chrome/browser/resources/downloads/item.ts
@@ -22,7 +22,7 @@
 import {focusWithoutInk} from 'chrome://resources/js/focus_without_ink.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {sanitizeInnerHtml} from 'chrome://resources/js/parse_html_subset.js';
-import {HTMLEscape} from 'chrome://resources/js/util.js';
+import {htmlEscape} from 'chrome://resources/js/util_ts.js';
 import {beforeNextRender, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {BrowserProxy} from './browser_proxy.js';
@@ -240,7 +240,7 @@
 
     const url = `chrome://extensions/?id=${this.data.byExtId}`;
     const name = this.data.byExtName;
-    return loadTimeData.getStringF('controlledByUrl', url, HTMLEscape(name));
+    return loadTimeData.getStringF('controlledByUrl', url, htmlEscape(name));
   }
 
   private computeControlRemoveFromListAriaLabel_(): string {
diff --git a/chrome/browser/resources/downloads/toolbar.ts b/chrome/browser/resources/downloads/toolbar.ts
index 805bfcac57..abd8c8c4 100644
--- a/chrome/browser/resources/downloads/toolbar.ts
+++ b/chrome/browser/resources/downloads/toolbar.ts
@@ -8,7 +8,7 @@
 import 'chrome://resources/cr_elements/cr_hidden_style.css.js';
 import 'chrome://resources/cr_elements/icons.html.js';
 import 'chrome://resources/cr_elements/cr_shared_vars.css.js';
-import 'chrome://resources/js/util.js';
+import 'chrome://resources/js/util_ts.js';
 import 'chrome://resources/polymer/v3_0/paper-styles/color.js';
 import './strings.m.js';
 
diff --git a/chrome/browser/resources/extensions/toolbar.ts b/chrome/browser/resources/extensions/toolbar.ts
index 01d8a81..69bbef6 100644
--- a/chrome/browser/resources/extensions/toolbar.ts
+++ b/chrome/browser/resources/extensions/toolbar.ts
@@ -14,7 +14,7 @@
 import {getToastManager} from 'chrome://resources/cr_elements/cr_toast/cr_toast_manager.js';
 import {CrToggleElement} from 'chrome://resources/cr_elements/cr_toggle/cr_toggle.js';
 import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
-import {listenOnce} from 'chrome://resources/js/util.js';
+import {listenOnce} from 'chrome://resources/js/util_ts.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {getTemplate} from './toolbar.html.js';
diff --git a/chrome/browser/resources/feed_internals/feed_internals.ts b/chrome/browser/resources/feed_internals/feed_internals.ts
index e8fd434..2d4d330 100644
--- a/chrome/browser/resources/feed_internals/feed_internals.ts
+++ b/chrome/browser/resources/feed_internals/feed_internals.ts
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import {assert} from 'chrome://resources/js/assert_ts.js';
-import {$} from 'chrome://resources/js/util.js';
+import {getRequiredElement} from 'chrome://resources/js/util_ts.js';
 import {TimeDelta} from 'chrome://resources/mojo/mojo/public/mojom/base/time.mojom-webui.js';
 
 import {FeedOrder, LastFetchProperties, PageHandler, PageHandlerRemote} from './feed_internals.mojom-webui.js';
@@ -20,37 +20,48 @@
   assert(pageHandler);
   pageHandler.getGeneralProperties().then(response => {
     const properties = response.properties;
-    $('is-feed-enabled').textContent = String(properties.isFeedEnabled);
-    $('is-feed-visible').textContent = String(properties.isFeedVisible);
-    $('is-feed-allowed').textContent = String(properties.isFeedAllowed);
-    $('is-prefetching-enabled').textContent =
+    getRequiredElement('is-feed-enabled').textContent =
+        String(properties.isFeedEnabled);
+    getRequiredElement('is-feed-visible').textContent =
+        String(properties.isFeedVisible);
+    getRequiredElement('is-feed-allowed').textContent =
+        String(properties.isFeedAllowed);
+    getRequiredElement('is-prefetching-enabled').textContent =
         String(properties.isPrefetchingEnabled);
-    $('load-stream-status').textContent = properties.loadStreamStatus;
-    $('feed-fetch-url').textContent = properties.feedFetchUrl.url;
-    $('feed-actions-url').textContent = properties.feedActionsUrl.url;
-    ($('enable-webfeed-follow-intro-debug') as HTMLInputElement).checked =
-        properties.isWebFeedFollowIntroDebugEnabled;
-    ($('enable-webfeed-follow-intro-debug') as HTMLInputElement).disabled =
-        false;
-    ($('use-feed-query-requests') as HTMLInputElement).checked =
+    getRequiredElement('load-stream-status').textContent =
+        properties.loadStreamStatus;
+    getRequiredElement('feed-fetch-url').textContent =
+        properties.feedFetchUrl.url;
+    getRequiredElement('feed-actions-url').textContent =
+        properties.feedActionsUrl.url;
+    getRequiredElement<HTMLInputElement>('enable-webfeed-follow-intro-debug')
+        .checked = properties.isWebFeedFollowIntroDebugEnabled;
+    getRequiredElement<HTMLInputElement>('enable-webfeed-follow-intro-debug')
+        .disabled = false;
+    getRequiredElement<HTMLInputElement>('use-feed-query-requests').checked =
         properties.useFeedQueryRequests;
 
     switch (properties.followingFeedOrder) {
       case FeedOrder.kUnspecified:
-        ($('following-feed-order-unset') as HTMLInputElement).checked = true;
+        getRequiredElement<HTMLInputElement>('following-feed-order-unset')
+            .checked = true;
         break;
       case FeedOrder.kGrouped:
-        ($('following-feed-order-grouped') as HTMLInputElement).checked = true;
+        getRequiredElement<HTMLInputElement>('following-feed-order-grouped')
+            .checked = true;
         break;
       case FeedOrder.kReverseChron:
-        ($('following-feed-order-reverse-chron') as HTMLInputElement).checked =
-            true;
+        getRequiredElement<HTMLInputElement>(
+            'following-feed-order-reverse-chron')
+            .checked = true;
         break;
     }
-    ($('following-feed-order-grouped') as HTMLInputElement).disabled = false;
-    ($('following-feed-order-reverse-chron') as HTMLInputElement).disabled =
-        false;
-    ($('following-feed-order-unset') as HTMLInputElement).disabled = false;
+    getRequiredElement<HTMLInputElement>('following-feed-order-grouped')
+        .disabled = false;
+    getRequiredElement<HTMLInputElement>('following-feed-order-reverse-chron')
+        .disabled = false;
+    getRequiredElement<HTMLInputElement>('following-feed-order-unset')
+        .disabled = false;
   });
 }
 
@@ -61,15 +72,19 @@
   assert(pageHandler);
   pageHandler.getLastFetchProperties().then(response => {
     const properties: LastFetchProperties = response.properties;
-    $('last-fetch-status').textContent = String(properties.lastFetchStatus);
-    $('last-fetch-trigger').textContent = properties.lastFetchTrigger;
-    $('last-fetch-time').textContent = toDateString(properties.lastFetchTime);
-    $('refresh-suppress-time').textContent =
+    getRequiredElement('last-fetch-status').textContent =
+        String(properties.lastFetchStatus);
+    getRequiredElement('last-fetch-trigger').textContent =
+        properties.lastFetchTrigger;
+    getRequiredElement('last-fetch-time').textContent =
+        toDateString(properties.lastFetchTime);
+    getRequiredElement('refresh-suppress-time').textContent =
         toDateString(properties.refreshSuppressTime);
-    $('last-fetch-bless-nonce').textContent = properties.lastBlessNonce;
-    $('last-action-upload-status').textContent =
+    getRequiredElement('last-fetch-bless-nonce').textContent =
+        properties.lastBlessNonce;
+    getRequiredElement('last-action-upload-status').textContent =
         String(properties.lastActionUploadStatus);
-    $('last-action-upload-time').textContent =
+    getRequiredElement('last-action-upload-time').textContent =
         toDateString(properties.lastActionUploadTime);
   });
 }
@@ -87,92 +102,114 @@
  * Hook up buttons to event listeners.
  */
 function setupEventListeners() {
-  $('refresh-for-you').addEventListener('click', function() {
+  getRequiredElement('refresh-for-you').addEventListener('click', function() {
     assert(pageHandler);
     pageHandler.refreshForYouFeed();
   });
 
-  $('refresh-following').addEventListener('click', function() {
+  getRequiredElement('refresh-following').addEventListener('click', function() {
     assert(pageHandler);
     pageHandler.refreshFollowingFeed();
   });
 
-  $('refresh-webfeed-suggestions').addEventListener('click', () => {
-    assert(pageHandler);
-    pageHandler.refreshWebFeedSuggestions();
-  });
-
-  $('dump-feed-process-scope').addEventListener('click', function() {
-    assert(pageHandler);
-    pageHandler.getFeedProcessScopeDump().then(response => {
-      $('feed-process-scope-dump').textContent = response.dump;
-      ($('feed-process-scope-details') as HTMLDetailsElement).open = true;
-    });
-  });
-
-  $('load-feed-histograms').addEventListener('click', function() {
-    assert(pageHandler);
-    pageHandler.getFeedHistograms().then(response => {
-      $('feed-histograms-log').textContent = response.log;
-      ($('feed-histograms-details') as HTMLDetailsElement).open = true;
-    });
-  });
-
-  $('feed-host-override-apply').addEventListener('click', function() {
-    assert(pageHandler);
-    pageHandler.overrideFeedHost(
-        {url: ($('feed-host-override') as HTMLInputElement).value});
-  });
-
-  $('discover-api-override-apply').addEventListener('click', function() {
-    assert(pageHandler);
-    pageHandler.overrideDiscoverApiEndpoint(
-        {url: ($('discover-api-override') as HTMLInputElement).value});
-  });
-
-  $('feed-stream-data-override').addEventListener('click', function() {
-    assert(pageHandler);
-    const file = ($('feed-stream-data-file') as HTMLInputElement).files![0];
-    if (file && typeof pageHandler.overrideFeedStreamData === 'function') {
-      const reader = new FileReader();
-      reader.readAsArrayBuffer(file);
-      reader.onload = function(e) {
+  getRequiredElement('refresh-webfeed-suggestions')
+      .addEventListener('click', () => {
         assert(pageHandler);
-        const typedArray = new Uint8Array(e.target!.result as ArrayBuffer);
-        pageHandler.overrideFeedStreamData([...typedArray]);
-      };
-    }
-  });
+        pageHandler.refreshWebFeedSuggestions();
+      });
 
-  $('enable-webfeed-follow-intro-debug').addEventListener('click', function() {
-    assert(pageHandler);
-    pageHandler.setWebFeedFollowIntroDebugEnabled(
-        ($('enable-webfeed-follow-intro-debug') as HTMLInputElement).checked);
-    ($('enable-webfeed-follow-intro-debug') as HTMLInputElement).disabled =
-        true;
-  });
+  getRequiredElement('dump-feed-process-scope')
+      .addEventListener('click', function() {
+        assert(pageHandler);
+        pageHandler.getFeedProcessScopeDump().then(response => {
+          getRequiredElement('feed-process-scope-dump').textContent =
+              response.dump;
+          getRequiredElement<HTMLDetailsElement>('feed-process-scope-details')
+              .open = true;
+        });
+      });
 
-  $('use-feed-query-requests').addEventListener('click', function() {
-    assert(pageHandler);
-    pageHandler.setUseFeedQueryRequests(
-        ($('use-feed-query-requests') as HTMLInputElement).checked);
-  });
+  getRequiredElement('load-feed-histograms')
+      .addEventListener('click', function() {
+        assert(pageHandler);
+        pageHandler.getFeedHistograms().then(response => {
+          getRequiredElement('feed-histograms-log').textContent = response.log;
+          getRequiredElement<HTMLDetailsElement>('feed-histograms-details')
+              .open = true;
+        });
+      });
+
+  getRequiredElement('feed-host-override-apply')
+      .addEventListener('click', function() {
+        assert(pageHandler);
+        pageHandler.overrideFeedHost({
+          url: getRequiredElement<HTMLInputElement>('feed-host-override').value,
+        });
+      });
+
+  getRequiredElement('discover-api-override-apply')
+      .addEventListener('click', function() {
+        assert(pageHandler);
+        pageHandler.overrideDiscoverApiEndpoint({
+          url: getRequiredElement<HTMLInputElement>('discover-api-override')
+                   .value,
+        });
+      });
+
+  getRequiredElement('feed-stream-data-override')
+      .addEventListener('click', function() {
+        assert(pageHandler);
+        const file =
+            getRequiredElement<HTMLInputElement>('feed-stream-data-file')
+                .files![0];
+        if (file && typeof pageHandler.overrideFeedStreamData === 'function') {
+          const reader = new FileReader();
+          reader.readAsArrayBuffer(file);
+          reader.onload = function(e) {
+            assert(pageHandler);
+            const typedArray = new Uint8Array(e.target!.result as ArrayBuffer);
+            pageHandler.overrideFeedStreamData([...typedArray]);
+          };
+        }
+      });
+
+  getRequiredElement('enable-webfeed-follow-intro-debug')
+      .addEventListener('click', function() {
+        assert(pageHandler);
+        pageHandler.setWebFeedFollowIntroDebugEnabled(
+            getRequiredElement<HTMLInputElement>(
+                'enable-webfeed-follow-intro-debug')
+                .checked);
+        getRequiredElement<HTMLInputElement>(
+            'enable-webfeed-follow-intro-debug')
+            .disabled = true;
+      });
+
+  getRequiredElement('use-feed-query-requests')
+      .addEventListener('click', function() {
+        assert(pageHandler);
+        pageHandler.setUseFeedQueryRequests(
+            getRequiredElement<HTMLInputElement>('use-feed-query-requests')
+                .checked);
+      });
 
   const orderRadioClickListener = function(order: FeedOrder) {
     assert(pageHandler);
-    ($('following-feed-order-grouped') as HTMLInputElement).disabled = true;
-    ($('following-feed-order-reverse-chron') as HTMLInputElement).disabled =
-        true;
-    ($('following-feed-order-unset') as HTMLInputElement).disabled = true;
+    getRequiredElement<HTMLInputElement>('following-feed-order-grouped')
+        .disabled = true;
+    getRequiredElement<HTMLInputElement>('following-feed-order-reverse-chron')
+        .disabled = true;
+    getRequiredElement<HTMLInputElement>('following-feed-order-unset')
+        .disabled = true;
     pageHandler.setFollowingFeedOrder(order);
   };
-  $('following-feed-order-unset')
+  getRequiredElement('following-feed-order-unset')
       .addEventListener(
           'click', () => orderRadioClickListener(FeedOrder.kUnspecified));
-  $('following-feed-order-grouped')
+  getRequiredElement('following-feed-order-grouped')
       .addEventListener(
           'click', () => orderRadioClickListener(FeedOrder.kGrouped));
-  $('following-feed-order-reverse-chron')
+  getRequiredElement('following-feed-order-reverse-chron')
       .addEventListener(
           'click', () => orderRadioClickListener(FeedOrder.kReverseChron));
 }
diff --git a/chrome/browser/resources/feedback/js/feedback.ts b/chrome/browser/resources/feedback/js/feedback.ts
index 8d32a8d..4631971 100644
--- a/chrome/browser/resources/feedback/js/feedback.ts
+++ b/chrome/browser/resources/feedback/js/feedback.ts
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import {assert} from 'chrome://resources/js/assert_ts.js';
-import {$} from 'chrome://resources/js/util.js';
+import {$, getRequiredElement} from 'chrome://resources/js/util_ts.js';
 
 import {FEEDBACK_LANDING_PAGE, FEEDBACK_LANDING_PAGE_TECHSTOP, FEEDBACK_LEGAL_HELP_URL, FEEDBACK_PRIVACY_POLICY_URL, FEEDBACK_TERM_OF_SERVICE_URL, openUrlInAppWindow} from './feedback_util.js';
 import {domainQuestions, questionnaireBegin, questionnaireNotification} from './questionnaire.js';
@@ -214,10 +214,10 @@
   }
 
   if (file.size > MAX_ATTACH_FILE_SIZE) {
-    $('attach-error').hidden = false;
+    getRequiredElement('attach-error').hidden = false;
 
     // Clear our selected file.
-    ($('attach-file') as HTMLInputElement).value = '';
+    getRequiredElement<HTMLInputElement>('attach-file').value = '';
     attachedFileBlob = null;
     return;
   }
@@ -226,11 +226,11 @@
 }
 
 /**
- * Called when user opens the file dialog. Hide $('attach-error') before file
+ * Called when user opens the file dialog. Hide 'attach-error' before file
  * dialog is open to prevent a11y bug https://crbug.com/1020047
  */
 function onOpenFileDialog() {
-  $('attach-error').hidden = true;
+  getRequiredElement('attach-error').hidden = true;
 }
 
 /**
@@ -239,10 +239,10 @@
  * attach another file.
  */
 function clearAttachedFile() {
-  $('custom-file-container').hidden = true;
+  getRequiredElement('custom-file-container').hidden = true;
   attachedFileBlob = null;
   feedbackInfo.attachedFile = undefined;
-  $('attach-file').hidden = false;
+  getRequiredElement('attach-file').hidden = false;
 }
 
 /**
@@ -288,12 +288,13 @@
       cantConnectRegEx.test(value) || tetherRegEx.test(value) ||
       smartLockRegEx.test(value) || nearbyShareRegEx.test(value) ||
       fastPairRegEx.test(value) || btDeviceRegEx.test(value);
-  $('bluetooth-checkbox-container').hidden = !isRelatedToBluetooth;
+  getRequiredElement('bluetooth-checkbox-container').hidden =
+      !isRelatedToBluetooth;
 }
 
 /**
  * Checks if any keywords have associated questionnaire in a domain. If so,
- * we append the questionnaire in $('description-text').
+ * we append the questionnaire in getRequiredElement('description-text').
  * @param inputEvent The input event for the description textarea.
  */
 function checkForShowQuestionnaire(inputEvent: Event) {
@@ -323,11 +324,12 @@
     return;
   }
 
-  const textarea = $('description-text') as HTMLTextAreaElement;
+  const textarea = getRequiredElement<HTMLTextAreaElement>('description-text');
   const savedCursor = textarea.selectionStart;
   if (Object.keys(appendedQuestions).length === 0) {
     textarea.value += '\n\n' + questionnaireBegin + '\n';
-    $('questionnaire-notification').textContent = questionnaireNotification;
+    getRequiredElement('questionnaire-notification').textContent =
+        questionnaireNotification;
   }
 
   for (const question of toAppend) {
@@ -353,13 +355,13 @@
 function updateDescription(wasValid: boolean) {
   // Set visibility of the alert text for users who don't use a screen
   // reader.
-  $('description-empty-error').hidden = wasValid;
+  getRequiredElement('description-empty-error').hidden = wasValid;
 
   // Change the textarea's aria-labelled by to ensure the screen reader does
   // (or doesn't) read the error, as appropriate.
   // If it does read the error, it should do so _before_ it reads the normal
   // description.
-  const description = $('description-text');
+  const description = getRequiredElement('description-text');
   description.setAttribute(
       'aria-labelledby',
       (wasValid ? '' : 'description-empty-error ') + 'free-form-text');
@@ -382,7 +384,7 @@
  * @return Whether the report was sent.
  */
 function sendReport(): boolean {
-  const textarea = $('description-text') as HTMLTextAreaElement;
+  const textarea = getRequiredElement<HTMLTextAreaElement>('description-text');
   if (textarea.value.length === 0) {
     updateDescription(false);
     return false;
@@ -393,16 +395,16 @@
   updateDescription(true);
 
   // Prevent double clicking from sending additional reports.
-  ($('send-report-button') as HTMLButtonElement).disabled = true;
+  getRequiredElement<HTMLButtonElement>('send-report-button').disabled = true;
   if (!feedbackInfo.attachedFile && attachedFileBlob) {
     feedbackInfo.attachedFile = {
-      name: ($('attach-file') as HTMLInputElement).value,
+      name: getRequiredElement<HTMLInputElement>('attach-file').value,
       data: attachedFileBlob,
     };
   }
 
   const consentCheckboxValue: boolean =
-      ($('consent-checkbox') as HTMLInputElement).checked;
+      getRequiredElement<HTMLInputElement>('consent-checkbox').checked;
   feedbackInfo.systemInformation = [
     {
       key: 'feedbackUserCtlConsent',
@@ -411,12 +413,14 @@
   ];
 
   feedbackInfo.description = textarea.value;
-  feedbackInfo.pageUrl = ($('page-url-text') as HTMLInputElement).value;
-  feedbackInfo.email = ($('user-email-drop-down') as HTMLSelectElement).value;
+  feedbackInfo.pageUrl =
+      getRequiredElement<HTMLInputElement>('page-url-text').value;
+  feedbackInfo.email =
+      getRequiredElement<HTMLSelectElement>('user-email-drop-down').value;
 
   let useSystemInfo = false;
   let useHistograms = false;
-  const checkbox = $('sys-info-checkbox') as HTMLInputElement | null;
+  const checkbox = $<HTMLInputElement>('sys-info-checkbox');
   if (checkbox != null && checkbox.checked) {
     // Send histograms along with system info.
     useHistograms = true;
@@ -424,24 +428,21 @@
   }
 
   // <if expr="chromeos_ash">
-  const assistantCheckbox =
-      $('assistant-info-checkbox') as HTMLInputElement | null;
+  const assistantCheckbox = $<HTMLInputElement>('assistant-info-checkbox');
   if (assistantCheckbox != null && assistantCheckbox.checked &&
-      !$('assistant-checkbox-container').hidden) {
+      !getRequiredElement('assistant-checkbox-container').hidden) {
     // User consent to link Assistant debug info on Assistant server.
     feedbackInfo.assistantDebugInfoAllowed = true;
   }
 
-  const bluetoothCheckbox =
-      $('bluetooth-logs-checkbox') as HTMLInputElement | null;
+  const bluetoothCheckbox = $<HTMLInputElement>('bluetooth-logs-checkbox');
   if (bluetoothCheckbox != null && bluetoothCheckbox.checked &&
-      !$('bluetooth-checkbox-container').hidden) {
+      !getRequiredElement('bluetooth-checkbox-container').hidden) {
     feedbackInfo.sendBluetoothLogs = true;
     feedbackInfo.categoryTag = 'BluetoothReportWithLogs';
   }
 
-  const performanceCheckbox =
-      $('performance-info-checkbox') as HTMLInputElement | null;
+  const performanceCheckbox = $<HTMLInputElement>('performance-info-checkbox');
   if (performanceCheckbox == null || !performanceCheckbox.checked) {
     feedbackInfo.traceId = undefined;
   }
@@ -449,7 +450,7 @@
 
   feedbackInfo.sendHistograms = useHistograms;
 
-  if (($('screenshot-checkbox') as HTMLInputElement).checked) {
+  if (getRequiredElement<HTMLInputElement>('screenshot-checkbox').checked) {
     // The user is okay with sending the screenshot and tab titles.
     feedbackInfo.sendTabTitles = true;
   } else {
@@ -485,10 +486,12 @@
  * Update the page when performance feedback state is changed.
  */
 function performanceFeedbackChanged() {
-  const screenshotCheckbox = $('screenshot-checkbox') as HTMLInputElement;
-  const fileInput = $('attach-file') as HTMLInputElement;
+  const screenshotCheckbox =
+      getRequiredElement<HTMLInputElement>('screenshot-checkbox');
+  const fileInput = getRequiredElement<HTMLInputElement>('attach-file');
 
-  if (($('performance-info-checkbox') as HTMLInputElement).checked) {
+  if (getRequiredElement<HTMLInputElement>(
+      'performance-info-checkbox').checked) {
     fileInput.disabled = true;
     fileInput.checked = false;
 
@@ -534,7 +537,7 @@
       assert(
           feedbackInfo.flow ===
           chrome.feedbackPrivate.FeedbackFlow.GOOGLE_INTERNAL);
-      $('description-text')
+      getRequiredElement('description-text')
           .addEventListener('input', checkForSendBluetoothLogs);
     }
 
@@ -542,7 +545,7 @@
       assert(
           feedbackInfo.flow ===
           chrome.feedbackPrivate.FeedbackFlow.GOOGLE_INTERNAL);
-      $('description-text')
+      getRequiredElement('description-text')
           .addEventListener('input', checkForShowQuestionnaire);
     }
 
@@ -550,16 +553,18 @@
         feedbackInfo.flow ===
             chrome.feedbackPrivate.FeedbackFlow.GOOGLE_INTERNAL &&
         feedbackInfo.fromAssistant) {
-      $('assistant-checkbox-container').hidden = false;
+      getRequiredElement('assistant-checkbox-container').hidden = false;
     }
 
-    $('description-text').textContent = feedbackInfo.description;
+    getRequiredElement('description-text').textContent =
+        feedbackInfo.description;
     if (feedbackInfo.descriptionPlaceholder) {
-      ($('description-text') as HTMLTextAreaElement).placeholder =
+      getRequiredElement<HTMLTextAreaElement>('description-text').placeholder =
           feedbackInfo.descriptionPlaceholder;
     }
     if (feedbackInfo.pageUrl) {
-      ($('page-url-text') as HTMLInputElement).value = feedbackInfo.pageUrl;
+      getRequiredElement<HTMLInputElement>('page-url-text').value =
+          feedbackInfo.pageUrl;
     }
 
     takeScreenshot(function(screenshotCanvas) {
@@ -573,14 +578,15 @@
 
       // Allow feedback to be sent even if the screenshot failed.
       if (!screenshotCanvas) {
-        const checkbox = $('screenshot-checkbox') as HTMLInputElement;
+        const checkbox =
+            getRequiredElement<HTMLInputElement>('screenshot-checkbox');
         checkbox.disabled = true;
         checkbox.checked = false;
         return;
       }
 
       screenshotCanvas.toBlob(function(blob) {
-        const image = $('screenshot-image') as HTMLImageElement;
+        const image = getRequiredElement<HTMLImageElement>('screenshot-image');
         image.src = URL.createObjectURL(blob!);
         // Only set the alt text when the src url is available, otherwise we'd
         // get a broken image picture instead. crbug.com/773985.
@@ -601,34 +607,37 @@
       optionElement.text = email;
       optionElement.selected = true;
       // Make sure the "Report anonymously" option comes last.
-      $('user-email-drop-down')
-          .insertBefore(optionElement, $('anonymous-user-option'));
+      getRequiredElement('user-email-drop-down')
+          .insertBefore(optionElement,
+                        getRequiredElement('anonymous-user-option'));
 
       // Now we can unhide the user email section:
-      $('user-email').hidden = false;
+      getRequiredElement('user-email').hidden = false;
     });
 
     // An extension called us with an attached file.
     if (feedbackInfo.attachedFile) {
-      $('attached-filename-text').textContent = feedbackInfo.attachedFile.name;
+      getRequiredElement('attached-filename-text').textContent =
+          feedbackInfo.attachedFile.name;
       attachedFileBlob = feedbackInfo.attachedFile.data!;
-      $('custom-file-container').hidden = false;
-      $('attach-file').hidden = true;
+      getRequiredElement('custom-file-container').hidden = false;
+      getRequiredElement('attach-file').hidden = true;
     }
 
     // No URL, file attachment for login screen feedback.
     if (feedbackInfo.flow === chrome.feedbackPrivate.FeedbackFlow.LOGIN) {
-      $('page-url').hidden = true;
-      $('attach-file-container').hidden = true;
-      $('attach-file-note').hidden = true;
+      getRequiredElement('page-url').hidden = true;
+      getRequiredElement('attach-file-container').hidden = true;
+      getRequiredElement('attach-file-note').hidden = true;
     }
 
     // <if expr="chromeos_ash">
     if (feedbackInfo.traceId && ($('performance-info-area'))) {
-      $('performance-info-area').hidden = false;
-      ($('performance-info-checkbox') as HTMLInputElement).checked = true;
+      getRequiredElement('performance-info-area').hidden = false;
+      getRequiredElement<HTMLInputElement>(
+          'performance-info-checkbox').checked = true;
       performanceFeedbackChanged();
-      $('performance-info-link').onclick = openSlowTraceWindow;
+      getRequiredElement('performance-info-link').onclick = openSlowTraceWindow;
     }
     // </if>
 
@@ -716,7 +725,7 @@
     }
 
     // Make sure our focus starts on the description field.
-    $('description-text').focus();
+    getRequiredElement('description-text').focus();
   }
 
   window.addEventListener('DOMContentLoaded', function() {
@@ -728,13 +737,15 @@
     Object.assign(window, {feedbackInfo, feedbackHelper});
 
     // Setup our event handlers.
-    $('attach-file').addEventListener('change', onFileSelected);
-    $('attach-file').addEventListener('click', onOpenFileDialog);
-    $('send-report-button').onclick = sendReport;
-    $('cancel-button').onclick = cancel;
-    $('remove-attached-file').onclick = clearAttachedFile;
+    getRequiredElement('attach-file').addEventListener(
+        'change', onFileSelected);
+    getRequiredElement('attach-file').addEventListener(
+        'click', onOpenFileDialog);
+    getRequiredElement('send-report-button').onclick = sendReport;
+    getRequiredElement('cancel-button').onclick = cancel;
+    getRequiredElement('remove-attached-file').onclick = clearAttachedFile;
     // <if expr="chromeos_ash">
-    $('performance-info-checkbox')
+    getRequiredElement('performance-info-checkbox')
         .addEventListener('change', performanceFeedbackChanged);
     // </if>
   });
diff --git a/chrome/browser/resources/feedback/js/sys_info.ts b/chrome/browser/resources/feedback/js/sys_info.ts
index 9da8a87..66ae3e5 100644
--- a/chrome/browser/resources/feedback/js/sys_info.ts
+++ b/chrome/browser/resources/feedback/js/sys_info.ts
@@ -5,7 +5,7 @@
 import '../strings.m.js';
 
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
-import {$} from 'chrome://resources/js/util.js';
+import {getRequiredElement} from 'chrome://resources/js/util_ts.js';
 
 /**
  * A queue of a sequence of closures that will incrementally build the sys info
@@ -38,26 +38,26 @@
   const hasCollapsed = multilineRowsCount - expandedRowsCount > 0;
 
   if (hasExpanded && hasCollapsed) {
-    $('expandAllBtn').ariaPressed = 'mixed';
-    $('collapseAllBtn').ariaPressed = 'mixed';
+    getRequiredElement('expandAllBtn').ariaPressed = 'mixed';
+    getRequiredElement('collapseAllBtn').ariaPressed = 'mixed';
   } else if (hasExpanded && !hasCollapsed) {
-    $('expandAllBtn').ariaPressed = 'true';
-    $('collapseAllBtn').ariaPressed = 'false';
+    getRequiredElement('expandAllBtn').ariaPressed = 'true';
+    getRequiredElement('collapseAllBtn').ariaPressed = 'false';
   } else if (!hasExpanded && hasCollapsed) {
-    $('expandAllBtn').ariaPressed = 'false';
-    $('collapseAllBtn').ariaPressed = 'true';
+    getRequiredElement('expandAllBtn').ariaPressed = 'false';
+    getRequiredElement('collapseAllBtn').ariaPressed = 'true';
   } else {
-    $('expandAllBtn').ariaPressed = 'false';
-    $('collapseAllBtn').ariaPressed = 'false';
+    getRequiredElement('expandAllBtn').ariaPressed = 'false';
+    getRequiredElement('collapseAllBtn').ariaPressed = 'false';
   }
 }
 
 function getValueDivForButton(button: HTMLElement) {
-  return $(button.id.substr(0, button.id.length - 4));
+  return getRequiredElement(button.id.substr(0, button.id.length - 4));
 }
 
 function getButtonForValueDiv(valueDiv: HTMLElement) {
-  return $(valueDiv.id + '-btn');
+  return getRequiredElement(valueDiv.id + '-btn');
 }
 
 function getSystemInformation():
@@ -203,7 +203,7 @@
   if (isMultiLine) {
     valueCell.className = 'number-collapsed';
     const loadingContainer =
-        $('spinner-container').cloneNode(true) as HTMLElement;
+        getRequiredElement('spinner-container').cloneNode(true) as HTMLElement;
     loadingContainer.setAttribute('id', '' + key + '-value-loading');
     loadingContainer.hidden = true;
     valueCell.appendChild(loadingContainer);
@@ -234,10 +234,10 @@
  * Finalize the page after the content has been loaded.
  */
 function finishPageLoading() {
-  $('collapseAllBtn').onclick = collapseAll;
-  $('expandAllBtn').onclick = expandAll;
+  getRequiredElement('collapseAllBtn').onclick = collapseAll;
+  getRequiredElement('expandAllBtn').onclick = expandAll;
 
-  $('spinner-container').hidden = true;
+  getRequiredElement('spinner-container').hidden = true;
   updateGlobalExpandButtonStates();
 }
 
@@ -264,7 +264,7 @@
  */
 function createTableRowWrapper(key: string, value: string): () => void {
   return function() {
-    $('detailsTable').appendChild(createTableRow(key, value));
+    getRequiredElement('detailsTable').appendChild(createTableRow(key, value));
   };
 }
 
diff --git a/chrome/browser/resources/history/app.ts b/chrome/browser/resources/history/app.ts
index 7b5c59e7..04ed94e 100644
--- a/chrome/browser/resources/history/app.ts
+++ b/chrome/browser/resources/history/app.ts
@@ -24,7 +24,7 @@
 import {EventTracker} from 'chrome://resources/js/event_tracker.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {getTrustedScriptURL} from 'chrome://resources/js/static_types.js';
-import {hasKeyModifiers} from 'chrome://resources/js/util.js';
+import {hasKeyModifiers} from 'chrome://resources/js/util_ts.js';
 import {IronA11yAnnouncer} from 'chrome://resources/polymer/v3_0/iron-a11y-announcer/iron-a11y-announcer.js';
 import {IronPagesElement} from 'chrome://resources/polymer/v3_0/iron-pages/iron-pages.js';
 import {IronScrollTargetBehavior} from 'chrome://resources/polymer/v3_0/iron-scroll-target-behavior/iron-scroll-target-behavior.js';
diff --git a/chrome/browser/resources/history/history_list.ts b/chrome/browser/resources/history/history_list.ts
index b716343b..af92bbb 100644
--- a/chrome/browser/resources/history/history_list.ts
+++ b/chrome/browser/resources/history/history_list.ts
@@ -16,7 +16,7 @@
 import {assert} from 'chrome://resources/js/assert_ts.js';
 import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
-import {getDeepActiveElement} from 'chrome://resources/js/util.js';
+import {getDeepActiveElement} from 'chrome://resources/js/util_ts.js';
 import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
 import {IronListElement} from 'chrome://resources/polymer/v3_0/iron-list/iron-list.js';
 import {IronScrollThresholdElement} from 'chrome://resources/polymer/v3_0/iron-scroll-threshold/iron-scroll-threshold.js';
diff --git a/chrome/browser/resources/history/searched_label.ts b/chrome/browser/resources/history/searched_label.ts
index 78a660d..53c59db 100644
--- a/chrome/browser/resources/history/searched_label.ts
+++ b/chrome/browser/resources/history/searched_label.ts
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {quoteString} from 'chrome://resources/js/util.js';
+import {quoteString} from 'chrome://resources/js/util_ts.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 export class HistorySearchedLabelElement extends PolymerElement {
diff --git a/chrome/browser/resources/inline_login/inline_login_app.ts b/chrome/browser/resources/inline_login/inline_login_app.ts
index 5a13b3b1..0fe0fc0a 100644
--- a/chrome/browser/resources/inline_login/inline_login_app.ts
+++ b/chrome/browser/resources/inline_login/inline_login_app.ts
@@ -20,7 +20,7 @@
 import {CrViewManagerElement} from 'chrome://resources/cr_elements/cr_view_manager/cr_view_manager.js';
 import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
 import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
-import {isRTL} from 'chrome://resources/js/util.js';
+import {isRTL} from 'chrome://resources/js/util_ts.js';
 import {PaperSpinnerLiteElement} from 'chrome://resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {assert} from 'chrome://resources/js/assert_ts.js';
diff --git a/chrome/browser/resources/media/webrtc_logs.ts b/chrome/browser/resources/media/webrtc_logs.ts
index d0caf3c5..1434ebad 100644
--- a/chrome/browser/resources/media/webrtc_logs.ts
+++ b/chrome/browser/resources/media/webrtc_logs.ts
@@ -7,7 +7,7 @@
 import {assert, assertNotReached} from 'chrome://resources/js/assert_ts.js';
 import {sendWithPromise} from 'chrome://resources/js/cr.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
-import {appendParam} from 'chrome://resources/js/util.js';
+import {appendParam} from 'chrome://resources/js/util_ts.js';
 
 
 interface EventLogEntry {
diff --git a/chrome/browser/resources/media_router/internals/media_router_internals.ts b/chrome/browser/resources/media_router/internals/media_router_internals.ts
index ec92a627..bc3f498 100644
--- a/chrome/browser/resources/media_router/internals/media_router_internals.ts
+++ b/chrome/browser/resources/media_router/internals/media_router_internals.ts
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import {sendWithPromise} from 'chrome://resources/js/cr.js';
-import {$} from 'chrome://resources/js/util.js';
+import {getRequiredElement} from 'chrome://resources/js/util_ts.js';
 
 function formatJson(jsonObj: object) {
   return JSON.stringify(jsonObj, null, /* spacing level = */ 2);
@@ -12,13 +12,13 @@
 // Handles user events for the Media Router Internals UI.
 document.addEventListener('DOMContentLoaded', function() {
   sendWithPromise('getState').then((status: object) => {
-    $('sink-status-div').textContent = formatJson(status);
+    getRequiredElement('sink-status-div').textContent = formatJson(status);
   });
   sendWithPromise('getProviderState', 'CAST').then((status: object) => {
-    $('cast-status-div').textContent = formatJson(status);
+    getRequiredElement('cast-status-div').textContent = formatJson(status);
   });
   sendWithPromise('getLogs').then((logs: object) => {
     // TODO(crbug.com/687380): Present the logs in a table format.
-    $('logs-div').textContent = formatJson(logs);
+    getRequiredElement('logs-div').textContent = formatJson(logs);
   });
 });
diff --git a/chrome/browser/resources/memory_internals/memory_internals.ts b/chrome/browser/resources/memory_internals/memory_internals.ts
index 517ea8f..0ec479c 100644
--- a/chrome/browser/resources/memory_internals/memory_internals.ts
+++ b/chrome/browser/resources/memory_internals/memory_internals.ts
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import {addWebUiListener, sendWithPromise} from 'chrome://resources/js/cr.js';
-import {$} from 'chrome://resources/js/util.js';
+import {getRequiredElement} from 'chrome://resources/js/util_ts.js';
 
 type Process = [number, string, boolean];
 
@@ -44,9 +44,9 @@
 }
 
 function onProcessListReceived(data: ProcessList) {
-  $('message').innerText = data['message'];
+  getRequiredElement('message').innerText = data['message'];
 
-  const proclist = $('proclist');
+  const proclist = getRequiredElement('proclist');
   proclist.innerText = '';  // Clear existing contents.
 
   const processes = data['processes'];
@@ -87,11 +87,11 @@
 
 // Get data and have it displayed upon loading.
 document.addEventListener('DOMContentLoaded', () => {
-  $('refresh').onclick = requestProcessList;
-  $('save').onclick = saveDump;
+  getRequiredElement('refresh').onclick = requestProcessList;
+  getRequiredElement('save').onclick = saveDump;
 
   addWebUiListener('save-dump-progress', (progress: string) => {
-    $('save-dump-text').innerText = progress;
+    getRequiredElement('save-dump-text').innerText = progress;
   });
 
   requestProcessList();
diff --git a/chrome/browser/resources/new_tab_page/realbox/realbox.ts b/chrome/browser/resources/new_tab_page/realbox/realbox.ts
index 0b287dcf..efc078b9 100644
--- a/chrome/browser/resources/new_tab_page/realbox/realbox.ts
+++ b/chrome/browser/resources/new_tab_page/realbox/realbox.ts
@@ -6,7 +6,7 @@
 import './realbox_icon.js';
 
 import {assert} from 'chrome://resources/js/assert_ts.js';
-import {hasKeyModifiers} from 'chrome://resources/js/util.js';
+import {hasKeyModifiers} from 'chrome://resources/js/util_ts.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {loadTimeData} from '../i18n_setup.js';
diff --git a/chrome/browser/resources/password_manager/password_manager_app.ts b/chrome/browser/resources/password_manager/password_manager_app.ts
index 8775134..20c68c0 100644
--- a/chrome/browser/resources/password_manager/password_manager_app.ts
+++ b/chrome/browser/resources/password_manager/password_manager_app.ts
@@ -15,7 +15,7 @@
 
 import {CrContainerShadowMixin} from 'chrome://resources/cr_elements/cr_container_shadow_mixin.js';
 import {CrDrawerElement} from 'chrome://resources/cr_elements/cr_drawer/cr_drawer.js';
-import {listenOnce} from 'chrome://resources/js/util.js';
+import {listenOnce} from 'chrome://resources/js/util_ts.js';
 import {IronPagesElement} from 'chrome://resources/polymer/v3_0/iron-pages/iron-pages.js';
 import {DomIf, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
diff --git a/chrome/browser/resources/pdf/elements/viewer-page-indicator.ts b/chrome/browser/resources/pdf/elements/viewer-page-indicator.ts
index 39b0fe7..2c7ef45 100644
--- a/chrome/browser/resources/pdf/elements/viewer-page-indicator.ts
+++ b/chrome/browser/resources/pdf/elements/viewer-page-indicator.ts
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import {assert} from 'chrome://resources/js/assert_ts.js';
-import {isRTL} from 'chrome://resources/js/util.js';
+import {isRTL} from 'chrome://resources/js/util_ts.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {Viewport} from '../viewport.js';
diff --git a/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar.ts b/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar.ts
index 1fa4ea70..334f856 100644
--- a/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar.ts
+++ b/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar.ts
@@ -7,7 +7,7 @@
 import './icons.html.js';
 import './viewer-zoom-button.js';
 
-import {isRTL} from 'chrome://resources/js/util.js';
+import {isRTL} from 'chrome://resources/js/util_ts.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {FittingType} from '../constants.js';
diff --git a/chrome/browser/resources/pdf/pdf_internal_plugin_wrapper.ts b/chrome/browser/resources/pdf/pdf_internal_plugin_wrapper.ts
index b5151f3a..6ce7228 100644
--- a/chrome/browser/resources/pdf/pdf_internal_plugin_wrapper.ts
+++ b/chrome/browser/resources/pdf/pdf_internal_plugin_wrapper.ts
@@ -271,7 +271,7 @@
   return hasModifier;
 }
 
-// TODO(crbug.com/1252096): Load from chrome://resources/js/util.js instead.
+// TODO(crbug.com/1252096): Load from chrome://resources/js/util_ts.js instead.
 function hasKeyModifiers(e: KeyboardEvent): boolean {
   return !!(e.altKey || e.ctrlKey || e.metaKey || e.shiftKey);
 }
diff --git a/chrome/browser/resources/pdf/pdf_viewer.ts b/chrome/browser/resources/pdf/pdf_viewer.ts
index ef38fb8..8d4b457 100644
--- a/chrome/browser/resources/pdf/pdf_viewer.ts
+++ b/chrome/browser/resources/pdf/pdf_viewer.ts
@@ -17,7 +17,7 @@
 
 import {assert, assertNotReached} from 'chrome://resources/js/assert_ts.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
-import {listenOnce} from 'chrome://resources/js/util.js';
+import {listenOnce} from 'chrome://resources/js/util_ts.js';
 
 import {Bookmark} from './bookmark_type.js';
 import {BrowserApi} from './browser_api.js';
diff --git a/chrome/browser/resources/pdf/pdf_viewer_pp.ts b/chrome/browser/resources/pdf/pdf_viewer_pp.ts
index 433fa060..df1a989 100644
--- a/chrome/browser/resources/pdf/pdf_viewer_pp.ts
+++ b/chrome/browser/resources/pdf/pdf_viewer_pp.ts
@@ -9,7 +9,7 @@
 import './pdf_viewer_shared_style.css.js';
 
 import {assertNotReached} from 'chrome://resources/js/assert_ts.js';
-import {isRTL} from 'chrome://resources/js/util.js';
+import {isRTL} from 'chrome://resources/js/util_ts.js';
 
 import {BrowserApi} from './browser_api.js';
 import {ExtendedKeyEvent, FittingType} from './constants.js';
diff --git a/chrome/browser/resources/pdf/pdf_viewer_utils.ts b/chrome/browser/resources/pdf/pdf_viewer_utils.ts
index 31a0570..3996832 100644
--- a/chrome/browser/resources/pdf/pdf_viewer_utils.ts
+++ b/chrome/browser/resources/pdf/pdf_viewer_utils.ts
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import {assert} from 'chrome://resources/js/assert_ts.js';
-import {getDeepActiveElement} from 'chrome://resources/js/util.js';
+import {getDeepActiveElement} from 'chrome://resources/js/util_ts.js';
 
 import {LayoutOptions, ViewportRect} from './viewport.js';
 
diff --git a/chrome/browser/resources/pdf/toolbar_manager.ts b/chrome/browser/resources/pdf/toolbar_manager.ts
index 6f0ec41..26976287 100644
--- a/chrome/browser/resources/pdf/toolbar_manager.ts
+++ b/chrome/browser/resources/pdf/toolbar_manager.ts
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {isRTL} from 'chrome://resources/js/util.js';
+import {isRTL} from 'chrome://resources/js/util_ts.js';
 import {ViewerZoomToolbarElement} from './elements/viewer-zoom-toolbar.js';
 
 /**
diff --git a/chrome/browser/resources/pdf/viewport.ts b/chrome/browser/resources/pdf/viewport.ts
index 9bdd94b..8dd2a420 100644
--- a/chrome/browser/resources/pdf/viewport.ts
+++ b/chrome/browser/resources/pdf/viewport.ts
@@ -5,7 +5,7 @@
 import {getInstance as getAnnouncerInstance} from 'chrome://resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.js';
 import {assert, assertNotReached} from 'chrome://resources/js/assert_ts.js';
 import {EventTracker} from 'chrome://resources/js/event_tracker.js';
-import {hasKeyModifiers, isRTL} from 'chrome://resources/js/util.js';
+import {hasKeyModifiers, isRTL} from 'chrome://resources/js/util_ts.js';
 
 import {ExtendedKeyEvent, FittingType, Point} from './constants.js';
 import {Gesture, GestureDetector, PinchEventDetail} from './gesture_detector.js';
diff --git a/chrome/browser/resources/print_preview/print_preview_utils.ts b/chrome/browser/resources/print_preview/print_preview_utils.ts
index 1b4c5f6..86e0f0b 100644
--- a/chrome/browser/resources/print_preview/print_preview_utils.ts
+++ b/chrome/browser/resources/print_preview/print_preview_utils.ts
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {isRTL} from 'chrome://resources/js/util.js';
+import {isRTL} from 'chrome://resources/js/util_ts.js';
 import {IronIconsetSvgElement} from 'chrome://resources/polymer/v3_0/iron-iconset-svg/iron-iconset-svg.js';
 
 import {inDarkMode} from './dark_mode_mixin.js';
diff --git a/chrome/browser/resources/print_preview/ui/app.ts b/chrome/browser/resources/print_preview/ui/app.ts
index 08a81015..c2959949 100644
--- a/chrome/browser/resources/print_preview/ui/app.ts
+++ b/chrome/browser/resources/print_preview/ui/app.ts
@@ -12,7 +12,7 @@
 import {isMac, isWindows} from 'chrome://resources/js/platform.js';
 import {FocusOutlineManager} from 'chrome://resources/js/focus_outline_manager.js';
 import {EventTracker} from 'chrome://resources/js/event_tracker.js';
-import {hasKeyModifiers} from 'chrome://resources/js/util.js';
+import {hasKeyModifiers} from 'chrome://resources/js/util_ts.js';
 import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
diff --git a/chrome/browser/resources/print_preview/ui/destination_select.ts b/chrome/browser/resources/print_preview/ui/destination_select.ts
index 606308d..1905924 100644
--- a/chrome/browser/resources/print_preview/ui/destination_select.ts
+++ b/chrome/browser/resources/print_preview/ui/destination_select.ts
@@ -11,7 +11,7 @@
 import 'chrome://resources/cr_elements/cr_hidden_style.css.js';
 import 'chrome://resources/cr_elements/cr_shared_vars.css.js';
 import 'chrome://resources/cr_elements/md_select.css.js';
-import 'chrome://resources/js/util.js';
+import 'chrome://resources/js/util_ts.js';
 import 'chrome://resources/polymer/v3_0/iron-iconset-svg/iron-iconset-svg.js';
 import './destination_select_style.css.js';
 import './icons.html.js';
diff --git a/chrome/browser/resources/print_preview/ui/destination_select_cros.ts b/chrome/browser/resources/print_preview/ui/destination_select_cros.ts
index 77ee0a9..b48050b 100644
--- a/chrome/browser/resources/print_preview/ui/destination_select_cros.ts
+++ b/chrome/browser/resources/print_preview/ui/destination_select_cros.ts
@@ -4,7 +4,7 @@
 
 import 'chrome://resources/cr_elements/cr_hidden_style.css.js';
 import 'chrome://resources/cr_elements/cr_shared_vars.css.js';
-import 'chrome://resources/js/util.js';
+import 'chrome://resources/js/util_ts.js';
 import 'chrome://resources/polymer/v3_0/iron-iconset-svg/iron-iconset-svg.js';
 import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
 import 'chrome://resources/polymer/v3_0/iron-media-query/iron-media-query.js';
diff --git a/chrome/browser/resources/print_preview/ui/preview_area.ts b/chrome/browser/resources/print_preview/ui/preview_area.ts
index 6f82833..7174a2b5 100644
--- a/chrome/browser/resources/print_preview/ui/preview_area.ts
+++ b/chrome/browser/resources/print_preview/ui/preview_area.ts
@@ -8,7 +8,7 @@
 import '../strings.m.js';
 
 import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
-import {hasKeyModifiers} from 'chrome://resources/js/util.js';
+import {hasKeyModifiers} from 'chrome://resources/js/util_ts.js';
 import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
diff --git a/chrome/browser/resources/reset_password/reset_password.ts b/chrome/browser/resources/reset_password/reset_password.ts
index 4e38b2e1..095da15 100644
--- a/chrome/browser/resources/reset_password/reset_password.ts
+++ b/chrome/browser/resources/reset_password/reset_password.ts
@@ -8,7 +8,7 @@
 import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
 import 'chrome://resources/polymer/v3_0/paper-styles/color.js';
 
-import {$} from 'chrome://resources/js/util.js';
+import {getRequiredElement} from 'chrome://resources/js/util_ts.js';
 
 import {ResetPasswordHandler, ResetPasswordHandlerRemote} from './reset_password.mojom-webui.js';
 
@@ -17,7 +17,7 @@
 document.addEventListener('DOMContentLoaded', function() {
   pageHandler = ResetPasswordHandler.getRemote();
 
-  const resetPasswordButton = $('reset-password-button');
+  const resetPasswordButton = getRequiredElement('reset-password-button');
   resetPasswordButton.addEventListener('click', function() {
     pageHandler.handlePasswordReset();
   });
diff --git a/chrome/browser/resources/sandbox_internals/sandbox_internals.ts b/chrome/browser/resources/sandbox_internals/sandbox_internals.ts
index 9cf81ae..7873ae3 100644
--- a/chrome/browser/resources/sandbox_internals/sandbox_internals.ts
+++ b/chrome/browser/resources/sandbox_internals/sandbox_internals.ts
@@ -8,7 +8,7 @@
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 // </if>
 
-import {$} from 'chrome://resources/js/util.js';
+import {getRequiredElement} from 'chrome://resources/js/util_ts.js';
 
 /**
  * CSS classes for different statuses.
@@ -42,7 +42,7 @@
     valueCol.classList.add(cssClass);
   }
 
-  $('sandbox-status').appendChild(row);
+  getRequiredElement('sandbox-status').appendChild(row);
   return row;
 }
 
@@ -52,7 +52,7 @@
 function setEvaluation(result: boolean) {
   const message = result ? 'You are adequately sandboxed.' :
                            'You are NOT adequately sandboxed.';
-  $('evaluation').innerText = message;
+  getRequiredElement('evaluation').innerText = message;
 }
 
 // <if expr="is_android">
diff --git a/chrome/browser/resources/sandbox_internals/sandbox_internals_win.ts b/chrome/browser/resources/sandbox_internals/sandbox_internals_win.ts
index 6108a90..be8ccca 100644
--- a/chrome/browser/resources/sandbox_internals/sandbox_internals_win.ts
+++ b/chrome/browser/resources/sandbox_internals/sandbox_internals_win.ts
@@ -4,7 +4,7 @@
 
 import {assert} from 'chrome://resources/js/assert_ts.js';
 import {sendWithPromise} from 'chrome://resources/js/cr.js';
-import {$} from 'chrome://resources/js/util.js';
+import {getRequiredElement} from 'chrome://resources/js/util_ts.js';
 
 interface SandboxFeature {
   name: string;
@@ -340,7 +340,7 @@
   for (const td of args) {
     row.appendChild(td);
   }
-  $('sandbox-status').appendChild(row);
+  getRequiredElement('sandbox-status').appendChild(row);
 }
 
 /**
@@ -534,7 +534,7 @@
   }
 
   // Raw Diagnostics.
-  $('raw-info').textContent =
+  getRequiredElement('raw-info').textContent =
       'features: ' + JSON.stringify(results.features, null, 2) + '\n' +
       'policies: ' + JSON.stringify(results.policies, null, 2);
 }
diff --git a/chrome/browser/resources/segmentation_internals/segmentation_internals.ts b/chrome/browser/resources/segmentation_internals/segmentation_internals.ts
index 08577c63..03f3462 100644
--- a/chrome/browser/resources/segmentation_internals/segmentation_internals.ts
+++ b/chrome/browser/resources/segmentation_internals/segmentation_internals.ts
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import {getTrustedHTML} from 'chrome://resources/js/static_types.js';
-import {$} from 'chrome://resources/js/util.js';
+import {getRequiredElement} from 'chrome://resources/js/util_ts.js';
 
 import {ClientInfo, SegmentInfo} from './segmentation_internals.mojom-webui.js';
 import {SegmentationInternalsBrowserProxy} from './segmentation_internals_browser_proxy.js';
@@ -91,13 +91,13 @@
 function initialize() {
   getProxy().getCallbackRouter().onServiceStatusChanged.addListener(
       (initialized: boolean, status: number) => {
-        $('initialized').textContent = String(initialized);
-        $('service-status').textContent = String(status);
+        getRequiredElement('initialized').textContent = String(initialized);
+        getRequiredElement('service-status').textContent = String(status);
       });
 
   getProxy().getCallbackRouter().onClientInfoAvailable.addListener(
       (clientInfos: ClientInfo[]) => {
-        const parent = $('client-container');
+        const parent = getRequiredElement('client-container');
         // Remove all current children.
         while (parent.firstChild) {
           parent.removeChild(parent.firstChild);
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_device_section.ts b/chrome/browser/resources/settings/autofill_page/passwords_device_section.ts
index 13ea3eef..7277095 100644
--- a/chrome/browser/resources/settings/autofill_page/passwords_device_section.ts
+++ b/chrome/browser/resources/settings/autofill_page/passwords_device_section.ts
@@ -24,7 +24,7 @@
 
 import {CrToastElement} from 'chrome://resources/cr_elements/cr_toast/cr_toast.js';
 import {PluralStringProxyImpl} from 'chrome://resources/js/plural_string_proxy.js';
-import {getDeepActiveElement} from 'chrome://resources/js/util.js';
+import {getDeepActiveElement} from 'chrome://resources/js/util_ts.js';
 import {WebUiListenerMixin, WebUiListenerMixinInterface} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
 import {IronListElement} from 'chrome://resources/polymer/v3_0/iron-list/iron-list.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_section.ts b/chrome/browser/resources/settings/autofill_page/passwords_section.ts
index c838d1b..d706d53 100644
--- a/chrome/browser/resources/settings/autofill_page/passwords_section.ts
+++ b/chrome/browser/resources/settings/autofill_page/passwords_section.ts
@@ -40,7 +40,7 @@
 import {WebUiListenerMixin, WebUiListenerMixinInterface} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
 import {assert, assertNotReached} from 'chrome://resources/js/assert_ts.js';
 import {focusWithoutInk} from 'chrome://resources/js/focus_without_ink.js';
-import {getDeepActiveElement} from 'chrome://resources/js/util.js';
+import {getDeepActiveElement} from 'chrome://resources/js/util_ts.js';
 import {DomRepeat, DomRepeatEvent, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {SettingsToggleButtonElement} from '../controls/settings_toggle_button.js';
diff --git a/chrome/browser/resources/settings/chromeos/os_printing_page/cups_edit_printer_dialog.ts b/chrome/browser/resources/settings/chromeos/os_printing_page/cups_edit_printer_dialog.ts
index ba4da2eb..dc3cd45 100644
--- a/chrome/browser/resources/settings/chromeos/os_printing_page/cups_edit_printer_dialog.ts
+++ b/chrome/browser/resources/settings/chromeos/os_printing_page/cups_edit_printer_dialog.ts
@@ -23,7 +23,7 @@
 import {OncMojo} from 'chrome://resources/ash/common/network/onc_mojo.js';
 import {I18nMixin, I18nMixinInterface} from 'chrome://resources/cr_elements/i18n_mixin.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
-import {HTMLEscape} from 'chrome://resources/js/util.js';
+import {htmlEscape} from 'chrome://resources/js/util_ts.js';
 import {CrosNetworkConfigRemote, FilterType, NetworkStateProperties, NO_LIMIT} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js';
 import {NetworkType} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js';
 import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
@@ -434,7 +434,7 @@
 
     const htmlText = '<!DOCTYPE html><html><body><h1>' +
         loadTimeData.getStringF('cupsPrintersPpdFor', ppdInfo.printerName) +
-        '</h1>' + eulaHtml + '<p><pre>' + HTMLEscape(ppdInfo.ppd) +
+        '</h1>' + eulaHtml + '<p><pre>' + htmlEscape(ppdInfo.ppd) +
         '</pre></p>';
 
     const win = window.open('');
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.ts b/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.ts
index 8ab15d404..c4cf2b85f 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.ts
+++ b/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.ts
@@ -26,7 +26,7 @@
 import {CrDrawerElement} from 'chrome://resources/cr_elements/cr_drawer/cr_drawer.js';
 import {FindShortcutMixin, FindShortcutMixinInterface} from 'chrome://resources/cr_elements/find_shortcut_mixin.js';
 import {assert} from 'chrome://resources/js/assert_ts.js';
-import {listenOnce} from 'chrome://resources/js/util.js';
+import {listenOnce} from 'chrome://resources/js/util_ts.js';
 import {Debouncer, DomIf, microTask, mixinBehaviors, PolymerElement, timeOut} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {loadTimeData} from '../../i18n_setup.js';
diff --git a/chrome/browser/resources/settings/downloads_page/downloads_page.ts b/chrome/browser/resources/settings/downloads_page/downloads_page.ts
index 088f303..47b71eb 100644
--- a/chrome/browser/resources/settings/downloads_page/downloads_page.ts
+++ b/chrome/browser/resources/settings/downloads_page/downloads_page.ts
@@ -15,7 +15,7 @@
 import '../settings_shared.css.js';
 
 import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
-import {listenOnce} from 'chrome://resources/js/util.js';
+import {listenOnce} from 'chrome://resources/js/util_ts.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {PrefsMixin} from '../prefs/prefs_mixin.js';
diff --git a/chrome/browser/resources/settings/people_page/sync_controls.ts b/chrome/browser/resources/settings/people_page/sync_controls.ts
index ce20540f..844af33 100644
--- a/chrome/browser/resources/settings/people_page/sync_controls.ts
+++ b/chrome/browser/resources/settings/people_page/sync_controls.ts
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import '//resources/js/util.js';
+import '//resources/js/util_ts.js';
 import '//resources/cr_components/localized_link/localized_link.js';
 import '//resources/cr_elements/cr_radio_button/cr_radio_button.js';
 import '//resources/cr_elements/cr_radio_group/cr_radio_group.js';
diff --git a/chrome/browser/resources/settings/people_page/sync_page.ts b/chrome/browser/resources/settings/people_page/sync_page.ts
index 39b10aa..7ca164b 100644
--- a/chrome/browser/resources/settings/people_page/sync_page.ts
+++ b/chrome/browser/resources/settings/people_page/sync_page.ts
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import '//resources/js/util.js';
+import '//resources/js/util_ts.js';
 import '//resources/cr_elements/cr_button/cr_button.js';
 import '//resources/cr_elements/cr_dialog/cr_dialog.js';
 import '//resources/cr_elements/cr_input/cr_input.js';
diff --git a/chrome/browser/resources/settings/settings_page/settings_subpage.ts b/chrome/browser/resources/settings/settings_page/settings_subpage.ts
index f9cd7805..b9ca6a7 100644
--- a/chrome/browser/resources/settings/settings_page/settings_subpage.ts
+++ b/chrome/browser/resources/settings/settings_page/settings_subpage.ts
@@ -21,7 +21,7 @@
 import {assert} from '//resources/js/assert_ts.js';
 import {focusWithoutInk} from '//resources/js/focus_without_ink.js';
 import {I18nMixin, I18nMixinInterface} from '//resources/cr_elements/i18n_mixin.js';
-import {listenOnce} from '//resources/js/util.js';
+import {listenOnce} from '//resources/js/util_ts.js';
 import {IronResizableBehavior} from '//resources/polymer/v3_0/iron-resizable-behavior/iron-resizable-behavior.js';
 import {afterNextRender, mixinBehaviors, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {EventTracker} from 'chrome://resources/js/event_tracker.js';
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.ts b/chrome/browser/resources/settings/settings_ui/settings_ui.ts
index cd85da50..142149a 100644
--- a/chrome/browser/resources/settings/settings_ui/settings_ui.ts
+++ b/chrome/browser/resources/settings/settings_ui/settings_ui.ts
@@ -27,7 +27,7 @@
 import {CrDrawerElement} from 'chrome://resources/cr_elements/cr_drawer/cr_drawer.js';
 import {CrToolbarElement} from 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar.js';
 import {FindShortcutMixin, FindShortcutMixinInterface} from 'chrome://resources/cr_elements/find_shortcut_mixin.js';
-import {listenOnce} from 'chrome://resources/js/util.js';
+import {listenOnce} from 'chrome://resources/js/util_ts.js';
 import {DomIf, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {resetGlobalScrollTargetForTesting, setGlobalScrollTarget} from '../global_scroll_target_mixin.js';
diff --git a/chrome/browser/resources/side_panel/bookmarks/bookmarks_list.ts b/chrome/browser/resources/side_panel/bookmarks/bookmarks_list.ts
index 145a44f..00650f0 100644
--- a/chrome/browser/resources/side_panel/bookmarks/bookmarks_list.ts
+++ b/chrome/browser/resources/side_panel/bookmarks/bookmarks_list.ts
@@ -7,7 +7,7 @@
 import {getInstance as getAnnouncerInstance} from 'chrome://resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.js';
 import {FocusOutlineManager} from 'chrome://resources/js/focus_outline_manager.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
-import {listenOnce} from 'chrome://resources/js/util.js';
+import {listenOnce} from 'chrome://resources/js/util_ts.js';
 import {afterNextRender, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {BookmarkFolderElement, FOLDER_OPEN_CHANGED_EVENT, getBookmarkFromElement, isBookmarkFolderElement} from './bookmark_folder.js';
diff --git a/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.ts b/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.ts
index 9338c51..3aa7065b 100644
--- a/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.ts
+++ b/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.ts
@@ -16,7 +16,7 @@
 import {getInstance as getAnnouncerInstance} from 'chrome://resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {PluralStringProxyImpl} from 'chrome://resources/js/plural_string_proxy.js';
-import {listenOnce} from 'chrome://resources/js/util.js';
+import {listenOnce} from 'chrome://resources/js/util_ts.js';
 import {DomRepeatEvent, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {ActionSource} from './bookmarks.mojom-webui.js';
diff --git a/chrome/browser/resources/side_panel/reading_list/app.ts b/chrome/browser/resources/side_panel/reading_list/app.ts
index 95e580cd..7b50293 100644
--- a/chrome/browser/resources/side_panel/reading_list/app.ts
+++ b/chrome/browser/resources/side_panel/reading_list/app.ts
@@ -16,7 +16,7 @@
 import {HelpBubbleMixin, HelpBubbleMixinInterface} from 'chrome://resources/cr_components/help_bubble/help_bubble_mixin.js';
 import {assertNotReached} from 'chrome://resources/js/assert_ts.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
-import {listenOnce} from 'chrome://resources/js/util.js';
+import {listenOnce} from 'chrome://resources/js/util_ts.js';
 import {IronSelectorElement} from 'chrome://resources/polymer/v3_0/iron-selector/iron-selector.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
diff --git a/chrome/browser/resources/tab_search/app.ts b/chrome/browser/resources/tab_search/app.ts
index d2cf84c28..00883c2 100644
--- a/chrome/browser/resources/tab_search/app.ts
+++ b/chrome/browser/resources/tab_search/app.ts
@@ -19,7 +19,7 @@
 import {assert} from 'chrome://resources/js/assert_ts.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {MetricsReporter, MetricsReporterImpl} from 'chrome://resources/js/metrics_reporter/metrics_reporter.js';
-import {listenOnce} from 'chrome://resources/js/util.js';
+import {listenOnce} from 'chrome://resources/js/util_ts.js';
 import {Token} from 'chrome://resources/mojo/mojo/public/mojom/base/token.mojom-webui.js';
 import {IronA11yAnnouncer} from 'chrome://resources/polymer/v3_0/iron-a11y-announcer/iron-a11y-announcer.js';
 import {DomRepeatEvent, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
diff --git a/chrome/browser/resources/tab_search/fuzzy_search.ts b/chrome/browser/resources/tab_search/fuzzy_search.ts
index c3e90e1..cf6c1e7 100644
--- a/chrome/browser/resources/tab_search/fuzzy_search.ts
+++ b/chrome/browser/resources/tab_search/fuzzy_search.ts
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {quoteString} from 'chrome://resources/js/util.js';
+import {quoteString} from 'chrome://resources/js/util_ts.js';
 import {get as deepGet} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import Fuse from './fuse.js';
diff --git a/chrome/browser/resources/tab_search/infinite_list.ts b/chrome/browser/resources/tab_search/infinite_list.ts
index 899baa53..040c0c82 100644
--- a/chrome/browser/resources/tab_search/infinite_list.ts
+++ b/chrome/browser/resources/tab_search/infinite_list.ts
@@ -19,7 +19,7 @@
 import 'chrome://resources/polymer/v3_0/iron-selector/iron-selector.js';
 
 import {assert} from 'chrome://resources/js/assert_ts.js';
-import {getDeepActiveElement} from 'chrome://resources/js/util.js';
+import {getDeepActiveElement} from 'chrome://resources/js/util_ts.js';
 import {IronSelectorElement} from 'chrome://resources/polymer/v3_0/iron-selector/iron-selector.js';
 import {calculateSplices, PolymerElement, TemplateInstanceBase, templatize} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
diff --git a/chrome/browser/resources/tab_strip/tab.ts b/chrome/browser/resources/tab_strip/tab.ts
index ca6c0db..4a8b1088 100644
--- a/chrome/browser/resources/tab_strip/tab.ts
+++ b/chrome/browser/resources/tab_strip/tab.ts
@@ -9,7 +9,7 @@
 import {CustomElement} from 'chrome://resources/js/custom_element.js';
 import {getFavicon} from 'chrome://resources/js/icon.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
-import {isRTL} from 'chrome://resources/js/util.js';
+import {isRTL} from 'chrome://resources/js/util_ts.js';
 
 import {AlertIndicatorsElement} from './alert_indicators.js';
 import {getTemplate} from './tab.html.js';
diff --git a/chrome/browser/resources/tab_strip/tab_list.ts b/chrome/browser/resources/tab_strip/tab_list.ts
index 73318d5..190b6c8b 100644
--- a/chrome/browser/resources/tab_strip/tab_list.ts
+++ b/chrome/browser/resources/tab_strip/tab_list.ts
@@ -12,7 +12,7 @@
 import {FocusOutlineManager} from 'chrome://resources/js/focus_outline_manager.js';
 import {CustomElement} from 'chrome://resources/js/custom_element.js';
 import {EventTracker} from 'chrome://resources/js/event_tracker.js';
-import {isRTL} from 'chrome://resources/js/util.js';
+import {isRTL} from 'chrome://resources/js/util_ts.js';
 
 import {DragManager, DragManagerDelegate} from './drag_manager.js';
 import {isTabElement, TabElement} from './tab.js';
diff --git a/chrome/browser/resources/tab_strip/tab_swiper.ts b/chrome/browser/resources/tab_strip/tab_swiper.ts
index 68173d45..8ce4d1d 100644
--- a/chrome/browser/resources/tab_strip/tab_swiper.ts
+++ b/chrome/browser/resources/tab_strip/tab_swiper.ts
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {isRTL} from 'chrome://resources/js/util.js';
+import {isRTL} from 'chrome://resources/js/util_ts.js';
 
 /**
  * The minimum amount of pixels needed for the user to swipe for the position
diff --git a/chrome/browser/resources/webui_js_error/webui_js_error.ts b/chrome/browser/resources/webui_js_error/webui_js_error.ts
index 45b3f054..0c5da05 100644
--- a/chrome/browser/resources/webui_js_error/webui_js_error.ts
+++ b/chrome/browser/resources/webui_js_error/webui_js_error.ts
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {$} from 'chrome://resources/js/util.js';
+import {getRequiredElement} from 'chrome://resources/js/util_ts.js';
 
 /**
  * @fileoverview This JavaScript prints an error message, throws uncaught
@@ -73,7 +73,7 @@
   promise.then(promiseSuccessful);
 }
 
-$('error-button').onclick = logsErrorFromButtonClickHandler;
-$('exception-button').onclick = throwExceptionHandler;
-$('promise-button').onclick = unhandledPromiseRejection;
+getRequiredElement('error-button').onclick = logsErrorFromButtonClickHandler;
+getRequiredElement('exception-button').onclick = throwExceptionHandler;
+getRequiredElement('promise-button').onclick = unhandledPromiseRejection;
 logsErrorDuringPageLoadOuter();
diff --git a/chrome/browser/resources/welcome/google_apps/nux_google_apps.ts b/chrome/browser/resources/welcome/google_apps/nux_google_apps.ts
index ce1a17c..db5d855 100644
--- a/chrome/browser/resources/welcome/google_apps/nux_google_apps.ts
+++ b/chrome/browser/resources/welcome/google_apps/nux_google_apps.ts
@@ -6,7 +6,7 @@
 import 'chrome://resources/cr_elements/icons.html.js';
 import 'chrome://resources/cr_elements/cr_shared_vars.css.js';
 import 'chrome://resources/js/cr.js';
-import 'chrome://resources/js/util.js';
+import 'chrome://resources/js/util_ts.js';
 import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
 import '../shared/animations.css.js';
 import '../shared/chooser_shared.css.js';
@@ -15,7 +15,7 @@
 
 import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
-import {isRTL} from 'chrome://resources/js/util.js';
+import {isRTL} from 'chrome://resources/js/util_ts.js';
 import {IronA11yAnnouncer} from 'chrome://resources/polymer/v3_0/iron-a11y-announcer/iron-a11y-announcer.js';
 import {afterNextRender, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
diff --git a/chrome/browser/resources/welcome/ntp_background/nux_ntp_background.ts b/chrome/browser/resources/welcome/ntp_background/nux_ntp_background.ts
index 398cf17..6c50db0e 100644
--- a/chrome/browser/resources/welcome/ntp_background/nux_ntp_background.ts
+++ b/chrome/browser/resources/welcome/ntp_background/nux_ntp_background.ts
@@ -14,7 +14,7 @@
 
 import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
-import {isRTL} from 'chrome://resources/js/util.js';
+import {isRTL} from 'chrome://resources/js/util_ts.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {navigateToNextStep, NavigationMixin} from '../navigation_mixin.js';
diff --git a/chrome/browser/sessions/session_restore_observer_browsertest.cc b/chrome/browser/sessions/session_restore_observer_browsertest.cc
index 6b4c50d..0f4e1de 100644
--- a/chrome/browser/sessions/session_restore_observer_browsertest.cc
+++ b/chrome/browser/sessions/session_restore_observer_browsertest.cc
@@ -39,38 +39,6 @@
 using content::WebContents;
 using content::NavigationHandle;
 
-// This class records session-restore states of a tab when it starts navigation.
-class NavigationStartWebContentsObserver : public content::WebContentsObserver {
- public:
-  explicit NavigationStartWebContentsObserver(WebContents* contents)
-      : WebContentsObserver(contents) {}
-
-  NavigationStartWebContentsObserver(
-      const NavigationStartWebContentsObserver&) = delete;
-  NavigationStartWebContentsObserver& operator=(
-      const NavigationStartWebContentsObserver&) = delete;
-
-  // content::WebContentsObserver implementation:
-  void DidStartNavigation(NavigationHandle* navigation_handle) override {
-    WebContents* contents = navigation_handle->GetWebContents();
-    resource_coordinator::TabManager* tab_manager =
-        g_browser_process->GetTabManager();
-    ASSERT_TRUE(tab_manager);
-
-    is_session_restored_ = tab_manager->IsTabInSessionRestore(contents);
-    is_restored_in_foreground_ =
-        tab_manager->IsTabRestoredInForeground(contents);
-  }
-
-  // Returns the session-restore states at the navigation start.
-  bool is_session_restored() const { return is_session_restored_; }
-  bool is_restored_in_foreground() const { return is_restored_in_foreground_; }
-
- private:
-  bool is_session_restored_ = false;
-  bool is_restored_in_foreground_ = false;
-};
-
 class MockSessionRestoreObserver : public SessionRestoreObserver {
  public:
   MockSessionRestoreObserver() { SessionRestore::AddObserver(this); }
@@ -96,21 +64,9 @@
     session_restore_events_.emplace_back(
         SessionRestoreEvent::kFinishedLoadingTabs);
   }
-  void OnWillRestoreTab(WebContents* contents) override {
-    navigation_start_observers_.emplace(
-        contents, new NavigationStartWebContentsObserver(contents));
-  }
-
-  NavigationStartWebContentsObserver*
-  GetNavigationStartWebContentsObserverForTab(WebContents* contents) {
-    return navigation_start_observers_[contents].get();
-  }
 
  private:
   std::vector<SessionRestoreEvent> session_restore_events_;
-  std::unordered_map<WebContents*,
-                     std::unique_ptr<NavigationStartWebContentsObserver>>
-      navigation_start_observers_;
 };
 
 class SessionRestoreObserverTest : public InProcessBrowserTest {
@@ -201,24 +157,6 @@
   EXPECT_EQ(
       MockSessionRestoreObserver::SessionRestoreEvent::kFinishedLoadingTabs,
       session_restore_events()[1]);
-
-  // The only restored tab should be in foreground.
-  NavigationStartWebContentsObserver* observer =
-      session_restore_observer().GetNavigationStartWebContentsObserverForTab(
-          new_browser->tab_strip_model()->GetWebContentsAt(0));
-  EXPECT_TRUE(observer->is_session_restored());
-  EXPECT_TRUE(observer->is_restored_in_foreground());
-
-  // A new foreground tab should not be created by session restore.
-  ui_test_utils::NavigateToURLWithDisposition(
-      new_browser, GetTestURL(), WindowOpenDisposition::NEW_FOREGROUND_TAB,
-      ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
-  resource_coordinator::TabManager* tab_manager =
-      g_browser_process->GetTabManager();
-  WebContents* contents = new_browser->tab_strip_model()->GetWebContentsAt(1);
-  ASSERT_TRUE(contents);
-  EXPECT_FALSE(tab_manager->IsTabInSessionRestore(contents));
-  EXPECT_FALSE(tab_manager->IsTabRestoredInForeground(contents));
 }
 
 IN_PROC_BROWSER_TEST_F(SessionRestoreObserverTest, MultipleTabSessionRestore) {
@@ -243,20 +181,4 @@
   EXPECT_EQ(
       MockSessionRestoreObserver::SessionRestoreEvent::kFinishedLoadingTabs,
       session_restore_events()[1]);
-
-  // The first tab should be restored in foreground.
-  NavigationStartWebContentsObserver* observer =
-      session_restore_observer().GetNavigationStartWebContentsObserverForTab(
-          new_browser->tab_strip_model()->GetWebContentsAt(0));
-  ASSERT_TRUE(observer);
-  EXPECT_TRUE(observer->is_session_restored());
-  EXPECT_TRUE(observer->is_restored_in_foreground());
-
-  // The second tab should be restored in background.
-  observer =
-      session_restore_observer().GetNavigationStartWebContentsObserverForTab(
-          new_browser->tab_strip_model()->GetWebContentsAt(1));
-  ASSERT_TRUE(observer);
-  EXPECT_TRUE(observer->is_session_restored());
-  EXPECT_FALSE(observer->is_restored_in_foreground());
 }
diff --git a/chrome/browser/sessions/session_restore_observer_unittest.cc b/chrome/browser/sessions/session_restore_observer_unittest.cc
index a819f7a..4ff12a4b 100644
--- a/chrome/browser/sessions/session_restore_observer_unittest.cc
+++ b/chrome/browser/sessions/session_restore_observer_unittest.cc
@@ -226,26 +226,3 @@
       session_restore_events()[1]);
   EXPECT_EQ(0u, number_of_tabs_restoring());
 }
-
-TEST_F(SessionRestoreObserverTest, TabManagerShouldObserveSessionRestore) {
-  auto test_contents = CreateRestoredWebContents();
-
-  std::vector<SessionRestoreDelegate::RestoredTab> restored_tabs{
-      SessionRestoreDelegate::RestoredTab(test_contents.get(), false, false,
-                                          false, absl::nullopt)};
-
-  resource_coordinator::TabManager* tab_manager =
-      g_browser_process->GetTabManager();
-  EXPECT_FALSE(tab_manager->IsSessionRestoreLoadingTabs());
-  EXPECT_FALSE(tab_manager->IsTabInSessionRestore(test_contents.get()));
-
-  SessionRestore::NotifySessionRestoreStartedLoadingTabs();
-  SessionRestore::OnWillRestoreTab(test_contents.get());
-  EXPECT_TRUE(tab_manager->IsSessionRestoreLoadingTabs());
-  EXPECT_TRUE(tab_manager->IsTabInSessionRestore(test_contents.get()));
-  TabLoader::RestoreTabs(restored_tabs, base::TimeTicks());
-
-  LoadWebContents(test_contents.get());
-  EXPECT_FALSE(tab_manager->IsSessionRestoreLoadingTabs());
-  EXPECT_FALSE(tab_manager->IsTabInSessionRestore(test_contents.get()));
-}
diff --git a/chrome/browser/signin/e2e_tests/account_capabilities_observer.cc b/chrome/browser/signin/e2e_tests/account_capabilities_observer.cc
new file mode 100644
index 0000000..fd59075
--- /dev/null
+++ b/chrome/browser/signin/e2e_tests/account_capabilities_observer.cc
@@ -0,0 +1,41 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "account_capabilities_observer.h"
+
+namespace signin::test {
+
+AccountCapabilitiesObserver::AccountCapabilitiesObserver(
+    IdentityManager* identity_manager)
+    : identity_manager_(identity_manager) {
+  identity_manager_observation_.Observe(identity_manager);
+}
+
+AccountCapabilitiesObserver::~AccountCapabilitiesObserver() = default;
+
+void AccountCapabilitiesObserver::OnExtendedAccountInfoUpdated(
+    const AccountInfo& info) {
+  if (info.account_id != account_id_)
+    return;
+
+  if (info.capabilities.AreAllCapabilitiesKnown())
+    run_loop_.Quit();
+}
+
+// This should be called only once per AccountCapabilitiesObserver instance.
+void AccountCapabilitiesObserver::WaitForAllCapabilitiesToBeKnown(
+    CoreAccountId account_id) {
+  DCHECK(
+      identity_manager_observation_.IsObservingSource(identity_manager_.get()));
+  AccountInfo info =
+      identity_manager_->FindExtendedAccountInfoByAccountId(account_id);
+  if (info.capabilities.AreAllCapabilitiesKnown())
+    return;
+
+  account_id_ = account_id;
+  run_loop_.Run();
+  identity_manager_observation_.Reset();
+}
+
+}  // namespace signin::test
diff --git a/chrome/browser/signin/e2e_tests/account_capabilities_observer.h b/chrome/browser/signin/e2e_tests/account_capabilities_observer.h
new file mode 100644
index 0000000..8acff55
--- /dev/null
+++ b/chrome/browser/signin/e2e_tests/account_capabilities_observer.h
@@ -0,0 +1,35 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SIGNIN_E2E_TESTS_ACCOUNT_CAPABILITIES_OBSERVER_H_
+#define CHROME_BROWSER_SIGNIN_E2E_TESTS_ACCOUNT_CAPABILITIES_OBSERVER_H_
+
+#include "base/run_loop.h"
+#include "components/signin/public/identity_manager/identity_manager.h"
+
+namespace signin::test {
+
+// Observer class allowing to wait for account capabilities to be known.
+class AccountCapabilitiesObserver : public IdentityManager::Observer {
+ public:
+  explicit AccountCapabilitiesObserver(IdentityManager* identity_manager);
+  ~AccountCapabilitiesObserver() override;
+
+  // IdentityManager::Observer:
+  void OnExtendedAccountInfoUpdated(const AccountInfo& info) override;
+
+  // This should be called only once per AccountCapabilitiesObserver instance.
+  void WaitForAllCapabilitiesToBeKnown(CoreAccountId account_id);
+
+ private:
+  raw_ptr<IdentityManager> identity_manager_ = nullptr;
+  CoreAccountId account_id_;
+  base::RunLoop run_loop_;
+  base::ScopedObservation<IdentityManager, IdentityManager::Observer>
+      identity_manager_observation_{this};
+};
+
+}  // namespace signin::test
+
+#endif  // CHROME_BROWSER_SIGNIN_E2E_TESTS_ACCOUNT_CAPABILITIES_OBSERVER_H_
diff --git a/chrome/browser/signin/e2e_tests/accounts_removed_waiter.cc b/chrome/browser/signin/e2e_tests/accounts_removed_waiter.cc
new file mode 100644
index 0000000..cf9e17e2
--- /dev/null
+++ b/chrome/browser/signin/e2e_tests/accounts_removed_waiter.cc
@@ -0,0 +1,32 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "accounts_removed_waiter.h"
+
+namespace signin::test {
+
+AccountsRemovedWaiter::AccountsRemovedWaiter(
+    signin::IdentityManager* identity_manager)
+    : identity_manager_(identity_manager) {
+  DCHECK(identity_manager_);
+}
+
+AccountsRemovedWaiter::~AccountsRemovedWaiter() = default;
+
+void AccountsRemovedWaiter::Wait() {
+  if (identity_manager_->GetAccountsWithRefreshTokens().empty())
+    return;
+  observation_.Observe(identity_manager_.get());
+  run_loop_.Run();
+}
+
+void AccountsRemovedWaiter::OnRefreshTokenRemovedForAccount(
+    const CoreAccountId& account_id) {
+  if (!identity_manager_->GetAccountsWithRefreshTokens().empty())
+    return;
+  observation_.Reset();
+  run_loop_.Quit();
+}
+
+}  // namespace signin::test
diff --git a/chrome/browser/signin/e2e_tests/accounts_removed_waiter.h b/chrome/browser/signin/e2e_tests/accounts_removed_waiter.h
new file mode 100644
index 0000000..4518fc98
--- /dev/null
+++ b/chrome/browser/signin/e2e_tests/accounts_removed_waiter.h
@@ -0,0 +1,35 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SIGNIN_E2E_TESTS_ACCOUNTS_REMOVED_WAITER_H_
+#define CHROME_BROWSER_SIGNIN_E2E_TESTS_ACCOUNTS_REMOVED_WAITER_H_
+
+#include "base/run_loop.h"
+#include "components/signin/public/identity_manager/identity_manager.h"
+
+namespace signin::test {
+
+// Helper class to wait until all accounts have been removed from the
+// `IdentityManager`.
+class AccountsRemovedWaiter : public signin::IdentityManager::Observer {
+ public:
+  explicit AccountsRemovedWaiter(signin::IdentityManager* identity_manager);
+  ~AccountsRemovedWaiter() override;
+
+  void Wait();
+
+ private:
+  void OnRefreshTokenRemovedForAccount(
+      const CoreAccountId& account_id) override;
+
+  base::RunLoop run_loop_;
+  const raw_ptr<signin::IdentityManager> identity_manager_;
+  base::ScopedObservation<signin::IdentityManager,
+                          signin::IdentityManager::Observer>
+      observation_{this};
+};
+
+}  // namespace signin::test
+
+#endif  // CHROME_BROWSER_SIGNIN_E2E_TESTS_ACCOUNTS_REMOVED_WAITER_H_
diff --git a/chrome/browser/signin/e2e_tests/live_sign_in_test.cc b/chrome/browser/signin/e2e_tests/live_sign_in_test.cc
index d20a082..db1a994f 100644
--- a/chrome/browser/signin/e2e_tests/live_sign_in_test.cc
+++ b/chrome/browser/signin/e2e_tests/live_sign_in_test.cc
@@ -2,29 +2,24 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/memory/raw_ptr.h"
-#include "base/run_loop.h"
-#include "base/scoped_observation.h"
 #include "base/strings/stringprintf.h"
-#include "base/time/time.h"
-#include "build/build_config.h"
+#include "base/test/bind.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/signin/account_reconcilor_factory.h"
+#include "chrome/browser/signin/e2e_tests/account_capabilities_observer.h"
+#include "chrome/browser/signin/e2e_tests/accounts_removed_waiter.h"
 #include "chrome/browser/signin/e2e_tests/live_test.h"
+#include "chrome/browser/signin/e2e_tests/sign_in_test_observer.h"
+#include "chrome/browser/signin/e2e_tests/signin_util.h"
 #include "chrome/browser/signin/e2e_tests/test_accounts_util.h"
-#include "chrome/browser/signin/identity_manager_factory.h"
-#include "chrome/browser/sync/sync_service_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
-#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "chrome/browser/ui/webui/signin/login_ui_test_utils.h"
 #include "chrome/browser/ui/webui/signin/signin_email_confirmation_dialog.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/signin/core/browser/account_reconcilor.h"
 #include "components/signin/public/base/consent_level.h"
-#include "components/signin/public/identity_manager/account_capabilities.h"
 #include "components/signin/public/identity_manager/account_info.h"
 #include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
@@ -32,7 +27,6 @@
 #include "components/signin/public/identity_manager/tribool.h"
 #include "components/sync/driver/sync_service.h"
 #include "content/public/test/browser_test.h"
-#include "google_apis/gaia/core_account_id.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
@@ -41,221 +35,7 @@
 #include "chrome/browser/sync/sync_ui_util.h"
 #endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
-namespace signin {
-namespace test {
-
-const base::TimeDelta kDialogTimeout = base::Seconds(10);
-
-// A wrapper importing the settings module when the chrome://settings serve the
-// Polymer 3 version.
-const char kSettingsScriptWrapperFormat[] =
-    "import('./settings.js').then(settings => {%s});";
-
-enum class PrimarySyncAccountWait { kWaitForAdded, kWaitForCleared, kNotWait };
-
-// Observes various sign-in events and allows to wait for a specific state of
-// signed-in accounts.
-class SignInTestObserver : public IdentityManager::Observer,
-                           public AccountReconcilor::Observer {
- public:
-  explicit SignInTestObserver(IdentityManager* identity_manager,
-                              AccountReconcilor* reconcilor)
-      : identity_manager_(identity_manager), reconcilor_(reconcilor) {
-    identity_manager_observation_.Observe(identity_manager_.get());
-    account_reconcilor_observation_.Observe(reconcilor_.get());
-  }
-  ~SignInTestObserver() override = default;
-
-  // IdentityManager::Observer:
-  void OnPrimaryAccountChanged(
-      const PrimaryAccountChangeEvent& event) override {
-    if (event.GetEventTypeFor(ConsentLevel::kSync) ==
-        PrimaryAccountChangeEvent::Type::kNone) {
-      return;
-    }
-    QuitIfConditionIsSatisfied();
-  }
-  void OnRefreshTokenUpdatedForAccount(const CoreAccountInfo&) override {
-    QuitIfConditionIsSatisfied();
-  }
-  void OnRefreshTokenRemovedForAccount(const CoreAccountId&) override {
-    QuitIfConditionIsSatisfied();
-  }
-  void OnErrorStateOfRefreshTokenUpdatedForAccount(
-      const CoreAccountInfo&,
-      const GoogleServiceAuthError&) override {
-    QuitIfConditionIsSatisfied();
-  }
-  void OnAccountsInCookieUpdated(const AccountsInCookieJarInfo&,
-                                 const GoogleServiceAuthError&) override {
-    QuitIfConditionIsSatisfied();
-  }
-
-  // AccountReconcilor::Observer:
-  // TODO(https://crbug.com/1051864): Remove this obsever method once the bug is
-  // fixed.
-  void OnStateChanged(signin_metrics::AccountReconcilorState state) override {
-    if (state == signin_metrics::ACCOUNT_RECONCILOR_OK) {
-      // This will trigger cookie update if accounts are stale.
-      identity_manager_->GetAccountsInCookieJar();
-    }
-  }
-
-  void WaitForAccountChanges(int signed_in_accounts,
-                             PrimarySyncAccountWait primary_sync_account_wait) {
-    expected_signed_in_accounts_ = signed_in_accounts;
-    primary_sync_account_wait_ = primary_sync_account_wait;
-    are_expectations_set = true;
-    QuitIfConditionIsSatisfied();
-    run_loop_.Run();
-  }
-
- private:
-  void QuitIfConditionIsSatisfied() {
-    if (!are_expectations_set)
-      return;
-
-    int accounts_with_valid_refresh_token =
-        CountAccountsWithValidRefreshToken();
-    int accounts_in_cookie = CountSignedInAccountsInCookie();
-
-    if (accounts_with_valid_refresh_token != accounts_in_cookie ||
-        accounts_with_valid_refresh_token != expected_signed_in_accounts_) {
-      return;
-    }
-
-    switch (primary_sync_account_wait_) {
-      case PrimarySyncAccountWait::kWaitForAdded:
-        if (!HasValidPrimarySyncAccount())
-          return;
-        break;
-      case PrimarySyncAccountWait::kWaitForCleared:
-        if (identity_manager_->HasPrimaryAccount(signin::ConsentLevel::kSync))
-          return;
-        break;
-      case PrimarySyncAccountWait::kNotWait:
-        break;
-    }
-
-    run_loop_.Quit();
-  }
-
-  int CountAccountsWithValidRefreshToken() const {
-    std::vector<CoreAccountInfo> accounts_with_refresh_tokens =
-        identity_manager_->GetAccountsWithRefreshTokens();
-    int valid_accounts = 0;
-    for (const auto& account_info : accounts_with_refresh_tokens) {
-      if (!identity_manager_->HasAccountWithRefreshTokenInPersistentErrorState(
-              account_info.account_id)) {
-        ++valid_accounts;
-      }
-    }
-    return valid_accounts;
-  }
-
-  int CountSignedInAccountsInCookie() const {
-    signin::AccountsInCookieJarInfo accounts_in_cookie_jar =
-        identity_manager_->GetAccountsInCookieJar();
-    if (!accounts_in_cookie_jar.accounts_are_fresh)
-      return -1;
-
-    return accounts_in_cookie_jar.signed_in_accounts.size();
-  }
-
-  bool HasValidPrimarySyncAccount() const {
-    CoreAccountId primary_account_id =
-        identity_manager_->GetPrimaryAccountId(signin::ConsentLevel::kSync);
-    if (primary_account_id.empty())
-      return false;
-
-    return !identity_manager_->HasAccountWithRefreshTokenInPersistentErrorState(
-        primary_account_id);
-  }
-
-  const raw_ptr<signin::IdentityManager> identity_manager_;
-  const raw_ptr<AccountReconcilor> reconcilor_;
-  base::ScopedObservation<IdentityManager, IdentityManager::Observer>
-      identity_manager_observation_{this};
-  base::ScopedObservation<AccountReconcilor, AccountReconcilor::Observer>
-      account_reconcilor_observation_{this};
-  base::RunLoop run_loop_;
-
-  bool are_expectations_set = false;
-  int expected_signed_in_accounts_ = 0;
-  PrimarySyncAccountWait primary_sync_account_wait_ =
-      PrimarySyncAccountWait::kNotWait;
-};
-
-// Helper class to wait until all accounts have been removed from the
-// `IdentityManager`.
-class AccountsRemovedWaiter : public signin::IdentityManager::Observer {
- public:
-  explicit AccountsRemovedWaiter(signin::IdentityManager* identity_manager)
-      : identity_manager_(identity_manager) {
-    DCHECK(identity_manager_);
-  }
-
-  void Wait() {
-    if (identity_manager_->GetAccountsWithRefreshTokens().empty())
-      return;
-    observation_.Observe(identity_manager_.get());
-    run_loop_.Run();
-  }
-
- private:
-  void OnRefreshTokenRemovedForAccount(
-      const CoreAccountId& account_id) override {
-    if (!identity_manager_->GetAccountsWithRefreshTokens().empty())
-      return;
-    observation_.Reset();
-    run_loop_.Quit();
-  }
-
-  base::RunLoop run_loop_;
-  const raw_ptr<signin::IdentityManager> identity_manager_;
-  base::ScopedObservation<signin::IdentityManager,
-                          signin::IdentityManager::Observer>
-      observation_{this};
-};
-
-// Observer class allowing to wait for account capabilities to be known.
-class AccountCapabilitiesObserver : public IdentityManager::Observer {
- public:
-  explicit AccountCapabilitiesObserver(IdentityManager* identity_manager)
-      : identity_manager_(identity_manager) {
-    identity_manager_observation_.Observe(identity_manager);
-  }
-
-  // IdentityManager::Observer:
-  void OnExtendedAccountInfoUpdated(const AccountInfo& info) override {
-    if (info.account_id != account_id_)
-      return;
-
-    if (info.capabilities.AreAllCapabilitiesKnown())
-      run_loop_.Quit();
-  }
-
-  // This should be called only once per AccountCapabilitiesObserver instance.
-  void WaitForAllCapabilitiesToBeKnown(CoreAccountId account_id) {
-    DCHECK(identity_manager_observation_.IsObservingSource(
-        identity_manager_.get()));
-    AccountInfo info =
-        identity_manager_->FindExtendedAccountInfoByAccountId(account_id);
-    if (info.capabilities.AreAllCapabilitiesKnown())
-      return;
-
-    account_id_ = account_id;
-    run_loop_.Run();
-    identity_manager_observation_.Reset();
-  }
-
- private:
-  raw_ptr<IdentityManager> identity_manager_ = nullptr;
-  CoreAccountId account_id_;
-  base::RunLoop run_loop_;
-  base::ScopedObservation<IdentityManager, IdentityManager::Observer>
-      identity_manager_observation_{this};
-};
+namespace signin::test {
 
 // Live tests for SignIn.
 // These tests can be run with:
@@ -272,89 +52,24 @@
         ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
   }
 
-  void SignInFromWeb(const TestAccount& test_account,
-                     int previously_signed_in_accounts) {
-    ASSERT_TRUE(AddTabAtIndex(0, GaiaUrls::GetInstance()->add_account_url(),
-                              ui::PageTransition::PAGE_TRANSITION_TYPED));
-    SignInFromCurrentPage(test_account, previously_signed_in_accounts);
-  }
-
-  void SignInFromSettings(const TestAccount& test_account,
-                          int previously_signed_in_accounts) {
-    GURL settings_url("chrome://settings");
-    ASSERT_TRUE(AddTabAtIndex(0, settings_url,
-                              ui::PageTransition::PAGE_TRANSITION_TYPED));
-    auto* settings_tab = browser()->tab_strip_model()->GetActiveWebContents();
-    EXPECT_TRUE(content::ExecuteScript(
-        settings_tab,
-        base::StringPrintf(
-            kSettingsScriptWrapperFormat,
-            "settings.SyncBrowserProxyImpl.getInstance().startSignIn();")));
-    SignInFromCurrentPage(test_account, previously_signed_in_accounts);
-  }
-
-  void SignInFromCurrentPage(const TestAccount& test_account,
-                             int previously_signed_in_accounts) {
-    SignInTestObserver observer(identity_manager(), account_reconcilor());
-    login_ui_test_utils::ExecuteJsToSigninInSigninFrame(
-        browser(), test_account.user, test_account.password);
-    observer.WaitForAccountChanges(previously_signed_in_accounts + 1,
-                                   PrimarySyncAccountWait::kNotWait);
-  }
-
-  void TurnOnSync(const TestAccount& test_account,
-                  int previously_signed_in_accounts) {
-    SignInFromSettings(test_account, previously_signed_in_accounts);
-
-    SignInTestObserver observer(identity_manager(), account_reconcilor());
-    EXPECT_TRUE(login_ui_test_utils::ConfirmSyncConfirmationDialog(
-        browser(), kDialogTimeout));
-    observer.WaitForAccountChanges(previously_signed_in_accounts + 1,
-                                   PrimarySyncAccountWait::kWaitForAdded);
-  }
-
-  void SignOutFromWeb() {
-    SignInTestObserver observer(identity_manager(), account_reconcilor());
-    ASSERT_TRUE(AddTabAtIndex(0, GaiaUrls::GetInstance()->service_logout_url(),
-                              ui::PageTransition::PAGE_TRANSITION_TYPED));
-    observer.WaitForAccountChanges(0, PrimarySyncAccountWait::kNotWait);
-  }
-
-  void TurnOffSync() {
-    GURL settings_url("chrome://settings");
-    ASSERT_TRUE(AddTabAtIndex(0, settings_url,
-                              ui::PageTransition::PAGE_TRANSITION_TYPED));
-    SignInTestObserver observer(identity_manager(), account_reconcilor());
-    auto* settings_tab = browser()->tab_strip_model()->GetActiveWebContents();
-    EXPECT_TRUE(content::ExecuteScript(
-        settings_tab,
-        base::StringPrintf(
-            kSettingsScriptWrapperFormat,
-            "settings.SyncBrowserProxyImpl.getInstance().signOut(false)")));
-    observer.WaitForAccountChanges(0, PrimarySyncAccountWait::kWaitForCleared);
-  }
-
   signin::IdentityManager* identity_manager() {
-    return identity_manager(browser());
+    return signin::test::identity_manager(browser());
   }
-
-  signin::IdentityManager* identity_manager(Browser* browser) {
-    return IdentityManagerFactory::GetForProfile(browser->profile());
+  syncer::SyncService* sync_service() {
+    return signin::test::sync_service(browser());
   }
-
-  syncer::SyncService* sync_service() { return sync_service(browser()); }
-
-  syncer::SyncService* sync_service(Browser* browser) {
-    return SyncServiceFactory::GetForProfile(browser->profile());
-  }
-
   AccountReconcilor* account_reconcilor() {
-    return account_reconcilor(browser());
+    return signin::test::account_reconcilor(browser());
   }
 
-  AccountReconcilor* account_reconcilor(Browser* browser) {
-    return AccountReconcilorFactory::GetForProfile(browser->profile());
-  }
+  SignInFunctions sign_in_functions = SignInFunctions(
+      base::BindLambdaForTesting(
+          [this]() -> Browser* { return this->browser(); }),
+      base::BindLambdaForTesting([this](int index,
+                                        const GURL& url,
+                                        ui::PageTransition transition) -> bool {
+        return this->AddTabAtIndex(index, url, transition);
+      }));
 };
 
 // This test can pass. Marked as manual because it TIMED_OUT on Win7.
@@ -365,7 +80,7 @@
 IN_PROC_BROWSER_TEST_F(LiveSignInTest, MANUAL_SimpleSignInFlow) {
   TestAccount ta;
   CHECK(GetTestAccountsUtil()->GetAccount("TEST_ACCOUNT_1", ta));
-  SignInFromSettings(ta, 0);
+  sign_in_functions.SignInFromSettings(ta, 0);
 
   const AccountsInCookieJarInfo& accounts_in_cookie_jar =
       identity_manager()->GetAccountsInCookieJar();
@@ -388,7 +103,7 @@
 IN_PROC_BROWSER_TEST_F(LiveSignInTest, MANUAL_WebSignOut) {
   TestAccount test_account;
   CHECK(GetTestAccountsUtil()->GetAccount("TEST_ACCOUNT_1", test_account));
-  TurnOnSync(test_account, 0);
+  sign_in_functions.TurnOnSync(test_account, 0);
 
   const CoreAccountInfo& primary_account =
       identity_manager()->GetPrimaryAccountInfo(signin::ConsentLevel::kSync);
@@ -396,7 +111,7 @@
   EXPECT_TRUE(gaia::AreEmailsSame(test_account.user, primary_account.email));
   EXPECT_TRUE(sync_service()->IsSyncFeatureEnabled());
 
-  SignOutFromWeb();
+  sign_in_functions.SignOutFromWeb();
 
   const AccountsInCookieJarInfo& accounts_in_cookie_jar =
       identity_manager()->GetAccountsInCookieJar();
@@ -422,7 +137,7 @@
 IN_PROC_BROWSER_TEST_F(LiveSignInTest, MANUAL_WebSignInAndSignOut) {
   TestAccount test_account_1;
   CHECK(GetTestAccountsUtil()->GetAccount("TEST_ACCOUNT_1", test_account_1));
-  SignInFromWeb(test_account_1, 0);
+  sign_in_functions.SignInFromWeb(test_account_1, 0);
 
   const AccountsInCookieJarInfo& accounts_in_cookie_jar_1 =
       identity_manager()->GetAccountsInCookieJar();
@@ -438,7 +153,7 @@
 
   TestAccount test_account_2;
   CHECK(GetTestAccountsUtil()->GetAccount("TEST_ACCOUNT_2", test_account_2));
-  SignInFromWeb(test_account_2, 1);
+  sign_in_functions.SignInFromWeb(test_account_2, 1);
 
   const AccountsInCookieJarInfo& accounts_in_cookie_jar_2 =
       identity_manager()->GetAccountsInCookieJar();
@@ -453,7 +168,7 @@
   EXPECT_FALSE(
       identity_manager()->HasPrimaryAccount(signin::ConsentLevel::kSync));
 
-  SignOutFromWeb();
+  sign_in_functions.SignOutFromWeb();
 
   const AccountsInCookieJarInfo& accounts_in_cookie_jar_3 =
       identity_manager()->GetAccountsInCookieJar();
@@ -472,11 +187,11 @@
 IN_PROC_BROWSER_TEST_F(LiveSignInTest, MANUAL_TurnOffSync) {
   TestAccount test_account_1;
   CHECK(GetTestAccountsUtil()->GetAccount("TEST_ACCOUNT_1", test_account_1));
-  TurnOnSync(test_account_1, 0);
+  sign_in_functions.TurnOnSync(test_account_1, 0);
 
   TestAccount test_account_2;
   CHECK(GetTestAccountsUtil()->GetAccount("TEST_ACCOUNT_2", test_account_2));
-  SignInFromWeb(test_account_2, 1);
+  sign_in_functions.SignInFromWeb(test_account_2, 1);
 
   const CoreAccountInfo& primary_account =
       identity_manager()->GetPrimaryAccountInfo(signin::ConsentLevel::kSync);
@@ -484,7 +199,7 @@
   EXPECT_TRUE(gaia::AreEmailsSame(test_account_1.user, primary_account.email));
   EXPECT_TRUE(sync_service()->IsSyncFeatureEnabled());
 
-  TurnOffSync();
+  sign_in_functions.TurnOffSync();
 
   const AccountsInCookieJarInfo& accounts_in_cookie_jar_2 =
       identity_manager()->GetAccountsInCookieJar();
@@ -501,10 +216,10 @@
 IN_PROC_BROWSER_TEST_F(LiveSignInTest, MANUAL_TurnOffSyncWhenPaused) {
   TestAccount test_account_1;
   CHECK(GetTestAccountsUtil()->GetAccount("TEST_ACCOUNT_1", test_account_1));
-  TurnOnSync(test_account_1, 0);
+  sign_in_functions.TurnOnSync(test_account_1, 0);
 
   // Get in sync paused state.
-  SignOutFromWeb();
+  sign_in_functions.SignOutFromWeb();
 
   const CoreAccountInfo& primary_account =
       identity_manager()->GetPrimaryAccountInfo(signin::ConsentLevel::kSync);
@@ -515,7 +230,7 @@
       identity_manager()->HasAccountWithRefreshTokenInPersistentErrorState(
           primary_account.account_id));
 
-  TurnOffSync();
+  sign_in_functions.TurnOffSync();
   EXPECT_FALSE(
       identity_manager()->HasPrimaryAccount(signin::ConsentLevel::kSync));
 
@@ -533,7 +248,7 @@
 IN_PROC_BROWSER_TEST_F(LiveSignInTest, MANUAL_CancelSyncWithWebAccount) {
   TestAccount test_account;
   CHECK(GetTestAccountsUtil()->GetAccount("TEST_ACCOUNT_1", test_account));
-  SignInFromWeb(test_account, 0);
+  sign_in_functions.SignInFromWeb(test_account, 0);
 
   SignInTestObserver observer(identity_manager(), account_reconcilor());
   GURL settings_url("chrome://settings");
@@ -571,7 +286,7 @@
 IN_PROC_BROWSER_TEST_F(LiveSignInTest, MANUAL_CancelSync) {
   TestAccount test_account;
   CHECK(GetTestAccountsUtil()->GetAccount("TEST_ACCOUNT_1", test_account));
-  SignInFromSettings(test_account, 0);
+  sign_in_functions.SignInFromSettings(test_account, 0);
 
   SignInTestObserver observer(identity_manager(), account_reconcilor());
   EXPECT_TRUE(login_ui_test_utils::CancelSyncConfirmationDialog(
@@ -598,13 +313,13 @@
   // Enable and disable sync for the first account.
   TestAccount test_account_1;
   CHECK(GetTestAccountsUtil()->GetAccount("TEST_ACCOUNT_1", test_account_1));
-  TurnOnSync(test_account_1, 0);
-  TurnOffSync();
+  sign_in_functions.TurnOnSync(test_account_1, 0);
+  sign_in_functions.TurnOffSync();
 
   // Start enable sync for the second account.
   TestAccount test_account_2;
   CHECK(GetTestAccountsUtil()->GetAccount("TEST_ACCOUNT_2", test_account_2));
-  SignInFromSettings(test_account_2, 0);
+  sign_in_functions.SignInFromSettings(test_account_2, 0);
 
   // Set up an observer for removing the second account from the original
   // profile.
@@ -627,8 +342,9 @@
   EXPECT_NE(browser()->profile(), new_browser->profile());
 
   // Confirm sync in the new browser window.
-  SignInTestObserver new_browser_observer(identity_manager(new_browser),
-                                          account_reconcilor(new_browser));
+  SignInTestObserver new_browser_observer(
+      signin::test::identity_manager(new_browser),
+      signin::test::account_reconcilor(new_browser));
   EXPECT_TRUE(login_ui_test_utils::ConfirmSyncConfirmationDialog(
       new_browser, kDialogTimeout));
   new_browser_observer.WaitForAccountChanges(
@@ -636,7 +352,7 @@
 
   // Check accounts in cookies in the new profile.
   const AccountsInCookieJarInfo& accounts_in_cookie_jar =
-      identity_manager(new_browser)->GetAccountsInCookieJar();
+      signin::test::identity_manager(new_browser)->GetAccountsInCookieJar();
   EXPECT_TRUE(accounts_in_cookie_jar.accounts_are_fresh);
   ASSERT_EQ(1u, accounts_in_cookie_jar.signed_in_accounts.size());
   const gaia::ListedAccount& account =
@@ -645,13 +361,13 @@
 
   // Check the primary account in the new profile is set and syncing.
   const CoreAccountInfo& primary_account =
-      identity_manager(new_browser)
+      signin::test::identity_manager(new_browser)
           ->GetPrimaryAccountInfo(signin::ConsentLevel::kSync);
   EXPECT_FALSE(primary_account.IsEmpty());
   EXPECT_TRUE(gaia::AreEmailsSame(test_account_2.user, primary_account.email));
-  EXPECT_TRUE(identity_manager(new_browser)
+  EXPECT_TRUE(signin::test::identity_manager(new_browser)
                   ->HasAccountWithRefreshToken(primary_account.account_id));
-  EXPECT_TRUE(sync_service(new_browser)->IsSyncFeatureEnabled());
+  EXPECT_TRUE(signin::test::sync_service(new_browser)->IsSyncFeatureEnabled());
 
   // Check that the second account was removed from the original profile.
   original_browser_observer.WaitForAccountChanges(
@@ -675,13 +391,13 @@
   // Enable and disable sync for the first account.
   TestAccount test_account_1;
   CHECK(GetTestAccountsUtil()->GetAccount("TEST_ACCOUNT_1", test_account_1));
-  TurnOnSync(test_account_1, 0);
-  TurnOffSync();
+  sign_in_functions.TurnOnSync(test_account_1, 0);
+  sign_in_functions.TurnOffSync();
 
   // Start enable sync for the second account.
   TestAccount test_account_2;
   CHECK(GetTestAccountsUtil()->GetAccount("TEST_ACCOUNT_2", test_account_2));
-  SignInFromSettings(test_account_2, 0);
+  sign_in_functions.SignInFromSettings(test_account_2, 0);
 
   // Check there is only one profile.
   ProfileManager* profile_manager = g_browser_process->profile_manager();
@@ -730,13 +446,13 @@
   // Enable and disable sync for the first account.
   TestAccount test_account_1;
   CHECK(GetTestAccountsUtil()->GetAccount("TEST_ACCOUNT_1", test_account_1));
-  TurnOnSync(test_account_1, 0);
-  TurnOffSync();
+  sign_in_functions.TurnOnSync(test_account_1, 0);
+  sign_in_functions.TurnOffSync();
 
   // Start enable sync for the second account.
   TestAccount test_account_2;
   CHECK(GetTestAccountsUtil()->GetAccount("TEST_ACCOUNT_2", test_account_2));
-  SignInFromSettings(test_account_2, 0);
+  sign_in_functions.SignInFromSettings(test_account_2, 0);
 
   // Check there is only one profile.
   ProfileManager* profile_manager = g_browser_process->profile_manager();
@@ -774,7 +490,7 @@
 
     TestAccount ta;
     ASSERT_TRUE(GetTestAccountsUtil()->GetAccount("TEST_ACCOUNT_1", ta));
-    SignInFromSettings(ta, 0);
+    sign_in_functions.SignInFromSettings(ta, 0);
 
     CoreAccountInfo core_account_info =
         identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSignin);
@@ -795,7 +511,7 @@
 
     TestAccount ta;
     ASSERT_TRUE(GetTestAccountsUtil()->GetAccount("TEST_ACCOUNT_MINOR", ta));
-    SignInFromWeb(ta, /*previously_signed_in_accounts=*/1);
+    sign_in_functions.SignInFromWeb(ta, /*previously_signed_in_accounts=*/1);
 
     CoreAccountInfo core_account_info =
         identity_manager()->FindExtendedAccountInfoByEmailAddress(ta.user);
@@ -811,5 +527,4 @@
   }
 }
 
-}  // namespace test
-}  // namespace signin
+}  // namespace signin::test
diff --git a/chrome/browser/signin/e2e_tests/sign_in_test_observer.cc b/chrome/browser/signin/e2e_tests/sign_in_test_observer.cc
new file mode 100644
index 0000000..727ca849
--- /dev/null
+++ b/chrome/browser/signin/e2e_tests/sign_in_test_observer.cc
@@ -0,0 +1,126 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sign_in_test_observer.h"
+
+#include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h"
+
+namespace signin::test {
+
+SignInTestObserver::SignInTestObserver(IdentityManager* identity_manager,
+                                       AccountReconcilor* reconcilor)
+    : identity_manager_(identity_manager), reconcilor_(reconcilor) {
+  identity_manager_observation_.Observe(identity_manager_.get());
+  account_reconcilor_observation_.Observe(reconcilor_.get());
+}
+
+SignInTestObserver::~SignInTestObserver() = default;
+
+void SignInTestObserver::OnPrimaryAccountChanged(
+    const PrimaryAccountChangeEvent& event) {
+  if (event.GetEventTypeFor(ConsentLevel::kSync) ==
+      PrimaryAccountChangeEvent::Type::kNone) {
+    return;
+  }
+  QuitIfConditionIsSatisfied();
+}
+void SignInTestObserver::OnRefreshTokenUpdatedForAccount(
+    const CoreAccountInfo&) {
+  QuitIfConditionIsSatisfied();
+}
+void SignInTestObserver::OnRefreshTokenRemovedForAccount(const CoreAccountId&) {
+  QuitIfConditionIsSatisfied();
+}
+void SignInTestObserver::OnErrorStateOfRefreshTokenUpdatedForAccount(
+    const CoreAccountInfo&,
+    const GoogleServiceAuthError&) {
+  QuitIfConditionIsSatisfied();
+}
+void SignInTestObserver::OnAccountsInCookieUpdated(
+    const AccountsInCookieJarInfo&,
+    const GoogleServiceAuthError&) {
+  QuitIfConditionIsSatisfied();
+}
+
+// TODO(https://crbug.com/1051864): Remove this observer method once the bug is
+// fixed.
+void SignInTestObserver::OnStateChanged(
+    signin_metrics::AccountReconcilorState state) {
+  if (state == signin_metrics::ACCOUNT_RECONCILOR_OK) {
+    // This will trigger cookie update if accounts are stale.
+    identity_manager_->GetAccountsInCookieJar();
+  }
+}
+
+void SignInTestObserver::WaitForAccountChanges(
+    int signed_in_accounts,
+    PrimarySyncAccountWait primary_sync_account_wait) {
+  expected_signed_in_accounts_ = signed_in_accounts;
+  primary_sync_account_wait_ = primary_sync_account_wait;
+  are_expectations_set = true;
+  QuitIfConditionIsSatisfied();
+  run_loop_.Run();
+}
+
+void SignInTestObserver::QuitIfConditionIsSatisfied() {
+  if (!are_expectations_set)
+    return;
+
+  int accounts_with_valid_refresh_token = CountAccountsWithValidRefreshToken();
+  int accounts_in_cookie = CountSignedInAccountsInCookie();
+
+  if (accounts_with_valid_refresh_token != accounts_in_cookie ||
+      accounts_with_valid_refresh_token != expected_signed_in_accounts_) {
+    return;
+  }
+
+  switch (primary_sync_account_wait_) {
+    case PrimarySyncAccountWait::kWaitForAdded:
+      if (!HasValidPrimarySyncAccount())
+        return;
+      break;
+    case PrimarySyncAccountWait::kWaitForCleared:
+      if (identity_manager_->HasPrimaryAccount(signin::ConsentLevel::kSync))
+        return;
+      break;
+    case PrimarySyncAccountWait::kNotWait:
+      break;
+  }
+
+  run_loop_.Quit();
+}
+
+int SignInTestObserver::CountAccountsWithValidRefreshToken() const {
+  std::vector<CoreAccountInfo> accounts_with_refresh_tokens =
+      identity_manager_->GetAccountsWithRefreshTokens();
+  int valid_accounts = 0;
+  for (const auto& account_info : accounts_with_refresh_tokens) {
+    if (!identity_manager_->HasAccountWithRefreshTokenInPersistentErrorState(
+            account_info.account_id)) {
+      ++valid_accounts;
+    }
+  }
+  return valid_accounts;
+}
+
+int SignInTestObserver::CountSignedInAccountsInCookie() const {
+  signin::AccountsInCookieJarInfo accounts_in_cookie_jar =
+      identity_manager_->GetAccountsInCookieJar();
+  if (!accounts_in_cookie_jar.accounts_are_fresh)
+    return -1;
+
+  return accounts_in_cookie_jar.signed_in_accounts.size();
+}
+
+bool SignInTestObserver::HasValidPrimarySyncAccount() const {
+  CoreAccountId primary_account_id =
+      identity_manager_->GetPrimaryAccountId(signin::ConsentLevel::kSync);
+  if (primary_account_id.empty())
+    return false;
+
+  return !identity_manager_->HasAccountWithRefreshTokenInPersistentErrorState(
+      primary_account_id);
+}
+
+}  // namespace signin::test
diff --git a/chrome/browser/signin/e2e_tests/sign_in_test_observer.h b/chrome/browser/signin/e2e_tests/sign_in_test_observer.h
new file mode 100644
index 0000000..37df5420
--- /dev/null
+++ b/chrome/browser/signin/e2e_tests/sign_in_test_observer.h
@@ -0,0 +1,65 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SIGNIN_E2E_TESTS_SIGN_IN_TEST_OBSERVER_H_
+#define CHROME_BROWSER_SIGNIN_E2E_TESTS_SIGN_IN_TEST_OBSERVER_H_
+
+#include "base/run_loop.h"
+#include "components/signin/core/browser/account_reconcilor.h"
+#include "components/signin/public/identity_manager/identity_manager.h"
+
+namespace signin::test {
+enum class PrimarySyncAccountWait { kWaitForAdded, kWaitForCleared, kNotWait };
+
+// Observes various sign-in events and allows to wait for a specific state of
+// signed-in accounts.
+class SignInTestObserver : public IdentityManager::Observer,
+                           public AccountReconcilor::Observer {
+ public:
+  explicit SignInTestObserver(IdentityManager* identity_manager,
+                              AccountReconcilor* reconcilor);
+  ~SignInTestObserver() override;
+
+  // IdentityManager::Observer:
+  void OnPrimaryAccountChanged(const PrimaryAccountChangeEvent& event) override;
+  void OnRefreshTokenUpdatedForAccount(const CoreAccountInfo&) override;
+  void OnRefreshTokenRemovedForAccount(const CoreAccountId&) override;
+  void OnErrorStateOfRefreshTokenUpdatedForAccount(
+      const CoreAccountInfo&,
+      const GoogleServiceAuthError&) override;
+  void OnAccountsInCookieUpdated(const AccountsInCookieJarInfo&,
+                                 const GoogleServiceAuthError&) override;
+
+  // AccountReconcilor::Observer:
+  // TODO(https://crbug.com/1051864): Remove this observer method once the bug
+  // is fixed.
+  void OnStateChanged(signin_metrics::AccountReconcilorState state) override;
+
+  void WaitForAccountChanges(int signed_in_accounts,
+                             PrimarySyncAccountWait primary_sync_account_wait);
+
+ private:
+  void QuitIfConditionIsSatisfied();
+
+  int CountAccountsWithValidRefreshToken() const;
+  int CountSignedInAccountsInCookie() const;
+  bool HasValidPrimarySyncAccount() const;
+
+  const raw_ptr<signin::IdentityManager> identity_manager_;
+  const raw_ptr<AccountReconcilor> reconcilor_;
+  base::ScopedObservation<IdentityManager, IdentityManager::Observer>
+      identity_manager_observation_{this};
+  base::ScopedObservation<AccountReconcilor, AccountReconcilor::Observer>
+      account_reconcilor_observation_{this};
+  base::RunLoop run_loop_;
+
+  bool are_expectations_set = false;
+  int expected_signed_in_accounts_ = 0;
+  PrimarySyncAccountWait primary_sync_account_wait_ =
+      PrimarySyncAccountWait::kNotWait;
+};
+
+}  // namespace signin::test
+
+#endif  // CHROME_BROWSER_SIGNIN_E2E_TESTS_SIGN_IN_TEST_OBSERVER_H_
diff --git a/chrome/browser/signin/e2e_tests/signin_util.cc b/chrome/browser/signin/e2e_tests/signin_util.cc
new file mode 100644
index 0000000..834b2d4
--- /dev/null
+++ b/chrome/browser/signin/e2e_tests/signin_util.cc
@@ -0,0 +1,117 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/signin/e2e_tests/signin_util.h"
+#include "chrome/browser/signin/e2e_tests/sign_in_test_observer.h"
+
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/signin/account_reconcilor_factory.h"
+#include "chrome/browser/signin/e2e_tests/live_test.h"
+#include "chrome/browser/signin/e2e_tests/test_accounts_util.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
+#include "chrome/browser/sync/sync_service_factory.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/webui/signin/login_ui_test_utils.h"
+#include "chrome/browser/ui/webui/signin/signin_email_confirmation_dialog.h"
+#include "components/signin/core/browser/account_reconcilor.h"
+#include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h"
+#include "components/signin/public/identity_manager/identity_manager.h"
+#include "components/sync/driver/sync_service.h"
+#include "content/public/test/browser_test.h"
+#include "google_apis/gaia/gaia_urls.h"
+
+namespace signin::test {
+
+signin::IdentityManager* identity_manager(Browser* browser) {
+  return IdentityManagerFactory::GetForProfile(browser->profile());
+}
+
+syncer::SyncService* sync_service(Browser* browser) {
+  return SyncServiceFactory::GetForProfile(browser->profile());
+}
+
+AccountReconcilor* account_reconcilor(Browser* browser) {
+  return AccountReconcilorFactory::GetForProfile(browser->profile());
+}
+
+SignInFunctions::SignInFunctions(
+    const base::RepeatingCallback<Browser*()> browser,
+    const base::RepeatingCallback<bool(int, const GURL&, ui::PageTransition)>
+        add_tab_function)
+    : browser_(browser), add_tab_function_(add_tab_function) {}
+
+SignInFunctions::~SignInFunctions() = default;
+
+void SignInFunctions::SignInFromWeb(const TestAccount& test_account,
+                                    int previously_signed_in_accounts) {
+  ASSERT_TRUE(add_tab_function_.Run(0,
+                                    GaiaUrls::GetInstance()->add_account_url(),
+                                    ui::PageTransition::PAGE_TRANSITION_TYPED));
+  SignInFromCurrentPage(test_account, previously_signed_in_accounts);
+}
+
+void SignInFunctions::SignInFromSettings(const TestAccount& test_account,
+                                         int previously_signed_in_accounts) {
+  GURL settings_url("chrome://settings");
+  ASSERT_TRUE(add_tab_function_.Run(0, settings_url,
+                                    ui::PageTransition::PAGE_TRANSITION_TYPED));
+  auto* settings_tab =
+      browser_.Run()->tab_strip_model()->GetActiveWebContents();
+  EXPECT_TRUE(content::ExecuteScript(
+      settings_tab,
+      base::StringPrintf(
+          kSettingsScriptWrapperFormat,
+          "settings.SyncBrowserProxyImpl.getInstance().startSignIn();")));
+  SignInFromCurrentPage(test_account, previously_signed_in_accounts);
+}
+
+void SignInFunctions::SignInFromCurrentPage(const TestAccount& test_account,
+                                            int previously_signed_in_accounts) {
+  SignInTestObserver observer(identity_manager(browser_.Run()),
+                              account_reconcilor(browser_.Run()));
+  login_ui_test_utils::ExecuteJsToSigninInSigninFrame(
+      browser_.Run(), test_account.user, test_account.password);
+  observer.WaitForAccountChanges(previously_signed_in_accounts + 1,
+                                 PrimarySyncAccountWait::kNotWait);
+}
+
+void SignInFunctions::TurnOnSync(const TestAccount& test_account,
+                                 int previously_signed_in_accounts) {
+  SignInFromSettings(test_account, previously_signed_in_accounts);
+
+  SignInTestObserver observer(identity_manager(browser_.Run()),
+                              account_reconcilor(browser_.Run()));
+  EXPECT_TRUE(login_ui_test_utils::ConfirmSyncConfirmationDialog(
+      browser_.Run(), kDialogTimeout));
+  observer.WaitForAccountChanges(previously_signed_in_accounts + 1,
+                                 PrimarySyncAccountWait::kWaitForAdded);
+}
+
+void SignInFunctions::SignOutFromWeb() {
+  SignInTestObserver observer(identity_manager(browser_.Run()),
+                              account_reconcilor(browser_.Run()));
+  ASSERT_TRUE(
+      add_tab_function_.Run(0, GaiaUrls::GetInstance()->service_logout_url(),
+                            ui::PageTransition::PAGE_TRANSITION_TYPED));
+  observer.WaitForAccountChanges(0, PrimarySyncAccountWait::kNotWait);
+}
+
+void SignInFunctions::TurnOffSync() {
+  GURL settings_url("chrome://settings");
+  ASSERT_TRUE(add_tab_function_.Run(0, settings_url,
+                                    ui::PageTransition::PAGE_TRANSITION_TYPED));
+  SignInTestObserver observer(identity_manager(browser_.Run()),
+                              account_reconcilor(browser_.Run()));
+  auto* settings_tab =
+      browser_.Run()->tab_strip_model()->GetActiveWebContents();
+  EXPECT_TRUE(content::ExecuteScript(
+      settings_tab,
+      base::StringPrintf(
+          kSettingsScriptWrapperFormat,
+          "settings.SyncBrowserProxyImpl.getInstance().signOut(false)")));
+  observer.WaitForAccountChanges(0, PrimarySyncAccountWait::kWaitForCleared);
+}
+
+}  // namespace signin::test
diff --git a/chrome/browser/signin/e2e_tests/signin_util.h b/chrome/browser/signin/e2e_tests/signin_util.h
new file mode 100644
index 0000000..57aead8
--- /dev/null
+++ b/chrome/browser/signin/e2e_tests/signin_util.h
@@ -0,0 +1,63 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SIGNIN_E2E_TESTS_SIGNIN_UTIL_H_
+#define CHROME_BROWSER_SIGNIN_E2E_TESTS_SIGNIN_UTIL_H_
+
+#include "base/time/time.h"
+#include "chrome/browser/signin/e2e_tests/test_accounts_util.h"
+#include "chrome/browser/ui/browser.h"
+#include "components/signin/core/browser/account_reconcilor.h"
+#include "components/signin/public/identity_manager/identity_manager.h"
+#include "components/sync/driver/sync_service.h"
+
+namespace signin::test {
+
+const base::TimeDelta kDialogTimeout = base::Seconds(10);
+
+// A wrapper importing the settings module when the chrome://settings serve the
+// Polymer 3 version.
+const char kSettingsScriptWrapperFormat[] =
+    "import('./settings.js').then(settings => {%s});";
+
+signin::IdentityManager* identity_manager(Browser* browser);
+
+syncer::SyncService* sync_service(Browser* browser);
+
+AccountReconcilor* account_reconcilor(Browser* browser);
+
+class SignInFunctions {
+ public:
+  explicit SignInFunctions(
+      const base::RepeatingCallback<Browser*()> browser,
+      const base::RepeatingCallback<bool(int, const GURL&, ui::PageTransition)>
+          add_tab_function);
+
+  ~SignInFunctions();
+
+  void SignInFromWeb(const TestAccount& test_account,
+                     int previously_signed_in_accounts);
+
+  void SignInFromSettings(const TestAccount& test_account,
+                          int previously_signed_in_accounts);
+
+  void SignInFromCurrentPage(const TestAccount& test_account,
+                             int previously_signed_in_accounts);
+
+  void TurnOnSync(const TestAccount& test_account,
+                  int previously_signed_in_accounts);
+
+  void SignOutFromWeb();
+
+  void TurnOffSync();
+
+ private:
+  const base::RepeatingCallback<Browser*()> browser_;
+  const base::RepeatingCallback<bool(int, const GURL&, ui::PageTransition)>
+      add_tab_function_;
+};
+
+}  // namespace signin::test
+
+#endif  // CHROME_BROWSER_SIGNIN_E2E_TESTS_SIGNIN_UTIL_H_
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/carousel/BaseCarouselSuggestionView.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/carousel/BaseCarouselSuggestionView.java
index 09495b32..741c25a 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/carousel/BaseCarouselSuggestionView.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/carousel/BaseCarouselSuggestionView.java
@@ -155,6 +155,9 @@
      * @param recycledViewPool the recycled view pool to assign to the recycler view.
      */
     void setCarouselRecycledViewPool(RecycledViewPool recycledViewPool) {
-        mRecyclerView.setRecycledViewPool(recycledViewPool);
+        // TODO(rongtan): Investigate why null assignment causes crashes in Recycler View.
+        if (recycledViewPool != null) {
+            mRecyclerView.setRecycledViewPool(recycledViewPool);
+        }
     }
 }
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
index 3b42a06..3c7876df 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
+++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -3261,9 +3261,6 @@
       <message name="IDS_NTP_MANAGE_FEED" desc="Menu item to manage feed settings from the feed header overflow menu.">
         Manage
       </message>
-      <message name="IDS_CORMORANT_CREATOR_ACTIVITY" desc="Menu item to launch the Cormorant creator activity. This is used only for testing." translateable="false">
-        Creator Profile
-      </message>
       <message name="IDS_CORMORANT_CREATOR_OFFLINE_ERROR_TITLE" desc="Creator page error title when the user is offline.">
         You're offline
       </message>
diff --git a/chrome/browser/ui/app_list/search/omnibox/omnibox_lacros_provider.cc b/chrome/browser/ui/app_list/search/omnibox/omnibox_lacros_provider.cc
index 1222dc8..000381b 100644
--- a/chrome/browser/ui/app_list/search/omnibox/omnibox_lacros_provider.cc
+++ b/chrome/browser/ui/app_list/search/omnibox/omnibox_lacros_provider.cc
@@ -4,8 +4,6 @@
 
 #include "chrome/browser/ui/app_list/search/omnibox/omnibox_lacros_provider.h"
 
-#include "ash/public/cpp/app_list/app_list_features.h"
-#include "base/bind.h"
 #include "chrome/browser/ash/crosapi/crosapi_ash.h"
 #include "chrome/browser/ash/crosapi/crosapi_manager.h"
 #include "chrome/browser/ash/crosapi/search_provider_ash.h"
@@ -34,24 +32,6 @@
 using ::ash::string_matching::TokenizedString;
 using CrosApiSearchResult = ::crosapi::mojom::SearchResult;
 
-// Some answer result types overtrigger on short queries. Returns true if an
-// answer should be filtered.
-bool ShouldFilterAnswer(const crosapi::mojom::SearchResultPtr& search_result,
-                        const std::u16string& query) {
-  // TODO(crbug.com/1258415): Move this to the filtering ranker once more
-  // detailed result subtype info is exposed by ChromeSearchResult.
-  if (query.size() >= kMinQueryLengthForCommonAnswers)
-    return false;
-
-  switch (search_result->answer_type) {
-    case CrosApiSearchResult::AnswerType::kDictionary:
-    case CrosApiSearchResult::AnswerType::kTranslation:
-      return true;
-    default:
-      return false;
-  }
-}
-
 }  // namespace
 
 OmniboxLacrosProvider::OmniboxLacrosProvider(
@@ -132,7 +112,7 @@
       // Omnibox result.
       list_results.emplace_back(std::make_unique<OmniboxResult>(
           profile_, list_controller_, std::move(search_result), last_query_));
-    } else if (!ShouldFilterAnswer(search_result, last_query_)) {
+    } else {
       // Answer result.
       new_results.emplace_back(std::make_unique<OmniboxAnswerResult>(
           profile_, list_controller_, std::move(search_result), last_query_));
diff --git a/chrome/browser/ui/app_list/search/omnibox/omnibox_lacros_provider_unittest.cc b/chrome/browser/ui/app_list/search/omnibox/omnibox_lacros_provider_unittest.cc
index a67b0e9..607e6501 100644
--- a/chrome/browser/ui/app_list/search/omnibox/omnibox_lacros_provider_unittest.cc
+++ b/chrome/browser/ui/app_list/search/omnibox/omnibox_lacros_provider_unittest.cc
@@ -332,31 +332,4 @@
             search_controller_->last_results()[1]->id());
 }
 
-// Test that answers of certain kinds (that tend to over-trigger) aren't shown
-// on very short queries.
-TEST_F(OmniboxLacrosProviderTest, ShortQuery) {
-  // Start with a query that is one character too short.
-  StartSearch(std::u16string(kMinQueryLengthForCommonAnswers - 1, 'a'));
-
-  // All results except dictionary and translate answers are allowed.
-  std::vector<cam::SearchResultPtr> to_produce;
-  to_produce.emplace_back(NewOmniboxResult("https://nonanswer.com/"));
-  to_produce.emplace_back(NewAnswerResult(
-      "https://finance.com/", cam::SearchResult::AnswerType::kFinance));
-  to_produce.emplace_back(NewOpenTabResult("https://opentab.com/"));
-  to_produce.emplace_back(NewAnswerResult(
-      "https://translation.com/", cam::SearchResult::AnswerType::kTranslation));
-  to_produce.emplace_back(NewAnswerResult(
-      "https://dictionary.com/", cam::SearchResult::AnswerType::kDictionary));
-  ProduceResults(std::move(to_produce));
-
-  ASSERT_EQ(3u, search_controller_->last_results().size());
-  EXPECT_EQ("omnibox_answer://https://finance.com/",
-            search_controller_->last_results()[0]->id());
-  EXPECT_EQ("opentab://https://opentab.com/",
-            search_controller_->last_results()[1]->id());
-  EXPECT_EQ("https://nonanswer.com/",
-            search_controller_->last_results()[2]->id());
-}
-
 }  // namespace app_list::test
diff --git a/chrome/browser/ui/app_list/search/omnibox/omnibox_provider.cc b/chrome/browser/ui/app_list/search/omnibox/omnibox_provider.cc
index 9bb7904..ae3f355 100644
--- a/chrome/browser/ui/app_list/search/omnibox/omnibox_provider.cc
+++ b/chrome/browser/ui/app_list/search/omnibox/omnibox_provider.cc
@@ -8,11 +8,6 @@
 #include <string>
 #include <utility>
 
-#include "ash/constants/ash_features.h"
-#include "ash/public/cpp/app_list/app_list_features.h"
-#include "base/bind.h"
-#include "base/callback_forward.h"
-#include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "chrome/browser/autocomplete/chrome_autocomplete_provider_client.h"
 #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h"
@@ -21,14 +16,11 @@
 #include "chrome/browser/favicon/favicon_service_factory.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
-#include "chrome/browser/ui/app_list/search/common/types_util.h"
 #include "chrome/browser/ui/app_list/search/omnibox/omnibox_answer_result.h"
 #include "chrome/browser/ui/app_list/search/omnibox/omnibox_result.h"
 #include "chrome/browser/ui/app_list/search/omnibox/omnibox_util.h"
 #include "chrome/browser/ui/app_list/search/omnibox/open_tab_result.h"
-#include "chrome/browser/ui/app_list/search/ranking/util.h"
 #include "components/favicon/core/favicon_service.h"
 #include "components/omnibox/browser/autocomplete_classifier.h"
 #include "components/omnibox/browser/autocomplete_input.h"
@@ -48,25 +40,6 @@
          match.type == AutocompleteMatchType::CALCULATOR;
 }
 
-// Some answer result types overtrigger on short queries. Returns true if an
-// answer should be filtered.
-bool ShouldFilterAnswer(const AutocompleteMatch& match,
-                        const std::u16string& query) {
-  // TODO(crbug.com/1258415): Move this to the filtering ranker once more
-  // detailed result subtype info is exposed by ChromeSearchResult.
-  if (query.size() >= kMinQueryLengthForCommonAnswers || !match.answer) {
-    return false;
-  }
-
-  switch (match.answer.value().type()) {
-    case SuggestionAnswer::ANSWER_TYPE_DICTIONARY:
-    case SuggestionAnswer::ANSWER_TYPE_TRANSLATION:
-      return true;
-    default:
-      return false;
-  }
-}
-
 int ProviderTypes() {
   // We use all the default providers except for the document provider, which
   // suggests Drive files on enterprise devices. This is disabled to avoid
@@ -162,7 +135,7 @@
               match, controller_.get(), &favicon_cache_,
               BookmarkModelFactory::GetForBrowserContext(profile_), input_),
           last_query_));
-    } else if (!ShouldFilterAnswer(match, last_query_)) {
+    } else {
       new_results.emplace_back(std::make_unique<OmniboxAnswerResult>(
           profile_, list_controller_,
           crosapi::CreateAnswerResult(match, controller_.get(), last_query_,
diff --git a/chrome/browser/ui/app_list/search/omnibox/omnibox_provider_unittest.cc b/chrome/browser/ui/app_list/search/omnibox/omnibox_provider_unittest.cc
index 699a6bef..c04253b 100644
--- a/chrome/browser/ui/app_list/search/omnibox/omnibox_provider_unittest.cc
+++ b/chrome/browser/ui/app_list/search/omnibox/omnibox_provider_unittest.cc
@@ -8,10 +8,8 @@
 #include <string>
 #include <vector>
 
-#include "ash/constants/ash_features.h"
 #include "base/run_loop.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
-#include "chrome/browser/ui/app_list/search/omnibox/omnibox_util.h"
 #include "chrome/browser/ui/app_list/search/search_controller.h"
 #include "chrome/browser/ui/app_list/search/test/test_search_controller.h"
 #include "chrome/browser/ui/app_list/test/test_app_list_controller_delegate.h"
@@ -291,37 +289,4 @@
             search_controller_->last_results()[1]->id());
 }
 
-// Test that answers of certain kinds (that tend to over-trigger) aren't shown
-// on very short queries.
-TEST_F(OmniboxProviderTest, ShortQuery) {
-  // Start with a query that is one character too short.
-  StartSearch(std::u16string(kMinQueryLengthForCommonAnswers - 1, 'a'));
-
-  // All results except dictionary and translate answers are allowed.
-  std::vector<AutocompleteMatch> to_produce;
-  AutocompleteResult result;
-
-  to_produce.emplace_back(NewOmniboxResult("https://nonanswer.com/"));
-  to_produce.emplace_back(
-      NewAnswerResult("https://finance.com/",
-                      SuggestionAnswer::AnswerType::ANSWER_TYPE_FINANCE));
-  to_produce.emplace_back(NewOpenTabResult("https://opentab.com/"));
-  to_produce.emplace_back(
-      NewAnswerResult("https://translation.com/",
-                      SuggestionAnswer::AnswerType::ANSWER_TYPE_TRANSLATION));
-  to_produce.emplace_back(
-      NewAnswerResult("https://dictionary.com/",
-                      SuggestionAnswer::AnswerType::ANSWER_TYPE_DICTIONARY));
-  result.AppendMatches(to_produce);
-  ProduceResults(std::move(result));
-
-  ASSERT_EQ(3u, search_controller_->last_results().size());
-  EXPECT_EQ("omnibox_answer://https://finance.com/",
-            search_controller_->last_results()[0]->id());
-  EXPECT_EQ("opentab://https://opentab.com/",
-            search_controller_->last_results()[1]->id());
-  EXPECT_EQ("https://nonanswer.com/",
-            search_controller_->last_results()[2]->id());
-}
-
 }  // namespace app_list::test
diff --git a/chrome/browser/ui/app_list/search/ranking/filtering_ranker.cc b/chrome/browser/ui/app_list/search/ranking/filtering_ranker.cc
index 34b048b..534ff350 100644
--- a/chrome/browser/ui/app_list/search/ranking/filtering_ranker.cc
+++ b/chrome/browser/ui/app_list/search/ranking/filtering_ranker.cc
@@ -6,17 +6,16 @@
 
 #include "ash/public/cpp/app_list/app_list_config.h"
 #include "base/containers/flat_set.h"
-#include "base/strings/strcat.h"
-#include "base/strings/string_number_conversions.h"
-#include "chrome/browser/ash/profiles/profile_helper.h"
-#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/search/chrome_search_result.h"
+#include "chrome/browser/ui/app_list/search/omnibox/omnibox_util.h"
 #include "chrome/browser/ui/app_list/search/ranking/constants.h"
-#include "chrome/browser/ui/app_list/search/ranking/util.h"
+#include "chromeos/crosapi/mojom/launcher_search.mojom.h"
 
 namespace app_list {
 namespace {
 
+using CrosApiSearchResult = ::crosapi::mojom::SearchResult;
+
 // Given `higher_priority` and `lower_priority` result types, deduplicate
 // results between the two result types in `results` based on their id,
 // preserving the ones in `higher_priority`.
@@ -67,13 +66,31 @@
   }
 }
 
-void FilterOmniboxResults(ResultsMap& results) {
+void FilterOmniboxResults(ResultsMap& results, const std::u16string& query) {
   // We currently only filter omnibox results. So if we don't have any yet,
   // early exit.
   const auto it = results.find(ProviderType::kOmnibox);
   if (it == results.end())
     return;
 
+  auto& omnibox_results = results[ProviderType::kOmnibox];
+
+  // Some answer result types overtrigger on short queries, so these will be
+  // filtered out be default.
+  if (query.size() <= kMinQueryLengthForCommonAnswers) {
+    for (const auto& omnibox_result : omnibox_results) {
+      auto& scoring = omnibox_result->scoring();
+      bool is_type_dictionary_or_translation =
+          omnibox_result->answer_type() ==
+              CrosApiSearchResult::AnswerType::kDictionary ||
+          omnibox_result->answer_type() ==
+              CrosApiSearchResult::AnswerType::kTranslation;
+      if (omnibox_result->display_type() == DisplayType::kAnswerCard &&
+          is_type_dictionary_or_translation)
+        scoring.filter = true;
+    }
+  }
+
   // Compute the total number of results. If we have fewer than can fit in the
   // UI, early exit.
   static const int max_search_results =
@@ -85,26 +102,26 @@
     return;
 
   // Sort the list of omnibox results best-to-worst.
-  auto& omnibox_results = results[ProviderType::kOmnibox];
   std::sort(omnibox_results.begin(), omnibox_results.end(),
             [](const auto& a, const auto& b) {
               return a->relevance() > b->relevance();
             });
 
-  // Filter all results after the |kMaxOmniboxResults|th one out of the UI, but
-  // never remove best matches.
+  // Filter all results after the |kMaxOmniboxResults|th one out of the UI,
+  // but never remove best matches  or answer cards.
   for (size_t i = kMaxOmniboxResults; i < omnibox_results.size(); ++i) {
     auto& scoring = omnibox_results[i]->scoring();
-    if (scoring.best_match_rank == -1)
+    if (scoring.best_match_rank == -1 &&
+        omnibox_results[i]->display_type() != DisplayType::kAnswerCard)
       scoring.filter = true;
   }
 }
 
 }  //  namespace
 
-FilteringRanker::FilteringRanker() {}
+FilteringRanker::FilteringRanker() = default;
 
-FilteringRanker::~FilteringRanker() {}
+FilteringRanker::~FilteringRanker() = default;
 
 void FilteringRanker::Start(const std::u16string& query,
                             ResultsMap& results,
@@ -117,7 +134,7 @@
   // Do not filter for zero-state.
   if (last_query_.empty())
     return;
-  FilterOmniboxResults(results);
+  FilterOmniboxResults(results, last_query_);
   DeduplicateDriveFilesAndTabs(results);
   // TODO(crbug.com/1305880): Verify that game URLs match the omnibox stripped
   // URL once game URLs are finalized.
diff --git a/chrome/browser/ui/app_list/search/ranking/filtering_ranker_unittest.cc b/chrome/browser/ui/app_list/search/ranking/filtering_ranker_unittest.cc
index 5b19503..bf86f89 100644
--- a/chrome/browser/ui/app_list/search/ranking/filtering_ranker_unittest.cc
+++ b/chrome/browser/ui/app_list/search/ranking/filtering_ranker_unittest.cc
@@ -5,10 +5,12 @@
 #include "chrome/browser/ui/app_list/search/ranking/filtering_ranker.h"
 
 #include "chrome/browser/ui/app_list/search/chrome_search_result.h"
+#include "chrome/browser/ui/app_list/search/omnibox/omnibox_util.h"
 #include "chrome/browser/ui/app_list/search/search_controller.h"
-#include "chrome/browser/ui/app_list/search/test/ranking_test_util.h"
 #include "chrome/browser/ui/app_list/search/test/test_result.h"
 #include "chrome/browser/ui/app_list/search/types.h"
+#include "chromeos/crosapi/mojom/launcher_search.mojom-forward.h"
+#include "chromeos/crosapi/mojom/launcher_search.mojom.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -18,6 +20,7 @@
 
 using testing::UnorderedElementsAre;
 using testing::UnorderedElementsAreArray;
+using AnswerType = ::crosapi::mojom::SearchResult::AnswerType;
 
 class TestDriveIdResult : public TestResult {
  public:
@@ -26,7 +29,7 @@
                     const absl::optional<std::string>& drive_id)
       : TestResult(id, type), drive_id_(drive_id) {}
 
-  ~TestDriveIdResult() override {}
+  ~TestDriveIdResult() override = default;
 
   // ChromeSearchResult:
   void Open(int event_flags) override {}
@@ -52,6 +55,20 @@
   return res;
 }
 
+Results MakeOmniboxResults(const std::vector<std::string>& ids,
+                           const std::vector<ResultType>& types,
+                           const std::vector<AnswerType>& answer_types) {
+  CHECK_EQ(ids.size(), types.size());
+  CHECK_EQ(ids.size(), answer_types.size());
+
+  Results res;
+  for (size_t i = 0; i < ids.size(); ++i) {
+    res.push_back(std::make_unique<TestResult>(
+        ids[i], types[i], answer_types[i], DisplayType::kAnswerCard));
+  }
+  return res;
+}
+
 }  // namespace
 
 class FilteringRankerTest : public testing::Test {};
@@ -80,4 +97,32 @@
   EXPECT_FALSE(results[drive][4]->scoring().filter);
 }
 
+// Test that answers of certain kinds (that tend to over-trigger) aren't shown
+// on very short queries.
+TEST_F(FilteringRankerTest, FilterOmniboxResults) {
+  auto web = ResultType::kOmnibox;
+  auto tab = ResultType::kOpenTab;
+  ResultsMap results;
+
+  results[web] = MakeOmniboxResults(
+      {"a", "b", "c", "d", "e"}, {web, web, tab, web, web},
+      {AnswerType::kFinance, AnswerType::kTranslation, AnswerType::kUnset,
+       AnswerType::kDictionary, AnswerType::kCalculator});
+
+  FilteringRanker ranker;
+  CategoriesList categories;
+
+  // Start with a query that is one character too short.
+  ranker.Start(std::u16string(kMinQueryLengthForCommonAnswers - 1, 'a'),
+               results, categories);
+  ranker.UpdateResultRanks(results, ProviderType::kOmnibox);
+
+  // All results except dictionary and translate answers are allowed.
+  EXPECT_FALSE(results[web][0]->scoring().filter);
+  EXPECT_TRUE(results[web][1]->scoring().filter);
+  EXPECT_FALSE(results[web][2]->scoring().filter);
+  EXPECT_TRUE(results[web][3]->scoring().filter);
+  EXPECT_FALSE(results[web][4]->scoring().filter);
+}
+
 }  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/test/test_result.cc b/chrome/browser/ui/app_list/search/test/test_result.cc
index 90f15f0..933f3ca8 100644
--- a/chrome/browser/ui/app_list/search/test/test_result.cc
+++ b/chrome/browser/ui/app_list/search/test/test_result.cc
@@ -47,6 +47,17 @@
   scoring().ftrl_result_score = ftrl_result_score;
 }
 
+TestResult::TestResult(const std::string& id,
+                       ResultType result_type,
+                       crosapi::mojom::SearchResult::AnswerType answer_type,
+                       DisplayType display_type) {
+  set_id(id);
+  SetTitle(base::UTF8ToUTF16(id));
+  SetResultType(result_type);
+  set_answer_type(answer_type);
+  SetDisplayType(display_type);
+}
+
 TestResult::~TestResult() = default;
 
 }  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/test/test_result.h b/chrome/browser/ui/app_list/search/test/test_result.h
index 1805046..7018134 100644
--- a/chrome/browser/ui/app_list/search/test/test_result.h
+++ b/chrome/browser/ui/app_list/search/test/test_result.h
@@ -38,6 +38,11 @@
              double relevance,
              double ftrl_result_score);
 
+  TestResult(const std::string& id,
+             ResultType result_type,
+             crosapi::mojom::SearchResult::AnswerType answer_type,
+             DisplayType display_type);
+
   ~TestResult() override;
 
   // ChromeSearchResult overrides:
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.cc b/chrome/browser/ui/ash/chrome_shell_delegate.cc
index 1673b92..f159f42 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.cc
@@ -13,7 +13,6 @@
 #include "ash/public/cpp/assistant/assistant_state.h"
 #include "ash/public/cpp/new_window_delegate.h"
 #include "ash/public/cpp/system_sounds_delegate.h"
-#include "ash/system/video_conference/video_conference_tray_controller.h"
 #include "base/bind.h"
 #include "base/check.h"
 #include "base/command_line.h"
@@ -152,11 +151,6 @@
   return std::make_unique<SystemSoundsDelegateImpl>();
 }
 
-std::unique_ptr<ash::VideoConferenceTrayController>
-ChromeShellDelegate::CreateVideoConferenceTrayController() const {
-  return std::make_unique<ash::VideoConferenceTrayController>();
-}
-
 scoped_refptr<network::SharedURLLoaderFactory>
 ChromeShellDelegate::GetGeolocationUrlLoaderFactory() const {
   return g_browser_process->shared_url_loader_factory();
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.h b/chrome/browser/ui/ash/chrome_shell_delegate.h
index 7271f8b..1d7df86 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.h
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.h
@@ -37,8 +37,6 @@
       const override;
   std::unique_ptr<ash::SystemSoundsDelegate> CreateSystemSoundsDelegate()
       const override;
-  std::unique_ptr<ash::VideoConferenceTrayController>
-  CreateVideoConferenceTrayController() const override;
   scoped_refptr<network::SharedURLLoaderFactory>
   GetGeolocationUrlLoaderFactory() const override;
   void OpenKeyboardShortcutHelpPage() const override;
diff --git a/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_arc_tracker.cc b/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_arc_tracker.cc
index 8a647d1e..1f95f5b0 100644
--- a/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_arc_tracker.cc
+++ b/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_arc_tracker.cc
@@ -705,9 +705,9 @@
   // some cases, the task has beend created but window property in aura window
   // haven't been updated and still kept "session_id". In this case, if the
   // session's task created, just return the latest task info.
-  if (session_id_to_task_id_map_.contains(*session_id)) {
+  if (base::Contains(session_id_to_task_id_map_, *session_id)) {
     auto mapped_task_id = session_id_to_task_id_map_[*session_id];
-    if (task_id_to_arc_app_window_info_.contains(mapped_task_id))
+    if (base::Contains(task_id_to_arc_app_window_info_, mapped_task_id))
       return task_id_to_arc_app_window_info_[mapped_task_id].get();
   }
 
diff --git a/chrome/browser/ui/ash/test_wallpaper_controller.cc b/chrome/browser/ui/ash/test_wallpaper_controller.cc
index 79ec5f9..c053842 100644
--- a/chrome/browser/ui/ash/test_wallpaper_controller.cc
+++ b/chrome/browser/ui/ash/test_wallpaper_controller.cc
@@ -81,10 +81,6 @@
     const ash::GooglePhotosWallpaperParams& params,
     SetWallpaperCallback callback) {
   ++set_google_photos_wallpaper_count_;
-  if (!ash::features::IsWallpaperGooglePhotosIntegrationEnabled()) {
-    std::move(callback).Run(/*success=*/false);
-    return;
-  }
   wallpaper_info_ = ash::WallpaperInfo(params);
   std::move(callback).Run(/*success=*/true);
 }
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index e801640..7cbabbcd 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -76,7 +76,6 @@
 #include "chrome/browser/profiles/profiles_state.h"
 #include "chrome/browser/repost_form_warning_controller.h"
 #include "chrome/browser/resource_coordinator/tab_load_tracker.h"
-#include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/sessions/app_session_service.h"
 #include "chrome/browser/sessions/app_session_service_factory.h"
diff --git a/chrome/browser/ui/browser_navigator.cc b/chrome/browser/ui/browser_navigator.cc
index cb56154..1c50c53 100644
--- a/chrome/browser/ui/browser_navigator.cc
+++ b/chrome/browser/ui/browser_navigator.cc
@@ -314,6 +314,7 @@
                   ->GetPictureInPictureInitialAspectRatio();
           browser_params.lock_aspect_ratio =
               params.contents_to_insert->GetPictureInPictureLockAspectRatio();
+          browser_params.omit_from_session_restore = true;
         }
 
         return {Browser::Create(browser_params), -1};
diff --git a/chrome/browser/ui/content_settings/content_setting_image_model.cc b/chrome/browser/ui/content_settings/content_setting_image_model.cc
index e9469fd..7da35bb 100644
--- a/chrome/browser/ui/content_settings/content_setting_image_model.cc
+++ b/chrome/browser/ui/content_settings/content_setting_image_model.cc
@@ -9,7 +9,6 @@
 
 #include "base/feature_list.h"
 #include "base/metrics/field_trial_params.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
 #include "build/build_config.h"
@@ -1086,9 +1085,6 @@
     ContentSettingBubbleModel::Delegate* delegate,
     content::WebContents* web_contents) {
   DCHECK(web_contents);
-  UMA_HISTOGRAM_ENUMERATION(
-      "ContentSettings.ImagePressed", image_type(),
-      ContentSettingImageModel::ImageType::NUM_IMAGE_TYPES);
   return CreateBubbleModelImpl(delegate, web_contents);
 }
 
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
index d0d7ead..6f80da0 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
@@ -367,8 +367,11 @@
   started_fullscreen_transition_ = false;
   if (IsTabFullscreen()) {
     DCHECK(exclusive_access_tab());
+#if !BUILDFLAG(IS_CHROMEOS_LACROS)
+    // TODO(crbug.com/1385866): This is flaky on ChromeOS Lacros browser tests.
     DCHECK_EQ(tab_fullscreen_target_display_id_,
               GetDisplayId(*exclusive_access_tab()));
+#endif
   }
   tab_fullscreen_target_display_id_ = display::kInvalidDisplayId;
 }
diff --git a/chrome/browser/ui/intent_picker_tab_helper.cc b/chrome/browser/ui/intent_picker_tab_helper.cc
index d2c22d7..152b1f74 100644
--- a/chrome/browser/ui/intent_picker_tab_helper.cc
+++ b/chrome/browser/ui/intent_picker_tab_helper.cc
@@ -311,7 +311,10 @@
   if (!web_contents()) {
     return;
   }
+
   if (IsNavigatingToNewSite(navigation_handle)) {
+    ++commit_count_;
+
     bool is_valid_page = navigation_handle->GetURL().SchemeIsHTTPOrHTTPS() &&
                          !navigation_handle->IsErrorPage();
     if (is_valid_page) {
diff --git a/chrome/browser/ui/intent_picker_tab_helper.h b/chrome/browser/ui/intent_picker_tab_helper.h
index b294de1..771fe85 100644
--- a/chrome/browser/ui/intent_picker_tab_helper.h
+++ b/chrome/browser/ui/intent_picker_tab_helper.h
@@ -62,6 +62,8 @@
                            std::vector<apps::IntentPickerAppInfo> apps,
                            IntentPickerIconLoaderCallback callback);
 
+  int commit_count() { return commit_count_; }
+
   // Sets a OnceClosure callback which will be called next time the icon is
   // updated. If include_latest_navigation is true, and the latest navigation
   // was finished, the callback is called immediately.
@@ -111,6 +113,10 @@
   // on this origin.
   bool show_expanded_chip_from_usage_ = false;
 
+  // Tracks the number of commits on this page, to allow for checking to make
+  // sure that asynchronous invocations do not cause a stale intent picker.
+  int commit_count_ = 0;
+
   // Contains the app ID of an app which can be opened through the intent
   // picker. This is only set when ShowIconForApps() is called with a single
   // app. Will be set to the empty string in all other cases (e.g. when there
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos_browsertest.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos_browsertest.cc
index 0ca2499..ead426f0 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos_browsertest.cc
@@ -46,7 +46,6 @@
 #include "base/ranges/algorithm.h"
 #include "base/run_loop.h"
 #include "base/scoped_observation.h"
-#include "base/test/metrics/histogram_tester.h"
 #include "base/test/test_future.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/app/vector_icons/vector_icons.h"
@@ -1057,20 +1056,14 @@
     bool is_geolocation_icon = view == geolocation_icon;
     EXPECT_EQ(is_geolocation_icon, view->GetVisible());
   }
+  EXPECT_FALSE(geolocation_icon->IsBubbleShowing());
 
   // Press the geolocation button.
-  base::HistogramTester histograms;
   geolocation_icon->OnKeyPressed(
       ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_SPACE, ui::EF_NONE));
   geolocation_icon->OnKeyReleased(
       ui::KeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_SPACE, ui::EF_NONE));
-
-  histograms.ExpectBucketCount(
-      "HostedAppFrame.ContentSettings.ImagePressed",
-      static_cast<int>(ContentSettingImageModel::ImageType::GEOLOCATION), 1);
-  histograms.ExpectBucketCount(
-      "ContentSettings.ImagePressed",
-      static_cast<int>(ContentSettingImageModel::ImageType::GEOLOCATION), 1);
+  EXPECT_TRUE(geolocation_icon->IsBubbleShowing());
 }
 
 // Regression test for https://crbug.com/839955
diff --git a/chrome/browser/ui/views/intent_picker_bubble_view_browsertest.cc b/chrome/browser/ui/views/intent_picker_bubble_view_browsertest.cc
index 35cafd9b..033a806 100644
--- a/chrome/browser/ui/views/intent_picker_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/intent_picker_bubble_view_browsertest.cc
@@ -5,12 +5,14 @@
 #include <string>
 
 #include "base/bind.h"
+#include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "chrome/browser/apps/intent_helper/intent_picker_features.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/intent_picker_tab_helper.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/toolbar_button_provider.h"
@@ -41,14 +43,29 @@
     scoped_feature_list_.InitWithFeatures({}, disabled_features);
   }
 
-  void OpenNewTab(const GURL& url) {
+  template <typename Action>
+  void DoAndWaitForIntentPickerIconUpdate(Action action) {
+    base::RunLoop run_loop;
+    auto* tab_helper = IntentPickerTabHelper::FromWebContents(GetWebContents());
+    tab_helper->SetIconUpdateCallbackForTesting(run_loop.QuitClosure());
+    action();
+    run_loop.Run();
+  }
+
+  content::WebContents* OpenNewTab(const GURL& url) {
     chrome::NewTab(browser());
     content::WebContents* web_contents =
         browser()->tab_strip_model()->GetActiveWebContents();
-    NavigateToLaunchingPage(browser());
-    TestTabActionDoesNotOpenAppWindow(
-        url, base::BindOnce(&ClickLinkAndWait, web_contents, url,
-                            LinkTarget::SELF, GetParam()));
+
+    DoAndWaitForIntentPickerIconUpdate(
+        [this] { NavigateToLaunchingPage(browser()); });
+    DoAndWaitForIntentPickerIconUpdate([this, url, web_contents] {
+      TestTabActionDoesNotOpenAppWindow(
+          url, base::BindOnce(&ClickLinkAndWait, web_contents, url,
+                              LinkTarget::SELF, GetParam()));
+    });
+
+    return web_contents;
   }
 
   // Inserts an iframe in the main frame of |web_contents|.
@@ -66,6 +83,10 @@
         ->GetPageActionIconView(PageActionIconType::kIntentPicker);
   }
 
+  content::WebContents* GetWebContents() {
+    return browser()->tab_strip_model()->GetActiveWebContents();
+  }
+
   IntentPickerBubbleView* intent_picker_bubble() {
     return IntentPickerBubbleView::intent_picker_bubble();
   }
@@ -91,7 +112,7 @@
 // Tests that clicking a link from a tabbed browser to outside the scope of an
 // installed app does not show the intent picker.
 IN_PROC_BROWSER_TEST_P(IntentPickerBubbleViewBrowserTest,
-                       NavigationToOutofScopeLinkDoesNotShowIntentPicker) {
+                       NavigationToOutOfScopeLinkDoesNotShowIntentPicker) {
   InstallTestWebApp();
 
   const GURL out_of_scope_url =
@@ -99,9 +120,8 @@
   NavigateToLaunchingPage(browser());
   TestTabActionDoesNotOpenAppWindow(
       out_of_scope_url,
-      base::BindOnce(&ClickLinkAndWait,
-                     browser()->tab_strip_model()->GetActiveWebContents(),
-                     out_of_scope_url, LinkTarget::SELF, GetParam()));
+      base::BindOnce(&ClickLinkAndWait, GetWebContents(), out_of_scope_url,
+                     LinkTarget::SELF, GetParam()));
 
   EXPECT_EQ(nullptr, intent_picker_bubble());
 }
@@ -116,23 +136,25 @@
 
   const GURL in_scope_url =
       https_server().GetURL(GetAppUrlHost(), GetInScopeUrlPath());
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
+  auto* tab_helper = IntentPickerTabHelper::FromWebContents(GetWebContents());
   NavigateToLaunchingPage(browser());
 
   views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{},
                                        "IntentPickerBubbleView");
+  base::RunLoop run_loop;
+  tab_helper->SetIconUpdateCallbackForTesting(run_loop.QuitClosure());
   TestTabActionDoesNotOpenAppWindow(
-      in_scope_url, base::BindOnce(&ClickLinkAndWait, web_contents,
+      in_scope_url, base::BindOnce(&ClickLinkAndWait, GetWebContents(),
                                    in_scope_url, LinkTarget::SELF, GetParam()));
+  run_loop.Run();
 
-  PageActionIconView* intent_picker_view = GetIntentPickerIcon();
-  EXPECT_TRUE(intent_picker_view->GetVisible());
+  PageActionIconView* intent_picker_icon = GetIntentPickerIcon();
+  EXPECT_TRUE(intent_picker_icon->GetVisible());
 
 #if !BUILDFLAG(IS_CHROMEOS)
-  // On Chrome OS, the picker bubble will appear automatically.
+  // On ChromeOS, the picker bubble will appear automatically.
   EXPECT_FALSE(intent_picker_bubble());
-  GetIntentPickerIcon()->ExecuteForTesting();
+  intent_picker_icon->ExecuteForTesting();
 #endif
 
   waiter.WaitIfNeededAndGet();
@@ -188,7 +210,7 @@
 #endif  // BUILDFLAG(IS_CHROMEOS)
 #endif  // !BUILDFLAG(IS_CHROMEOS_LACROS)
 
-// Tests that the intent icon updates its visibiliy when switching between
+// Tests that the intent icon updates its visibility when switching between
 // tabs.
 IN_PROC_BROWSER_TEST_P(IntentPickerBubbleViewBrowserTest,
                        IconVisibilityAfterTabSwitching) {
@@ -199,19 +221,18 @@
   const GURL out_of_scope_url =
       https_server().GetURL(GetAppUrlHost(), GetOutOfScopeUrlPath());
 
-  PageActionIconView* intent_picker_view = GetIntentPickerIcon();
+  PageActionIconView* intent_picker_icon = GetIntentPickerIcon();
 
   // OpenNewTab opens a new tab and focus on the new tab.
   OpenNewTab(in_scope_url);
-  EXPECT_TRUE(intent_picker_view->GetVisible());
+  EXPECT_TRUE(intent_picker_icon->GetVisible());
   OpenNewTab(out_of_scope_url);
-  EXPECT_FALSE(intent_picker_view->GetVisible());
+  EXPECT_FALSE(intent_picker_icon->GetVisible());
 
   chrome::SelectPreviousTab(browser());
-  EXPECT_TRUE(intent_picker_view->GetVisible());
-
+  EXPECT_TRUE(intent_picker_icon->GetVisible());
   chrome::SelectNextTab(browser());
-  EXPECT_FALSE(intent_picker_view->GetVisible());
+  EXPECT_FALSE(intent_picker_icon->GetVisible());
 }
 
 // Tests that the navigation in iframe doesn't affect intent picker icon
@@ -224,29 +245,25 @@
   const GURL out_of_scope_url =
       https_server().GetURL(GetAppUrlHost(), GetOutOfScopeUrlPath());
 
-  PageActionIconView* intent_picker_view = GetIntentPickerIcon();
+  PageActionIconView* intent_picker_icon = GetIntentPickerIcon();
 
-  OpenNewTab(out_of_scope_url);
-  content::WebContents* initial_tab =
-      browser()->tab_strip_model()->GetActiveWebContents();
+  content::WebContents* initial_tab = OpenNewTab(out_of_scope_url);
   ASSERT_TRUE(InsertIFrame(initial_tab));
 
   EXPECT_TRUE(
       content::NavigateIframeToURL(initial_tab, "iframe", in_scope_url));
-  EXPECT_FALSE(intent_picker_view->GetVisible());
+  EXPECT_FALSE(intent_picker_icon->GetVisible());
 
-  OpenNewTab(in_scope_url);
-  content::WebContents* new_tab =
-      browser()->tab_strip_model()->GetActiveWebContents();
+  content::WebContents* new_tab = OpenNewTab(in_scope_url);
   ASSERT_TRUE(InsertIFrame(new_tab));
 
   EXPECT_TRUE(
       content::NavigateIframeToURL(initial_tab, "iframe", out_of_scope_url));
-  EXPECT_TRUE(intent_picker_view->GetVisible());
+  EXPECT_TRUE(intent_picker_icon->GetVisible());
 }
 
-// Tests that the intent picker icon is not visible if the navigatation
-// redirects to a URL that doesn't have an installed PWA.
+// Tests that the intent picker icon is not visible if the navigation redirects
+// to a URL that doesn't have an installed PWA.
 IN_PROC_BROWSER_TEST_P(IntentPickerBubbleViewBrowserTest,
                        DoesNotShowIntentPickerWhenRedirectedOutOfScope) {
   InstallTestWebApp(GetOtherAppUrlHost(), /*app_scope=*/"/");
@@ -257,15 +274,16 @@
   const GURL redirect_url = https_server().GetURL(
       GetOtherAppUrlHost(), CreateServerRedirect(out_of_scope_url));
 
-  PageActionIconView* intent_picker_view = GetIntentPickerIcon();
+  PageActionIconView* intent_picker_icon = GetIntentPickerIcon();
 
   OpenNewTab(in_scope_url);
-  EXPECT_TRUE(intent_picker_view->GetVisible());
+  EXPECT_TRUE(intent_picker_icon->GetVisible());
 
-  ClickLinkAndWaitForURL(browser()->tab_strip_model()->GetActiveWebContents(),
-                         redirect_url, out_of_scope_url, LinkTarget::SELF,
-                         GetParam());
-  EXPECT_FALSE(intent_picker_view->GetVisible());
+  DoAndWaitForIntentPickerIconUpdate([this, redirect_url, out_of_scope_url] {
+    ClickLinkAndWaitForURL(GetWebContents(), redirect_url, out_of_scope_url,
+                           LinkTarget::SELF, GetParam());
+  });
+  EXPECT_FALSE(intent_picker_icon->GetVisible());
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -302,10 +320,6 @@
     return prerender_helper_;
   }
 
-  content::WebContents* GetWebContents() {
-    return browser()->tab_strip_model()->GetActiveWebContents();
-  }
-
  private:
   content::test::PrerenderTestHelper prerender_helper_;
 };
@@ -314,12 +328,12 @@
                        PrerenderingShouldNotShowIntentPicker) {
   InstallTestWebApp();
 
-  PageActionIconView* intent_picker_view = GetIntentPickerIcon();
-
   const GURL initial_url =
       https_server().GetURL(GetAppUrlHost(), "/empty.html");
   OpenNewTab(initial_url);
-  EXPECT_FALSE(intent_picker_view->GetVisible());
+
+  PageActionIconView* intent_picker_icon = GetIntentPickerIcon();
+  EXPECT_FALSE(intent_picker_icon->GetVisible());
 
   // Load a prerender page and prerendering should not try to show the
   // intent picker.
@@ -329,15 +343,17 @@
   content::test::PrerenderHostObserver host_observer(*GetWebContents(),
                                                      host_id);
   EXPECT_FALSE(host_observer.was_activated());
-  EXPECT_FALSE(intent_picker_view->GetVisible());
+  EXPECT_FALSE(intent_picker_icon->GetVisible());
 
   // Activate the prerender page.
-  prerender_test_helper().NavigatePrimaryPage(prerender_url);
+  DoAndWaitForIntentPickerIconUpdate([this, prerender_url] {
+    prerender_test_helper().NavigatePrimaryPage(prerender_url);
+  });
   EXPECT_TRUE(host_observer.was_activated());
 
   // After activation, IntentPickerTabHelper should show the
   // intent picker.
-  EXPECT_TRUE(intent_picker_view->GetVisible());
+  EXPECT_TRUE(intent_picker_icon->GetVisible());
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -368,24 +384,20 @@
                        ShouldShowIntentPickerInFencedFrame) {
   InstallTestWebApp();
 
-  PageActionIconView* intent_picker_view = GetIntentPickerIcon();
+  PageActionIconView* intent_picker_icon = GetIntentPickerIcon();
 
   const GURL initial_url =
       https_server().GetURL(GetAppUrlHost(), "/empty.html");
   OpenNewTab(initial_url);
-  EXPECT_FALSE(intent_picker_view->GetVisible());
+  EXPECT_FALSE(intent_picker_icon->GetVisible());
 
   const GURL fenced_frame_url = https_server().GetURL(
       GetAppUrlHost(), std::string(GetAppScopePath()) + "index1.html");
   // Create a fenced frame.
-  ASSERT_TRUE(
-      fenced_frame_test_helper().CreateFencedFrame(browser()
-                                                       ->tab_strip_model()
-                                                       ->GetActiveWebContents()
-                                                       ->GetPrimaryMainFrame(),
-                                                   fenced_frame_url));
+  ASSERT_TRUE(fenced_frame_test_helper().CreateFencedFrame(
+      GetWebContents()->GetPrimaryMainFrame(), fenced_frame_url));
 
-  EXPECT_FALSE(intent_picker_view->GetVisible());
+  EXPECT_FALSE(intent_picker_icon->GetVisible());
 }
 
 INSTANTIATE_TEST_SUITE_P(
diff --git a/chrome/browser/ui/views/intent_picker_bubble_view_browsertest_chromeos.cc b/chrome/browser/ui/views/intent_picker_bubble_view_browsertest_chromeos.cc
index befdd18..b48f72c 100644
--- a/chrome/browser/ui/views/intent_picker_bubble_view_browsertest_chromeos.cc
+++ b/chrome/browser/ui/views/intent_picker_bubble_view_browsertest_chromeos.cc
@@ -30,6 +30,7 @@
 #include "chrome/browser/ui/browser_list_observer.h"
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_navigator_params.h"
+#include "chrome/browser/ui/intent_picker_tab_helper.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/toolbar_button_provider.h"
 #include "chrome/browser/ui/views/location_bar/intent_picker_view.h"
@@ -347,6 +348,19 @@
     return embedded_test_server()->GetURL("/web_apps/minimal_ui/basic.html");
   }
 
+  content::WebContents* GetWebContents() {
+    return browser()->tab_strip_model()->GetActiveWebContents();
+  }
+
+  template <typename Action>
+  void DoAndWaitForIntentPickerIconUpdate(Action action) {
+    base::RunLoop run_loop;
+    auto* tab_helper = IntentPickerTabHelper::FromWebContents(GetWebContents());
+    tab_helper->SetIconUpdateCallbackForTesting(run_loop.QuitClosure());
+    action();
+    run_loop.Run();
+  }
+
  private:
   base::test::ScopedFeatureList feature_list_;
   apps::AppServiceProxy* app_service_proxy_ = nullptr;
@@ -404,14 +418,10 @@
   // Launch the default selected app.
   EXPECT_EQ(0U, launched_arc_apps().size());
 
-  content::TestNavigationObserver observer(
-      browser()->tab_strip_model()->GetActiveWebContents());
-
-  intent_picker_bubble()->AcceptDialog();
-  ASSERT_NO_FATAL_FAILURE(VerifyArcAppLaunched(app_name, test_url));
-
-  // The page should go back to blank state after launching the app.
-  observer.WaitForNavigationFinished();
+  DoAndWaitForIntentPickerIconUpdate([this, app_name, test_url] {
+    intent_picker_bubble()->AcceptDialog();
+    ASSERT_NO_FATAL_FAILURE(VerifyArcAppLaunched(app_name, test_url));
+  });
 
   // Make sure that the intent picker icon is no longer visible.
   ASSERT_TRUE(intent_picker_view);
@@ -744,12 +754,12 @@
   NavigateParams params(browser(), test_url,
                         ui::PageTransition::PAGE_TRANSITION_LINK);
 
+  // Navigates and waits for loading to finish.
   views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{},
                                        IntentPickerBubbleView::kViewClassName);
-  // Navigates and waits for loading to finish.
   ui_test_utils::NavigateToURL(&params);
-
   waiter.WaitIfNeededAndGet();
+
   EXPECT_TRUE(intent_picker_view->GetVisible());
   ASSERT_TRUE(intent_picker_bubble());
   EXPECT_TRUE(intent_picker_bubble()->GetVisible());
@@ -762,11 +772,12 @@
 
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
-  content::TestNavigationObserver observer(web_contents);
-  ASSERT_TRUE(content::ExecuteScript(
-      web_contents,
-      "document.getElementById('push_to_new_url_button').click();"));
-  observer.WaitForNavigationFinished();
+  DoAndWaitForIntentPickerIconUpdate([web_contents] {
+    ASSERT_TRUE(content::ExecuteScript(
+        web_contents,
+        "document.getElementById('push_to_new_url_button').click();"));
+  });
+
   EXPECT_FALSE(intent_picker_view->GetVisible());
 }
 
@@ -794,11 +805,9 @@
   auto app_id = AddArcAppWithIntentFilter(app_name, test_url);
 
   // Reload the page and the intent picker should show up.
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  content::TestNavigationObserver observer(web_contents);
-  chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB);
-  observer.WaitForNavigationFinished();
+  DoAndWaitForIntentPickerIconUpdate([this] {
+    chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB);
+  });
 
   EXPECT_TRUE(intent_picker_view->GetVisible());
 
diff --git a/chrome/browser/ui/views/location_bar/content_setting_bubble_dialog_browsertest.cc b/chrome/browser/ui/views/location_bar/content_setting_bubble_dialog_browsertest.cc
index c584c5e8..a46a0bfd 100644
--- a/chrome/browser/ui/views/location_bar/content_setting_bubble_dialog_browsertest.cc
+++ b/chrome/browser/ui/views/location_bar/content_setting_bubble_dialog_browsertest.cc
@@ -4,7 +4,6 @@
 
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
@@ -196,15 +195,9 @@
     ContentSettingImageModel::ImageType image_type) {
   LocationBarTesting* location_bar_testing =
       browser()->window()->GetLocationBar()->GetLocationBarForTesting();
-
-  base::HistogramTester histograms;
-
   EXPECT_TRUE(location_bar_testing->TestContentSettingImagePressed(
       ContentSettingImageModel::GetContentSettingImageModelIndexForTesting(
           image_type)));
-
-  histograms.ExpectBucketCount("ContentSettings.ImagePressed",
-                               static_cast<int>(image_type), 1);
 }
 
 void ContentSettingBubbleDialogTest::ShowUi(const std::string& name) {
diff --git a/chrome/browser/ui/views/location_bar/intent_chip_button_browsertest.cc b/chrome/browser/ui/views/location_bar/intent_chip_button_browsertest.cc
index 776b8d13..09adc730 100644
--- a/chrome/browser/ui/views/location_bar/intent_chip_button_browsertest.cc
+++ b/chrome/browser/ui/views/location_bar/intent_chip_button_browsertest.cc
@@ -100,12 +100,23 @@
     web_app::WebAppNavigationBrowserTest::TearDownOnMainThread();
   }
 
-  void OpenNewTab(const GURL& url) {
-    chrome::NewTab(browser());
+  template <typename Action>
+  void DoAndWaitForIntentPickerIconUpdate(Action action) {
     content::WebContents* web_contents =
         browser()->tab_strip_model()->GetActiveWebContents();
-    NavigateToLaunchingPage(browser());
-    ClickLinkAndWait(web_contents, url, LinkTarget::SELF, "");
+    base::RunLoop run_loop;
+    auto* tab_helper = IntentPickerTabHelper::FromWebContents(web_contents);
+    tab_helper->SetIconUpdateCallbackForTesting(run_loop.QuitClosure());
+    action();
+    run_loop.Run();
+  }
+
+  void OpenNewTab(const GURL& url) {
+    chrome::NewTab(browser());
+    DoAndWaitForIntentPickerIconUpdate(
+        [this] { NavigateToLaunchingPage(browser()); });
+    ClickLinkAndWaitForIconUpdate(
+        browser()->tab_strip_model()->GetActiveWebContents(), url);
   }
 
   IntentChipButton* GetIntentChip() {
@@ -121,6 +132,16 @@
     test_api.NotifyClick(e);
   }
 
+  void ClickLinkAndWaitForIconUpdate(content::WebContents* web_contents,
+                                     const GURL& link_url) {
+    auto* tab_helper = IntentPickerTabHelper::FromWebContents(web_contents);
+
+    base::RunLoop run_loop;
+    tab_helper->SetIconUpdateCallbackForTesting(run_loop.QuitClosure());
+    ClickLinkAndWait(web_contents, link_url, LinkTarget::SELF, "");
+    run_loop.Run();
+  }
+
   // Installs a web app on the same host as InstallTestWebApp(), but with "/" as
   // a scope, so it overlaps with all URLs in the test app scope.
   void InstallOverlappingApp() {
@@ -184,7 +205,6 @@
 
   chrome::SelectPreviousTab(browser());
   EXPECT_TRUE(intent_chip_button->GetVisible());
-
   chrome::SelectNextTab(browser());
   EXPECT_FALSE(intent_chip_button->GetVisible());
 }
@@ -199,9 +219,11 @@
       https_server().GetURL(GetAppUrlHost(), GetInScopeUrlPath());
   ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), in_scope_url));
 
+  ui_test_utils::BrowserChangeObserver new_browser(
+      nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
   ClickIntentChip();
+  Browser* app_browser = new_browser.Wait();
 
-  Browser* app_browser = BrowserList::GetInstance()->GetLastActive();
   EXPECT_TRUE(web_app::AppBrowserController::IsForWebApp(app_browser,
                                                          test_web_app_id()));
 }
@@ -247,9 +269,11 @@
       https_server().GetURL(GetAppUrlHost(), GetInScopeUrlPath());
   ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), in_scope_url));
 
+  ui_test_utils::BrowserChangeObserver new_browser(
+      nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
   ClickIntentChip();
+  Browser* app_browser = new_browser.Wait();
 
-  Browser* app_browser = BrowserList::GetInstance()->GetLastActive();
   EXPECT_TRUE(web_app::AppBrowserController::IsForWebApp(app_browser,
                                                          test_web_app_id()));
 }
@@ -298,31 +322,31 @@
       browser()->tab_strip_model()->GetActiveWebContents();
 
   // 1st appearance: Expanded.
-  ClickLinkAndWait(web_contents, in_scope_url, LinkTarget::SELF, "");
+  ClickLinkAndWaitForIconUpdate(web_contents, in_scope_url);
   EXPECT_TRUE(GetIntentChip()->GetVisible());
   EXPECT_FALSE(GetIntentChip()->is_fully_collapsed());
 
-  ClickLinkAndWait(web_contents, separate_host_url, LinkTarget::SELF, "");
+  ClickLinkAndWaitForIconUpdate(web_contents, separate_host_url);
   EXPECT_FALSE(GetIntentChip()->GetVisible());
 
   // 2nd appearance: Expanded.
-  ClickLinkAndWait(web_contents, in_scope_url, LinkTarget::SELF, "");
+  ClickLinkAndWaitForIconUpdate(web_contents, in_scope_url);
   EXPECT_TRUE(GetIntentChip()->GetVisible());
   EXPECT_FALSE(GetIntentChip()->is_fully_collapsed());
 
-  ClickLinkAndWait(web_contents, out_of_scope_url, LinkTarget::SELF, "");
+  ClickLinkAndWaitForIconUpdate(web_contents, out_of_scope_url);
   EXPECT_FALSE(GetIntentChip()->GetVisible());
 
   // 3rd appearance: Expanded.
-  ClickLinkAndWait(web_contents, in_scope_url, LinkTarget::SELF, "");
+  ClickLinkAndWaitForIconUpdate(web_contents, in_scope_url);
   EXPECT_TRUE(GetIntentChip()->GetVisible());
   EXPECT_FALSE(GetIntentChip()->is_fully_collapsed());
 
-  ClickLinkAndWait(web_contents, out_of_scope_url, LinkTarget::SELF, "");
+  ClickLinkAndWaitForIconUpdate(web_contents, out_of_scope_url);
   EXPECT_FALSE(GetIntentChip()->GetVisible());
 
   // 4th appearance: Collapsed.
-  ClickLinkAndWait(web_contents, in_scope_url, LinkTarget::SELF, "");
+  ClickLinkAndWaitForIconUpdate(web_contents, in_scope_url);
   EXPECT_TRUE(GetIntentChip()->GetVisible());
   EXPECT_TRUE(GetIntentChip()->is_fully_collapsed());
 
@@ -330,11 +354,12 @@
   ClickIntentChip();
 
   // Open another browser- we should be able to see the expanded chip again.
-  NavigateToLaunchingPage(browser());
-  web_contents = browser()->tab_strip_model()->GetActiveWebContents();
+  DoAndWaitForIntentPickerIconUpdate(
+      [this] { NavigateToLaunchingPage(browser()); });
 
   // 1st appearance since intent chip counter reset: Expanded.
-  ClickLinkAndWait(web_contents, in_scope_url, LinkTarget::SELF, "");
+  web_contents = browser()->tab_strip_model()->GetActiveWebContents();
+  ClickLinkAndWaitForIconUpdate(web_contents, in_scope_url);
   EXPECT_TRUE(GetIntentChip()->GetVisible());
   EXPECT_FALSE(GetIntentChip()->is_fully_collapsed());
 }
@@ -380,7 +405,7 @@
       browser()->tab_strip_model()->GetActiveWebContents();
 
   // Navigate to an in-scope page to see the intent chip and the IPH.
-  ClickLinkAndWait(web_contents, in_scope_url, LinkTarget::SELF, "");
+  ClickLinkAndWaitForIconUpdate(web_contents, in_scope_url);
   EXPECT_TRUE(GetIntentChip()->GetVisible());
 
   // Wait for the chip to actually be laid out. This will result in the IPH
@@ -407,18 +432,6 @@
     feature_list_.InitAndEnableFeature(apps::features::kIntentChipAppIcon);
   }
 
-  void ClickLinkAndWaitForIconUpdate(content::WebContents* web_contents,
-                                     const GURL& link_url) {
-    auto* tab_helper = IntentPickerTabHelper::FromWebContents(web_contents);
-    base::RunLoop run_loop;
-    tab_helper->SetIconUpdateCallbackForTesting(
-        base::BindLambdaForTesting([&run_loop]() { run_loop.Quit(); }));
-
-    ClickLinkAndWait(web_contents, link_url, LinkTarget::SELF, "");
-
-    run_loop.Run();
-  }
-
  private:
   base::test::ScopedFeatureList feature_list_;
 };
@@ -481,11 +494,16 @@
                        ShowsInfoBarOnAppOpen) {
   const GURL in_scope_url =
       https_server().GetURL(GetAppUrlHost(), GetInScopeUrlPath());
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), in_scope_url));
 
+  DoAndWaitForIntentPickerIconUpdate([this, in_scope_url] {
+    ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), in_scope_url));
+  });
   EXPECT_TRUE(GetIntentChip()->GetVisible());
 
+  ui_test_utils::BrowserChangeObserver browser_opened(
+      nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
   ClickIntentChip();
+  browser_opened.Wait();
 
   Browser* app_browser = BrowserList::GetInstance()->GetLastActive();
   EXPECT_TRUE(web_app::AppBrowserController::IsForWebApp(app_browser,
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_button_view.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_button_view.cc
index ed5656b..f30a663 100644
--- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_button_view.cc
+++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_button_view.cc
@@ -6,11 +6,15 @@
 
 #include "chrome/browser/ui/views/side_panel/read_anything/read_anything_constants.h"
 #include "ui/base/models/image_model.h"
+#include "ui/views/controls/button/image_button_factory.h"
+#include "ui/views/controls/highlight_path_generator.h"
 #include "ui/views/layout/box_layout.h"
 
 ReadAnythingButtonView::ReadAnythingButtonView(
     views::ImageButton::PressedCallback callback,
-    const gfx::ImageSkia& icon,
+    const gfx::VectorIcon& icon,
+    int icon_size,
+    SkColor icon_color,
     const std::u16string& tooltip) {
   // Create and set a BoxLayout with insets to hold the button.
   auto button_layout_manager = std::make_unique<views::BoxLayout>(
@@ -25,19 +29,21 @@
   SetLayoutManager(std::move(button_layout_manager));
 
   // Create the image button.
-  auto button = std::make_unique<views::ImageButton>(std::move(callback));
-  button->SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
-  button->SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
-  button->SetImageModel(views::Button::STATE_NORMAL,
-                        ui::ImageModel::FromImageSkia(icon));
+  auto button = views::CreateVectorImageButton(std::move(callback));
+  views::SetImageFromVectorIconWithColor(button.get(), icon, icon_size,
+                                         icon_color, icon_color);
+  views::InstallCircleHighlightPathGenerator(button.get());
   button->SetTooltipText(tooltip);
 
   // Add the button to the view.
   button_ = AddChildView(std::move(button));
 }
 
-void ReadAnythingButtonView::UpdateIcon(const gfx::ImageSkia& icon) {
-  button_->SetImage(views::Button::STATE_NORMAL, icon);
+void ReadAnythingButtonView::UpdateIcon(const gfx::VectorIcon& icon,
+                                        int icon_size,
+                                        SkColor icon_color) {
+  views::SetImageFromVectorIconWithColor(button_, icon, icon_size, icon_color,
+                                         icon_color);
 }
 
 ReadAnythingButtonView::~ReadAnythingButtonView() = default;
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_button_view.h b/chrome/browser/ui/views/side_panel/read_anything/read_anything_button_view.h
index e962cb4..dc6479e8 100644
--- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_button_view.h
+++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_button_view.h
@@ -20,13 +20,17 @@
 class ReadAnythingButtonView : public views::View {
  public:
   ReadAnythingButtonView(const views::ImageButton::PressedCallback callback,
-                         const gfx::ImageSkia& icon,
+                         const gfx::VectorIcon& icon,
+                         int icon_size,
+                         SkColor icon_color,
                          const std::u16string& tooltip);
   ReadAnythingButtonView(const ReadAnythingButtonView&) = delete;
   ReadAnythingButtonView& operator=(const ReadAnythingButtonView&) = delete;
   ~ReadAnythingButtonView() override;
 
-  void UpdateIcon(const gfx::ImageSkia& icon);
+  void UpdateIcon(const gfx::VectorIcon& icon,
+                  int icon_size,
+                  SkColor icon_color);
 
  private:
   raw_ptr<views::ImageButton> button_;
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view.cc
index 15c20710..2661d9b 100644
--- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view.cc
+++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view.cc
@@ -51,16 +51,14 @@
   auto decrease_size_button = std::make_unique<ReadAnythingButtonView>(
       base::BindRepeating(&ReadAnythingToolbarView::DecreaseFontSizeCallback,
                           weak_pointer_factory_.GetWeakPtr()),
-      gfx::CreateVectorIcon(kTextDecreaseIcon, kSmallIconSize,
-                            gfx::kPlaceholderColor),
+      kTextDecreaseIcon, kSmallIconSize, gfx::kPlaceholderColor,
       l10n_util::GetStringUTF16(
           IDS_READ_ANYTHING_DECREASE_FONT_SIZE_BUTTON_LABEL));
 
   auto increase_size_button = std::make_unique<ReadAnythingButtonView>(
       base::BindRepeating(&ReadAnythingToolbarView::IncreaseFontSizeCallback,
                           weak_pointer_factory_.GetWeakPtr()),
-      gfx::CreateVectorIcon(kTextIncreaseIcon, kLargeIconSize,
-                            gfx::kPlaceholderColor),
+      kTextIncreaseIcon, kLargeIconSize, gfx::kPlaceholderColor,
       l10n_util::GetStringUTF16(
           IDS_READ_ANYTHING_INCREASE_FONT_SIZE_BUTTON_LABEL));
 
@@ -162,11 +160,11 @@
   letter_spacing_combobox_->SetBackground(
       views::CreateSolidBackground(new_theme->background_color));
 
-  decrease_text_size_button_->UpdateIcon(gfx::CreateVectorIcon(
-      kTextDecreaseIcon, kSmallIconSize, new_theme->foreground_color));
+  decrease_text_size_button_->UpdateIcon(kTextDecreaseIcon, kSmallIconSize,
+                                         new_theme->foreground_color);
 
-  increase_text_size_button_->UpdateIcon(gfx::CreateVectorIcon(
-      kTextIncreaseIcon, kLargeIconSize, new_theme->foreground_color));
+  increase_text_size_button_->UpdateIcon(kTextIncreaseIcon, kLargeIconSize,
+                                         new_theme->foreground_color);
 
   for (views::Separator* separator : separators_) {
     separator->SetColorId(delegate_->GetForegroundColorId());
diff --git a/chrome/browser/ui/views/tabs/tab_strip_scrolling_overflow_indicator_strategy.cc b/chrome/browser/ui/views/tabs/tab_strip_scrolling_overflow_indicator_strategy.cc
index d95c483..6e0cb6d 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_scrolling_overflow_indicator_strategy.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip_scrolling_overflow_indicator_strategy.cc
@@ -44,6 +44,8 @@
 
   switch (overview_feature_flag) {
     case OverflowFeatureFlag::kDivider:
+      return std::make_unique<DividerOverflowIndicatorStrategy>(scroll_view,
+                                                                tab_strip);
     case OverflowFeatureFlag::kFade:
       return std::make_unique<FadeOverflowIndicatorStrategy>(scroll_view,
                                                              tab_strip);
@@ -223,3 +225,42 @@
   left_overflow_indicator()->SetShadowColor(frame_color);
   right_overflow_indicator()->SetShadowColor(frame_color);
 }
+
+DividerOverflowIndicatorStrategy::DividerOverflowIndicatorStrategy(
+    views::ScrollView* scroll_view,
+    TabStrip* tab_strip)
+    : GradientOverflowIndicatorStrategy(scroll_view, tab_strip) {}
+
+void DividerOverflowIndicatorStrategy::Init() {
+  scroll_view()->SetDrawOverflowIndicator(true);
+
+  std::unique_ptr<GradientIndicatorView> left_overflow_indicator =
+      std::make_unique<GradientIndicatorView>(
+          views::OverflowIndicatorAlignment::kLeft);
+  left_overflow_indicator_ = left_overflow_indicator.get();
+
+  std::unique_ptr<GradientIndicatorView> right_overflow_indicator =
+      std::make_unique<GradientIndicatorView>(
+          views::OverflowIndicatorAlignment::kRight);
+  right_overflow_indicator_ = right_overflow_indicator.get();
+
+  left_overflow_indicator_->SetOpaqueWidth(0);
+  right_overflow_indicator_->SetOpaqueWidth(0);
+
+  scroll_view()->SetCustomOverflowIndicator(
+      views::OverflowIndicatorAlignment::kLeft,
+      std::move(left_overflow_indicator),
+      left_overflow_indicator_->GetTotalWidth(), false);
+
+  scroll_view()->SetCustomOverflowIndicator(
+      views::OverflowIndicatorAlignment::kRight,
+      std::move(right_overflow_indicator),
+      right_overflow_indicator_->GetTotalWidth(), false);
+}
+
+void DividerOverflowIndicatorStrategy::FrameColorsChanged() {
+  SkColor4f shadow_color = SkColor4f::FromColor(
+      tab_strip()->GetColorProvider()->GetColor(ui::kColorShadowBase));
+  left_overflow_indicator()->SetShadowColor(shadow_color);
+  right_overflow_indicator()->SetShadowColor(shadow_color);
+}
diff --git a/chrome/browser/ui/views/tabs/tab_strip_scrolling_overflow_indicator_strategy.h b/chrome/browser/ui/views/tabs/tab_strip_scrolling_overflow_indicator_strategy.h
index 4c5d04b..a0cc51a 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_scrolling_overflow_indicator_strategy.h
+++ b/chrome/browser/ui/views/tabs/tab_strip_scrolling_overflow_indicator_strategy.h
@@ -153,4 +153,15 @@
   void FrameColorsChanged() override;
 };
 
+class DividerOverflowIndicatorStrategy
+    : public GradientOverflowIndicatorStrategy {
+ public:
+  DividerOverflowIndicatorStrategy(views::ScrollView* scroll_view,
+                                   TabStrip* tab_strip);
+  ~DividerOverflowIndicatorStrategy() override = default;
+
+  void Init() override;
+  void FrameColorsChanged() override;
+};
+
 #endif  // CHROME_BROWSER_UI_VIEWS_TABS_TAB_STRIP_SCROLLING_OVERFLOW_INDICATOR_STRATEGY_H_
diff --git a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_toolbar_button_container.cc b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_toolbar_button_container.cc
index 6d7766a..02868707 100644
--- a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_toolbar_button_container.cc
+++ b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_toolbar_button_container.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/ui/views/web_apps/frame_toolbar/web_app_toolbar_button_container.h"
 
-#include "base/metrics/histogram_macros.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
@@ -321,13 +320,6 @@
   return browser_view_->browser()->content_setting_bubble_model_delegate();
 }
 
-void WebAppToolbarButtonContainer::OnContentSettingImageBubbleShown(
-    ContentSettingImageModel::ImageType type) const {
-  UMA_HISTOGRAM_ENUMERATION(
-      "HostedAppFrame.ContentSettings.ImagePressed", type,
-      ContentSettingImageModel::ImageType::NUM_IMAGE_TYPES);
-}
-
 // ImmersiveModeController::Observer:
 void WebAppToolbarButtonContainer::OnImmersiveRevealStarted() {
   // Don't wait for the fade in animation to make content setting icons
diff --git a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_toolbar_button_container.h b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_toolbar_button_container.h
index 339b6c0..5ee7bcfd 100644
--- a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_toolbar_button_container.h
+++ b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_toolbar_button_container.h
@@ -126,8 +126,6 @@
   content::WebContents* GetContentSettingWebContents() override;
   ContentSettingBubbleModelDelegate* GetContentSettingBubbleModelDelegate()
       override;
-  void OnContentSettingImageBubbleShown(
-      ContentSettingImageModel::ImageType type) const override;
 
   // ImmersiveModeController::Observer:
   void OnImmersiveRevealStarted() override;
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.cc b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.cc
index fe0d228e..a56f8cf 100644
--- a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.cc
+++ b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.cc
@@ -83,6 +83,7 @@
                       const std::string& action) {
   using file_manager::file_tasks::kActionIdOpenInOffice;
   using file_manager::file_tasks::SetExcelFileHandler;
+  using file_manager::file_tasks::SetOfficeSetupComplete;
   using file_manager::file_tasks::SetPowerPointFileHandler;
   using file_manager::file_tasks::SetWordFileHandler;
 
@@ -93,11 +94,13 @@
                         file_manager::file_tasks::kActionIdWebDriveOfficeExcel);
     SetPowerPointFileHandler(
         profile, file_manager::file_tasks::kActionIdWebDriveOfficePowerPoint);
+    SetOfficeSetupComplete(profile);
     StartUpload(profile, file_urls, CloudProvider::kGoogleDrive);
   } else if (action == kUserActionUploadToOneDrive) {
     SetWordFileHandler(profile, kActionIdOpenInOffice);
     SetExcelFileHandler(profile, kActionIdOpenInOffice);
     SetPowerPointFileHandler(profile, kActionIdOpenInOffice);
+    SetOfficeSetupComplete(profile);
     StartUpload(profile, file_urls, CloudProvider::kOneDrive);
   } else if (action == kUserActionSetUpGoogleDrive) {
     CloudUploadDialog::Show(profile, file_urls,
@@ -115,9 +118,9 @@
 
 bool UploadAndOpen(Profile* profile,
                    const std::vector<storage::FileSystemURL>& file_urls,
-                   const CloudProvider cloud_provider,
-                   bool show_dialog) {
-  if (show_dialog) {
+                   const CloudProvider cloud_provider) {
+  // Run the setup flow if it's never been completed.
+  if (!file_manager::file_tasks::OfficeSetupComplete(profile)) {
     return CloudUploadDialog::Show(profile, file_urls,
                                    mojom::DialogPage::kFileHandlerDialog);
   }
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.h b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.h
index 35e226c..bee2ea6 100644
--- a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.h
+++ b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.h
@@ -32,8 +32,7 @@
 // Initiates the upload workflow.
 bool UploadAndOpen(Profile* profile,
                    const std::vector<storage::FileSystemURL>& file_urls,
-                   const CloudProvider cloud_provider,
-                   bool show_dialog);
+                   const CloudProvider cloud_provider);
 
 // Defines the web dialog used to help users upload Office files to the cloud.
 class CloudUploadDialog : public SystemWebDialogDelegate {
diff --git a/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_ui.cc b/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_ui.cc
index b08b9d51..d197537 100644
--- a/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_ui.cc
+++ b/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_ui.cc
@@ -28,7 +28,7 @@
   html_source->OverrideContentSecurityPolicy(
       network::mojom::CSPDirectiveName::ScriptSrc,
       "script-src chrome://resources chrome://webui-test 'self';");
-  html_source->DisableTrustedTypesCSP();
+  webui::EnableTrustedTypesCSP(html_source);
   html_source->AddResourcePath("test_loader_util.js",
                                IDR_WEBUI_JS_TEST_LOADER_UTIL_JS);
 
diff --git a/chrome/browser/ui/webui/settings/ash/internet_section.cc b/chrome/browser/ui/webui/settings/ash/internet_section.cc
index 507d2099e..20a3dd0 100644
--- a/chrome/browser/ui/webui/settings/ash/internet_section.cc
+++ b/chrome/browser/ui/webui/settings/ash/internet_section.cc
@@ -436,7 +436,9 @@
        mojom::SearchResultIcon::kInstantTethering,
        mojom::SearchResultDefaultRank::kMedium,
        mojom::SearchResultType::kSubpage,
-       {.subpage = mojom::Subpage::kMobileDataNetworks}},
+       {.subpage = mojom::Subpage::kMobileDataNetworks},
+       {IDS_OS_SETTINGS_TAG_INSTANT_MOBILE_NETWORKS_ALT1,
+        SearchConcept::kAltTagEnd}},
   });
   return *tags;
 }
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc
index e660a08..0333690 100644
--- a/chrome/browser/ui/webui/settings/settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -414,6 +414,7 @@
   webui::SetupWebUIDataSource(
       html_source, base::make_span(kSettingsResources, kSettingsResourcesSize),
       IDR_SETTINGS_SETTINGS_HTML);
+  webui::EnableTrustedTypesCSP(html_source);
 
   AddLocalizedStrings(html_source, profile, web_ui->GetWebContents());
 
diff --git a/chrome/browser/ui/webui/webui_util.cc b/chrome/browser/ui/webui/webui_util.cc
index 0e87f4c..089e337f 100644
--- a/chrome/browser/ui/webui/webui_util.cc
+++ b/chrome/browser/ui/webui/webui_util.cc
@@ -69,6 +69,8 @@
   source->OverrideContentSecurityPolicy(
       network::mojom::CSPDirectiveName::TrustedTypes,
       "trusted-types parse-html-subset sanitize-inner-html static-types "
+      // Add TrustedTypes policies for cr-lottie.
+      "lottie-worker-script-loader "
       // Add TrustedTypes policies used during tests.
       "webui-test-script webui-test-html "
       // Add TrustedTypes policies necessary for using Polymer.
diff --git a/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_from_command_line.cc b/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_from_command_line.cc
index b2fea557..d8cd41f 100644
--- a/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_from_command_line.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_from_command_line.cc
@@ -12,6 +12,7 @@
 #include "base/command_line.h"
 #include "base/feature_list.h"
 #include "base/files/file_util.h"
+#include "base/functional/callback_helpers.h"
 #include "base/functional/overloaded.h"
 #include "base/no_destructor.h"
 #include "base/strings/strcat.h"
@@ -20,6 +21,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/web_applications/commands/install_isolated_web_app_command.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h"
+#include "chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_reader.h"
 #include "chrome/browser/web_applications/isolation_data.h"
 #include "chrome/browser/web_applications/web_app_command_manager.h"
 #include "chrome/browser/web_applications/web_app_command_scheduler.h"
@@ -29,6 +31,7 @@
 #include "components/policy/core/common/policy_pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "components/web_package/signed_web_bundles/signed_web_bundle_id.h"
+#include "components/web_package/signed_web_bundles/signed_web_bundle_signature_verifier.h"
 #include "components/webapps/browser/installable/installable_manager.h"
 #include "content/public/common/content_features.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -101,30 +104,108 @@
   return IsolationData{IsolationData::DevModeBundle{.path = absolute_path}};
 }
 
+// TODO: Reconsider where this function should live
+// https://crrev.com/c/4010139/comment/48a226a1_9d7ebd63/
+void GetSignedWebBundleIdByPath(
+    const base::FilePath& path,
+    base::OnceCallback<void(base::expected<IsolatedWebAppUrlInfo, std::string>)>
+        callback) {
+  std::unique_ptr<SignedWebBundleReader> reader =
+      SignedWebBundleReader::Create(path);
+
+  SignedWebBundleReader* reader_raw_ptr = reader.get();
+
+  auto [callback_first, callback_second] =
+      base::SplitOnceCallback(std::move(callback));
+
+  SignedWebBundleReader::IntegrityBlockReadResultCallback
+      integrity_block_result_callback = base::BindOnce(
+          [](base::OnceCallback<void(
+                 base::expected<IsolatedWebAppUrlInfo, std::string>)> callback,
+             const std::vector<web_package::Ed25519PublicKey>& public_key_stack,
+             base::OnceCallback<void(
+                 SignedWebBundleReader::SignatureVerificationAction)>
+                 verify_callback) {
+            std::move(verify_callback)
+                .Run(SignedWebBundleReader::SignatureVerificationAction::Abort(
+                    "Stopped after reading the integrity block."));
+            DCHECK(!public_key_stack.empty());
+            web_package::SignedWebBundleId bundle_id =
+                web_package::SignedWebBundleId::CreateForEd25519PublicKey(
+                    public_key_stack[0]);
+            std::move(callback).Run(
+                IsolatedWebAppUrlInfo::CreateFromSignedWebBundleId(bundle_id));
+          },
+          std::move(callback_first));
+
+  SignedWebBundleReader::ReadErrorCallback read_error_callback = base::BindOnce(
+      [](std::unique_ptr<SignedWebBundleReader> reader_ownership,
+         base::OnceCallback<void(
+             base::expected<IsolatedWebAppUrlInfo, std::string>)> callback,
+         absl::optional<
+             SignedWebBundleReader::ReadIntegrityBlockAndMetadataError>
+             read_error) {
+        DCHECK(read_error.has_value());
+
+        if (!absl::holds_alternative<SignedWebBundleReader::AbortedByCaller>(
+                read_error.value())) {
+          web_package::mojom::BundleIntegrityBlockParseErrorPtr* error_ptr =
+              absl::get_if<
+                  web_package::mojom::BundleIntegrityBlockParseErrorPtr>(
+                  &read_error.value());
+          // only other possible variant, as the other 2 variants shouldn't be
+          // reachable.
+          DCHECK(error_ptr);
+
+          std::move(callback).Run(base::unexpected(base::StrCat(
+              {"Failed to read the integrity block of the signed web bundle: ",
+               (*error_ptr)->message})));
+        }
+      },
+      std::move(reader), std::move(callback_second));
+  ;
+
+  reader_raw_ptr->StartReading(std::move(integrity_block_result_callback),
+                               std::move(read_error_callback));
+}
 }  // namespace
 
-base::expected<IsolatedWebAppUrlInfo, std::string> GetIsolationInfo(
-    const IsolationData& isolation_data) {
-  return absl::visit(
-      base::Overloaded{
-          [](const IsolationData::InstalledBundle&)
-              -> base::expected<IsolatedWebAppUrlInfo, std::string> {
-            return base::unexpected(
-                "Getting IsolationInfo from |InstalledBundle| is not "
-                "implemented");
-          },
-          [](const IsolationData::DevModeBundle&)
-              -> base::expected<IsolatedWebAppUrlInfo, std::string> {
-            return base::unexpected(
-                "Getting IsolationInfo from |DevModeBundle| is not "
-                "implemented");
-          },
-          [](const IsolationData::DevModeProxy&)
-              -> base::expected<IsolatedWebAppUrlInfo, std::string> {
-            return IsolatedWebAppUrlInfo::CreateFromSignedWebBundleId(
-                web_package::SignedWebBundleId::CreateRandomForDevelopment());
-          }},
-      isolation_data.content);
+void GetIsolationInfo(
+    const IsolationData& isolation_data,
+    base::OnceCallback<void(base::expected<IsolatedWebAppUrlInfo, std::string>)>
+        callback) {
+  absl::visit(base::Overloaded{
+                  [&](const IsolationData::InstalledBundle&) {
+                    std::move(callback).Run(base::unexpected(
+                        "Getting IsolationInfo from |InstalledBundle| is not "
+                        "implemented"));
+                  },
+                  [&](const IsolationData::DevModeBundle& dev_mode_bundle) {
+                    GetSignedWebBundleIdByPath(dev_mode_bundle.path,
+                                               std::move(callback));
+                  },
+                  [&](const IsolationData::DevModeProxy&) {
+                    std::move(callback).Run(
+                        IsolatedWebAppUrlInfo::CreateFromSignedWebBundleId(
+                            web_package::SignedWebBundleId::
+                                CreateRandomForDevelopment()));
+                  }},
+              isolation_data.content);
+}
+
+void OnGetIsolationInfo(
+    WebAppProvider* provider,
+    const IsolationData& isolation_data,
+    base::expected<IsolatedWebAppUrlInfo, std::string> isolation_info) {
+  if (!isolation_info.has_value()) {
+    LOG(ERROR) << base::StrCat(
+        {"Failed to get IsolationInfo: ", isolation_info.error()});
+    return;
+  }
+
+  provider->scheduler().InstallIsolatedWebApp(
+      isolation_info.value(), isolation_data,
+      base::BindOnce(&ReportInstallationResult));
 }
 
 base::expected<absl::optional<IsolationData>, std::string>
@@ -185,17 +266,9 @@
     return;
   }
 
-  base::expected<IsolatedWebAppUrlInfo, std::string> isolation_info =
-      GetIsolationInfo(**isolation_data);
-
-  if (!isolation_info.has_value()) {
-    LOG(ERROR) << isolation_info.error();
-    return;
-  }
-
-  provider->scheduler().InstallIsolatedWebApp(
-      isolation_info.value(), **isolation_data,
-      base::BindOnce(&ReportInstallationResult));
+  GetIsolationInfo(
+      **isolation_data,
+      base::BindOnce(&OnGetIsolationInfo, provider, **isolation_data));
 }
 
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_from_command_line.h b/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_from_command_line.h
index 633d7d155..827fea8 100644
--- a/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_from_command_line.h
+++ b/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_from_command_line.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_WEB_APPLICATIONS_ISOLATED_WEB_APPS_INSTALL_ISOLATED_WEB_APP_FROM_COMMAND_LINE_H_
 #define CHROME_BROWSER_WEB_APPLICATIONS_ISOLATED_WEB_APPS_INSTALL_ISOLATED_WEB_APP_FROM_COMMAND_LINE_H_
 
+#include "base/callback.h"
 #include "base/types/expected.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h"
 #include "chrome/browser/web_applications/isolation_data.h"
@@ -19,8 +20,10 @@
 
 namespace web_app {
 
-base::expected<IsolatedWebAppUrlInfo, std::string> GetIsolationInfo(
-    const IsolationData& isolation_data);
+void GetIsolationInfo(
+    const IsolationData& isolation_data,
+    base::OnceCallback<void(base::expected<IsolatedWebAppUrlInfo, std::string>)>
+        callback);
 
 base::expected<absl::optional<IsolationData>, std::string>
 GetIsolationDataFromCommandLine(const base::CommandLine& command_line,
diff --git a/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_from_command_line_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_from_command_line_unittest.cc
index 5284b80..7318e0d 100644
--- a/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_from_command_line_unittest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_from_command_line_unittest.cc
@@ -4,23 +4,33 @@
 
 #include "chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_from_command_line.h"
 
+#include "base/bind.h"
 #include "base/callback.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
 #include "base/path_service.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_piece_forward.h"
 #include "base/test/bind.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
+#include "base/test/test_future.h"
+#include "base/types/expected.h"
 #include "base/values.h"
+#include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h"
 #include "chrome/browser/web_applications/isolation_data.h"
 #include "chrome/common/chrome_features.h"
 #include "components/policy/core/common/policy_pref_names.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/testing_pref_service.h"
+#include "components/web_package/signed_web_bundles/ed25519_public_key.h"
+#include "components/web_package/signed_web_bundles/signed_web_bundle_id.h"
+#include "components/web_package/test_support/signed_web_bundles/web_bundle_signer.h"
+#include "components/web_package/web_bundle_builder.h"
 #include "content/public/common/content_features.h"
+#include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -369,34 +379,132 @@
 class InstallIsolatedWebAppFromCommandLineIsolationInfoTest
     : public ::testing::Test {
  protected:
-  base::test::SingleThreadTaskEnvironment task_environment_;
+  web_package::SignedWebBundleId CreateSignedWebBundle(base::FilePath path) {
+    std::pair<std::vector<uint8_t>, web_package::SignedWebBundleId>
+        bundle_data = BuildBundle();
+    DCHECK(base::WriteFile(path, bundle_data.first));
+    return bundle_data.second;
+  }
+
+  std::pair<std::vector<uint8_t>, web_package::SignedWebBundleId>
+  BuildBundle() {
+    web_package::WebBundleSigner::KeyPair key_pair =
+        web_package::WebBundleSigner::KeyPair::CreateRandom();
+    web_package::SignedWebBundleId bundle_id =
+        web_package::SignedWebBundleId::CreateForEd25519PublicKey(
+            key_pair.public_key);
+    web_package::WebBundleBuilder builder;
+
+    builder.AddPrimaryURL("isolated-app://" + bundle_id.id());
+    builder.AddExchange("isolated-app://" + bundle_id.id(),
+                        {{":status", "200"}, {"content-type", "text/plain"}},
+                        "payload");
+
+    auto unsigned_bundle = builder.CreateBundle();
+    return {
+        web_package::WebBundleSigner::SignBundle(unsigned_bundle, {key_pair}),
+        bundle_id};
+  }
+
+  void TearDown() override {
+    task_environment_
+        .RunUntilIdle();  // because SequencedTaskRunner::DeleteSoon() is used
+                          // in SignedWebBundleReader
+    ::testing::Test::TearDown();
+  }
+
+  base::test::TaskEnvironment task_environment_;
+
+ private:
+  data_decoder::test::InProcessDataDecoder in_process_data_decoder_;
 };
 
 TEST_F(InstallIsolatedWebAppFromCommandLineIsolationInfoTest,
-       GetIsolationInfoSucceedsWhenInstalledBundle) {
+       GetIsolationInfoWhenInstalledBundleSucceeds) {
   IsolationData isolation_data =
       IsolationData{IsolationData::InstalledBundle{}};
-  base::expected<IsolatedWebAppUrlInfo, std::string> isolation_info =
-      GetIsolationInfo(isolation_data);
-  ASSERT_THAT(isolation_info.has_value(), false);
-  EXPECT_THAT(isolation_info.error(), HasSubstr("is not implemented"));
+  base::test::TestFuture<base::expected<IsolatedWebAppUrlInfo, std::string>>
+      test_future;
+
+  GetIsolationInfo(isolation_data, test_future.GetCallback());
+  base::expected<IsolatedWebAppUrlInfo, std::string> result = test_future.Get();
+
+  ASSERT_THAT(result.has_value(), false);
+  EXPECT_THAT(result.error(), HasSubstr("is not implemented"));
 }
 
 TEST_F(InstallIsolatedWebAppFromCommandLineIsolationInfoTest,
-       GetIsolationInfoSucceedsWhenDevModeBundle) {
-  IsolationData isolation_data = IsolationData{IsolationData::DevModeBundle{}};
-  base::expected<IsolatedWebAppUrlInfo, std::string> isolation_info =
-      GetIsolationInfo(isolation_data);
-  ASSERT_THAT(isolation_info.has_value(), false);
-  EXPECT_THAT(isolation_info.error(), HasSubstr("is not implemented"));
+       GetIsolationInfoWhenDevModeBundleSucceeds) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath path =
+      temp_dir.GetPath().Append(base::FilePath::FromASCII("test-0.webn"));
+  web_package::SignedWebBundleId input_bundle_id = CreateSignedWebBundle(path);
+  IsolationData isolation_data =
+      IsolationData{IsolationData::DevModeBundle{.path = path}};
+  base::test::TestFuture<base::expected<IsolatedWebAppUrlInfo, std::string>>
+      test_future;
+
+  GetIsolationInfo(isolation_data, test_future.GetCallback());
+  base::expected<IsolatedWebAppUrlInfo, std::string> result = test_future.Get();
+
+  ASSERT_THAT(result.has_value(), true);
+  EXPECT_EQ(result.value().web_bundle_id(), input_bundle_id);
+}
+
+TEST_F(InstallIsolatedWebAppFromCommandLineIsolationInfoTest,
+       GetIsolationInfoWhenDevModeBundleFailsWhenFileNotExist) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath path = temp_dir.GetPath().Append(
+      base::FilePath::FromASCII("file_not_exist.webn"));
+  IsolationData isolation_data =
+      IsolationData{IsolationData::DevModeBundle{.path = path}};
+  base::test::TestFuture<base::expected<IsolatedWebAppUrlInfo, std::string>>
+      test_future;
+
+  GetIsolationInfo(isolation_data, test_future.GetCallback());
+  base::expected<IsolatedWebAppUrlInfo, std::string> result = test_future.Get();
+
+  ASSERT_THAT(result.has_value(), false);
+  EXPECT_THAT(result.error(),
+              HasSubstr("Failed to read the integrity block of the signed web "
+                        "bundle: FILE_ERROR_NOT_FOUND"));
+}
+
+TEST_F(InstallIsolatedWebAppFromCommandLineIsolationInfoTest,
+       GetIsolationInfoWhenDevModeBundleFailsWhenInvalidFile) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath path =
+      temp_dir.GetPath().Append(base::FilePath::FromASCII("invalid_file.webn"));
+  DCHECK(
+      base::WriteFile(path, "clearly, this is not a valid signed web bundle"));
+  ASSERT_TRUE(base::PathExists(path));
+  IsolationData isolation_data =
+      IsolationData{IsolationData::DevModeBundle{.path = path}};
+  base::test::TestFuture<base::expected<IsolatedWebAppUrlInfo, std::string>>
+      test_future;
+
+  GetIsolationInfo(isolation_data, test_future.GetCallback());
+  base::expected<IsolatedWebAppUrlInfo, std::string> result = test_future.Get();
+
+  ASSERT_THAT(result.has_value(), false);
+  EXPECT_THAT(result.error(),
+              HasSubstr("Failed to read the integrity block of the signed web "
+                        "bundle: Wrong array size or magic bytes."));
 }
 
 TEST_F(InstallIsolatedWebAppFromCommandLineIsolationInfoTest,
        GetIsolationInfoSucceedsWhenDevModeProxy) {
   IsolationData isolation_data = IsolationData{IsolationData::DevModeProxy{}};
-  base::expected<IsolatedWebAppUrlInfo, std::string> isolation_info =
-      GetIsolationInfo(isolation_data);
-  EXPECT_THAT(isolation_info.has_value(), true);
+  base::test::TestFuture<base::expected<IsolatedWebAppUrlInfo, std::string>>
+      test_future;
+
+  GetIsolationInfo(isolation_data, test_future.GetCallback());
+  base::expected<IsolatedWebAppUrlInfo, std::string> result = test_future.Get();
+
+  EXPECT_THAT(result.has_value(), true);
 }
 
 }  // namespace
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
index f1268d3..0de2688 100644
--- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
+++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
@@ -332,7 +332,8 @@
 }
 
 bool ChromeWebAuthenticationDelegate::IsSecurityLevelAcceptableForWebAuthn(
-    content::RenderFrameHost* rfh) {
+    content::RenderFrameHost* rfh,
+    const url::Origin& caller_origin) {
   if (!base::FeatureList::IsEnabled(device::kDisableWebAuthnWithBrokenCerts)) {
     return true;
   }
@@ -342,6 +343,9 @@
           webauthn::pref_names::kAllowWithBrokenCerts)) {
     return true;
   }
+  if (caller_origin.scheme() == extensions::kExtensionScheme) {
+    return true;
+  }
   content::WebContents* web_contents =
       content::WebContents::FromRenderFrameHost(rfh);
   SecurityStateTabHelper::CreateForWebContents(web_contents);
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.h b/chrome/browser/webauthn/chrome_authenticator_request_delegate.h
index 9fb7c20..a47462ce 100644
--- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.h
+++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.h
@@ -68,7 +68,8 @@
       content::BrowserContext* browser_context,
       const url::Origin& caller_origin) override;
   bool IsSecurityLevelAcceptableForWebAuthn(
-      content::RenderFrameHost* rfh) override;
+      content::RenderFrameHost* rfh,
+      const url::Origin& caller_origin) override;
   absl::optional<std::string> MaybeGetRelyingPartyIdOverride(
       const std::string& claimed_relying_party_id,
       const url::Origin& caller_origin) override;
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate_unittest.cc b/chrome/browser/webauthn/chrome_authenticator_request_delegate_unittest.cc
index 15d208d..4e81d3e 100644
--- a/chrome/browser/webauthn/chrome_authenticator_request_delegate_unittest.cc
+++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate_unittest.cc
@@ -36,6 +36,7 @@
 #include "net/test/test_data_directory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
+#include "url/origin.h"
 
 #if BUILDFLAG(IS_WIN)
 #include "device/fido/win/authenticator.h"
@@ -633,7 +634,23 @@
       net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
   simulator->SetSSLInfo(std::move(ssl_info));
   simulator->Commit();
-  EXPECT_FALSE(delegate.IsSecurityLevelAcceptableForWebAuthn(main_rfh()));
+  EXPECT_FALSE(delegate.IsSecurityLevelAcceptableForWebAuthn(
+      main_rfh(), url::Origin::Create(url)));
+}
+
+TEST_F(DisableWebAuthnWithBrokenCertsTest, ExtensionSupported) {
+  GURL url("chrome-extension://extensionid");
+  ChromeWebAuthenticationDelegate delegate;
+  auto simulator =
+      content::NavigationSimulator::CreateBrowserInitiated(url, web_contents());
+  net::SSLInfo ssl_info;
+  ssl_info.cert_status = net::CERT_STATUS_DATE_INVALID;
+  ssl_info.cert =
+      net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
+  simulator->SetSSLInfo(std::move(ssl_info));
+  simulator->Commit();
+  EXPECT_TRUE(delegate.IsSecurityLevelAcceptableForWebAuthn(
+      main_rfh(), url::Origin::Create(url)));
 }
 
 TEST_F(DisableWebAuthnWithBrokenCertsTest, EnterpriseOverride) {
@@ -650,7 +667,8 @@
       net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
   simulator->SetSSLInfo(std::move(ssl_info));
   simulator->Commit();
-  EXPECT_TRUE(delegate.IsSecurityLevelAcceptableForWebAuthn(main_rfh()));
+  EXPECT_TRUE(delegate.IsSecurityLevelAcceptableForWebAuthn(
+      main_rfh(), url::Origin::Create(url)));
 }
 
 TEST_F(DisableWebAuthnWithBrokenCertsTest, SecurityLevelAcceptable) {
@@ -664,7 +682,8 @@
       net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
   simulator->SetSSLInfo(std::move(ssl_info));
   simulator->Commit();
-  EXPECT_TRUE(delegate.IsSecurityLevelAcceptableForWebAuthn(main_rfh()));
+  EXPECT_TRUE(delegate.IsSecurityLevelAcceptableForWebAuthn(
+      main_rfh(), url::Origin::Create(url)));
 }
 
 }  // namespace
diff --git a/chrome/browser/webauthn/chrome_webauthn_browsertest.cc b/chrome/browser/webauthn/chrome_webauthn_browsertest.cc
index b48855b..54c73f0f 100644
--- a/chrome/browser/webauthn/chrome_webauthn_browsertest.cc
+++ b/chrome/browser/webauthn/chrome_webauthn_browsertest.cc
@@ -79,11 +79,7 @@
     host_resolver()->AddRule("*", "127.0.0.1");
 
     // Allowlist all certs for the HTTPS server.
-    auto cert = https_server_.GetCertificate();
-    net::CertVerifyResult verify_result;
-    verify_result.cert_status = 0;
-    verify_result.verified_cert = cert;
-    mock_cert_verifier()->AddResultForCert(cert.get(), verify_result, net::OK);
+    mock_cert_verifier()->set_default_result(net::OK);
   }
 
  protected:
diff --git a/chrome/browser/window_management/screen_details_browsertest.cc b/chrome/browser/window_management/screen_details_browsertest.cc
index 46217e2..96f4ab7 100644
--- a/chrome/browser/window_management/screen_details_browsertest.cc
+++ b/chrome/browser/window_management/screen_details_browsertest.cc
@@ -2,14 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/browser/devtools/devtools_window_testing.h"
+#include "chrome/browser/ui/browser.h"
 #include "chrome/test/base/chrome_test_utils.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/permissions/permission_request_manager.h"
 #include "content/browser/screen_enumeration/screen_details_test_utils.h"
+#include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
+#include "third_party/blink/public/common/features.h"
 
 using ScreenDetailsTest = InProcessBrowserTest;
 
@@ -32,3 +36,88 @@
       EvalJs(tab, content::test::kGetScreenDetailsScript);
   EXPECT_EQ(content::test::GetExpectedScreenDetails(), result.value);
 }
+
+class ScreenDetailsFullscreenScreenSizeTest
+    : public ScreenDetailsTest,
+      public testing::WithParamInterface<bool> {
+ public:
+  ScreenDetailsFullscreenScreenSizeTest() {
+    scoped_feature_list_.InitWithFeatureState(
+        blink::features::kFullscreenScreenSizeMatchesDisplay,
+        FullscreenScreenSizeMatchesDisplayEnabled());
+  }
+  bool FullscreenScreenSizeMatchesDisplayEnabled() { return GetParam(); }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+INSTANTIATE_TEST_SUITE_P(All,
+                         ScreenDetailsFullscreenScreenSizeTest,
+                         testing::Bool());
+
+// Test screen size in fullscreen. ScreenDetailed always yields display metrics,
+// but `window.screen` may yield smaller viewport dimensions while the frame is
+// fullscreen as a speculative site compatibility measure, because web authors
+// may assume that screen dimensions match window.innerWidth/innerHeight while a
+// page is fullscreen, but that is not always true. crbug.com/1367416
+// TODO(crbug.com/1119974): Need content_browsertests permission controls.
+IN_PROC_BROWSER_TEST_P(ScreenDetailsFullscreenScreenSizeTest, FullscreenSize) {
+  auto* tab = chrome_test_utils::GetActiveWebContents(this);
+  ASSERT_TRUE(embedded_test_server()->Start());
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(
+      browser(), embedded_test_server()->GetURL("/empty.html")));
+
+  // Auto-accept the permission request.
+  permissions::PermissionRequestManager::FromWebContents(tab)
+      ->set_auto_response_for_test(
+          permissions::PermissionRequestManager::ACCEPT_ALL);
+
+  constexpr char kGetCurrentScreenSizeScript[] = R"JS(
+    window.getScreenDetails().then(sD => {
+        return `${sD.currentScreen.width}x${sD.currentScreen.height}`;
+    });
+  )JS";
+
+  // Check initial dimensions before entering fullscreen.
+  ASSERT_FALSE(tab->IsFullscreen());
+  const std::string display_size =
+      tab->GetRenderWidgetHostView()->GetScreenInfo().rect.size().ToString();
+  EXPECT_EQ(display_size, EvalJs(tab, "`${screen.width}x${screen.height}`"));
+  EXPECT_NE(display_size, EvalJs(tab, "`${innerWidth}x${innerHeight}`"));
+  EXPECT_EQ(display_size, EvalJs(tab, kGetCurrentScreenSizeScript));
+
+  // Enter fullscreen; and show docked devtools, which shrinks the content area.
+  constexpr char kEnterFullscreenScript[] = R"JS(
+    document.documentElement.requestFullscreen().then(() => {
+        return !!document.fullscreenElement;
+    });
+  )JS";
+  ASSERT_TRUE(EvalJs(tab, kEnterFullscreenScript).ExtractBool());
+  ASSERT_TRUE(tab->IsFullscreen());
+  DevToolsWindow* dev_tools_window =
+      DevToolsWindowTesting::OpenDevToolsWindowSync(tab, true);
+  ASSERT_TRUE(tab->IsFullscreen());
+  if (FullscreenScreenSizeMatchesDisplayEnabled()) {
+    // `window.screen` dimensions match the display size.
+    EXPECT_EQ(display_size, EvalJs(tab, "`${screen.width}x${screen.height}`"));
+  } else {
+    // `window.screen` dimensions match the smaller viewport size.
+    EXPECT_NE(display_size, EvalJs(tab, "`${screen.width}x${screen.height}`"));
+  }
+  EXPECT_NE(display_size, EvalJs(tab, "`${innerWidth}x${innerHeight}`"));
+  EXPECT_EQ(display_size, EvalJs(tab, kGetCurrentScreenSizeScript));
+
+  // Check dimensions again after exiting fullscreen and closing dev tools.
+  DevToolsWindowTesting::CloseDevToolsWindowSync(dev_tools_window);
+  constexpr char kExitFullscreenScript[] = R"JS(
+    document.exitFullscreen().then(() => {
+        return !document.fullscreenElement;
+    });
+  )JS";
+  ASSERT_TRUE(EvalJs(tab, kExitFullscreenScript).ExtractBool());
+  ASSERT_FALSE(tab->IsFullscreen());
+  EXPECT_EQ(display_size, EvalJs(tab, "`${screen.width}x${screen.height}`"));
+  EXPECT_NE(display_size, EvalJs(tab, "`${innerWidth}x${innerHeight}`"));
+  EXPECT_EQ(display_size, EvalJs(tab, kGetCurrentScreenSizeScript));
+}
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 78559a8f8..3c2318b2 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1669052379-0db4490b297ef571c169300f9ae958f9623dea28.profdata
+chrome-mac-main-1669075030-b6c517aaf7fcdb56dd96db53064a6fad987648f8.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index b273ed0..33016e9 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1669042776-901bce6dc7880edbf227ab7d1793b8aabb385ce3.profdata
+chrome-win32-main-1669052379-ed4e1927fb4c3372babbbba7ae1d10dd6fe9a454.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 0a68a40..7c4c6b3 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1669042776-b54a09cb0595c1ae028823ca4c0bc555dbf84d5d.profdata
+chrome-win64-main-1669052379-aff84406a097833821a4a1c0cd18bde5494c3d6f.profdata
diff --git a/chrome/common/extensions/api/action.json b/chrome/common/extensions/api/action.json
index 0dd9fdf3..2ba891c 100644
--- a/chrome/common/extensions/api/action.json
+++ b/chrome/common/extensions/api/action.json
@@ -250,8 +250,6 @@
       }
     }, {
       "name": "setBadgeTextColor",
-      // TODO(https://crbug.com/1337783): Remove once on stable channel.
-      "nodoc": "true",
       "type": "function",
       "description": "Sets the text color for the badge.",
       "parameters": [
@@ -286,8 +284,6 @@
       }
     }, {
       "name": "getBadgeTextColor",
-      // TODO(https://crbug.com/1337783): Remove once on stable channel.
-      "nodoc": "true",
       "type": "function",
       "description": "Gets the text color of the action.",
       "parameters": [
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 8b8a8fa..b64923f 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -1939,6 +1939,9 @@
 // DefaultHandlersForFileExtensions policy.
 const char kDefaultHandlersForFileExtensions[] =
     "filebrowser.default_handlers_for_file_extensions";
+
+// Whether the office files setup flow has ever been completed by the user.
+const char kOfficeSetupComplete[] = "filebrowser.office.setup_complete";
 #endif
 
 // A flag to enable/disable the Shared Clipboard feature which enables users to
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index afed232..86028dca 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -636,6 +636,7 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 extern const char kDefaultHandlersForFileExtensions[];
+extern const char kOfficeSetupComplete[];
 #endif
 
 extern const char kSharedClipboardEnabled[];
diff --git a/chrome/common/printing/print_media_l10n.cc b/chrome/common/printing/print_media_l10n.cc
index a422da4..7944acf 100644
--- a/chrome/common/printing/print_media_l10n.cc
+++ b/chrome/common/printing/print_media_l10n.cc
@@ -28,426 +28,563 @@
 // group. The static map contained here is intended to reach all translated
 // media names - see print_media_resources.grd.
 MediaSizeInfo InfoForVendorId(const std::string& vendor_id) {
-  using MediaSizeGroup::kSizeIn;
-  using MediaSizeGroup::kSizeMm;
-  using MediaSizeGroup::kSizeNamed;
-
   static const base::NoDestructor<
       std::map<std::string, std::pair<int, MediaSizeGroup>>>
       media_map({
-          {"asme_f_28x40in", {PRINT_PREVIEW_MEDIA_ASME_F_28X40IN, kSizeIn}},
+          {"asme_f_28x40in",
+           {PRINT_PREVIEW_MEDIA_ASME_F_28X40IN, MediaSizeGroup::kSizeIn}},
           {"iso_2a0_1189x1682mm",
-           {PRINT_PREVIEW_MEDIA_ISO_2A0_1189X1682MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_2A0_1189X1682MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_a0_841x1189mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A0_841X1189MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A0_841X1189MM, MediaSizeGroup::kSizeNamed}},
           {"iso_a0x3_1189x2523mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A0X3_1189X2523MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A0X3_1189X2523MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_a10_26x37mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A10_26X37MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A10_26X37MM, MediaSizeGroup::kSizeNamed}},
           {"iso_a1_594x841mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A1_594X841MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A1_594X841MM, MediaSizeGroup::kSizeNamed}},
           {"iso_a1x3_841x1783mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A1X3_841X1783MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A1X3_841X1783MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_a1x4_841x2378mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A1X4_841X2378MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A1X4_841X2378MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_a2_420x594mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A2_420X594MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A2_420X594MM, MediaSizeGroup::kSizeNamed}},
           {"iso_a2x3_594x1261mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A2X3_594X1261MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A2X3_594X1261MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_a2x4_594x1682mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A2X4_594X1682MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A2X4_594X1682MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_a2x5_594x2102mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A2X5_594X2102MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A2X5_594X2102MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_a3-extra_322x445mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A3_EXTRA_322X445MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A3_EXTRA_322X445MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_a3_297x420mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A3_297X420MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A3_297X420MM, MediaSizeGroup::kSizeNamed}},
           {"iso_a3x3_420x891mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A3X3_420X891MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A3X3_420X891MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_a3x4_420x1189mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A3X4_420X1189MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A3X4_420X1189MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_a3x5_420x1486mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A3X5_420X1486MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A3X5_420X1486MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_a3x6_420x1783mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A3X6_420X1783MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A3X6_420X1783MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_a3x7_420x2080mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A3X7_420X2080MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A3X7_420X2080MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_a4-extra_235.5x322.3mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A4_EXTRA_235_5X322_3MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A4_EXTRA_235_5X322_3MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_a4-tab_225x297mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A4_TAB_225X297MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A4_TAB_225X297MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_a4_210x297mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A4_210X297MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A4_210X297MM, MediaSizeGroup::kSizeNamed}},
           {"iso_a4x3_297x630mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A4X3_297X630MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A4X3_297X630MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_a4x4_297x841mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A4X4_297X841MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A4X4_297X841MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_a4x5_297x1051mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A4X5_297X1051MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A4X5_297X1051MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_a4x6_297x1261mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A4X6_297X1261MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A4X6_297X1261MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_a4x7_297x1471mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A4X7_297X1471MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A4X7_297X1471MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_a4x8_297x1682mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A4X8_297X1682MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A4X8_297X1682MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_a4x9_297x1892mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A4X9_297X1892MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A4X9_297X1892MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_a5-extra_174x235mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A5_EXTRA_174X235MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A5_EXTRA_174X235MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_a5_148x210mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A5_148X210MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A5_148X210MM, MediaSizeGroup::kSizeNamed}},
           {"iso_a6_105x148mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A6_105X148MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A6_105X148MM, MediaSizeGroup::kSizeNamed}},
           {"iso_a7_74x105mm",
-           {PRINT_PREVIEW_MEDIA_ISO_A7_74X105MM, kSizeNamed}},
-          {"iso_a8_52x74mm", {PRINT_PREVIEW_MEDIA_ISO_A8_52X74MM, kSizeNamed}},
-          {"iso_a9_37x52mm", {PRINT_PREVIEW_MEDIA_ISO_A9_37X52MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_A7_74X105MM, MediaSizeGroup::kSizeNamed}},
+          {"iso_a8_52x74mm",
+           {PRINT_PREVIEW_MEDIA_ISO_A8_52X74MM, MediaSizeGroup::kSizeNamed}},
+          {"iso_a9_37x52mm",
+           {PRINT_PREVIEW_MEDIA_ISO_A9_37X52MM, MediaSizeGroup::kSizeNamed}},
           {"iso_b0_1000x1414mm",
-           {PRINT_PREVIEW_MEDIA_ISO_B0_1000X1414MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_B0_1000X1414MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_b10_31x44mm",
-           {PRINT_PREVIEW_MEDIA_ISO_B10_31X44MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_B10_31X44MM, MediaSizeGroup::kSizeNamed}},
           {"iso_b1_707x1000mm",
-           {PRINT_PREVIEW_MEDIA_ISO_B1_707X1000MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_B1_707X1000MM, MediaSizeGroup::kSizeNamed}},
           {"iso_b2_500x707mm",
-           {PRINT_PREVIEW_MEDIA_ISO_B2_500X707MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_B2_500X707MM, MediaSizeGroup::kSizeNamed}},
           {"iso_b3_353x500mm",
-           {PRINT_PREVIEW_MEDIA_ISO_B3_353X500MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_B3_353X500MM, MediaSizeGroup::kSizeNamed}},
           {"iso_b4_250x353mm",
-           {PRINT_PREVIEW_MEDIA_ISO_B4_250X353MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_B4_250X353MM, MediaSizeGroup::kSizeNamed}},
           {"iso_b5-extra_201x276mm",
-           {PRINT_PREVIEW_MEDIA_ISO_B5_EXTRA_201X276MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_B5_EXTRA_201X276MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_b5_176x250mm",
-           {PRINT_PREVIEW_MEDIA_ISO_B5_176X250MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_B5_176X250MM, MediaSizeGroup::kSizeNamed}},
           {"iso_b6_125x176mm",
-           {PRINT_PREVIEW_MEDIA_ISO_B6_125X176MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_B6_125X176MM, MediaSizeGroup::kSizeNamed}},
           {"iso_b6c4_125x324mm",
-           {PRINT_PREVIEW_MEDIA_ISO_B6C4_125X324MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_B6C4_125X324MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_b7_88x125mm",
-           {PRINT_PREVIEW_MEDIA_ISO_B7_88X125MM, kSizeNamed}},
-          {"iso_b8_62x88mm", {PRINT_PREVIEW_MEDIA_ISO_B8_62X88MM, kSizeNamed}},
-          {"iso_b9_44x62mm", {PRINT_PREVIEW_MEDIA_ISO_B9_44X62MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_B7_88X125MM, MediaSizeGroup::kSizeNamed}},
+          {"iso_b8_62x88mm",
+           {PRINT_PREVIEW_MEDIA_ISO_B8_62X88MM, MediaSizeGroup::kSizeNamed}},
+          {"iso_b9_44x62mm",
+           {PRINT_PREVIEW_MEDIA_ISO_B9_44X62MM, MediaSizeGroup::kSizeNamed}},
           {"iso_c0_917x1297mm",
-           {PRINT_PREVIEW_MEDIA_ISO_C0_917X1297MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_C0_917X1297MM, MediaSizeGroup::kSizeNamed}},
           {"iso_c10_28x40mm",
-           {PRINT_PREVIEW_MEDIA_ISO_C10_28X40MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_C10_28X40MM, MediaSizeGroup::kSizeNamed}},
           {"iso_c1_648x917mm",
-           {PRINT_PREVIEW_MEDIA_ISO_C1_648X917MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_C1_648X917MM, MediaSizeGroup::kSizeNamed}},
           {"iso_c2_458x648mm",
-           {PRINT_PREVIEW_MEDIA_ISO_C2_458X648MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_C2_458X648MM, MediaSizeGroup::kSizeNamed}},
           {"iso_c3_324x458mm",
-           {PRINT_PREVIEW_MEDIA_ISO_C3_324X458MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_C3_324X458MM, MediaSizeGroup::kSizeNamed}},
           {"iso_c4_229x324mm",
-           {PRINT_PREVIEW_MEDIA_ISO_C4_229X324MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_C4_229X324MM, MediaSizeGroup::kSizeNamed}},
           {"iso_c5_162x229mm",
-           {PRINT_PREVIEW_MEDIA_ISO_C5_162X229MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_C5_162X229MM, MediaSizeGroup::kSizeNamed}},
           {"iso_c6_114x162mm",
-           {PRINT_PREVIEW_MEDIA_ISO_C6_114X162MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_C6_114X162MM, MediaSizeGroup::kSizeNamed}},
           {"iso_c6c5_114x229mm",
-           {PRINT_PREVIEW_MEDIA_ISO_C6C5_114X229MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_C6C5_114X229MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_c7_81x114mm",
-           {PRINT_PREVIEW_MEDIA_ISO_C7_81X114MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_C7_81X114MM, MediaSizeGroup::kSizeNamed}},
           {"iso_c7c6_81x162mm",
-           {PRINT_PREVIEW_MEDIA_ISO_C7C6_81X162MM, kSizeNamed}},
-          {"iso_c8_57x81mm", {PRINT_PREVIEW_MEDIA_ISO_C8_57X81MM, kSizeNamed}},
-          {"iso_c9_40x57mm", {PRINT_PREVIEW_MEDIA_ISO_C9_40X57MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_C7C6_81X162MM, MediaSizeGroup::kSizeNamed}},
+          {"iso_c8_57x81mm",
+           {PRINT_PREVIEW_MEDIA_ISO_C8_57X81MM, MediaSizeGroup::kSizeNamed}},
+          {"iso_c9_40x57mm",
+           {PRINT_PREVIEW_MEDIA_ISO_C9_40X57MM, MediaSizeGroup::kSizeNamed}},
           {"iso_dl_110x220mm",
-           {PRINT_PREVIEW_MEDIA_ISO_DL_110X220MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_DL_110X220MM, MediaSizeGroup::kSizeNamed}},
           {"iso_id-1_53.98x85.6mm",
-           {PRINT_PREVIEW_MEDIA_ISO_ID_1_53_98X85_6MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_ID_1_53_98X85_6MM,
+            MediaSizeGroup::kSizeNamed}},
           // Duplicate of iso_b7_88x125mm.
           {"iso_id-3_88x125mm",
-           {PRINT_PREVIEW_MEDIA_ISO_B7_88X125MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_B7_88X125MM, MediaSizeGroup::kSizeNamed}},
           {"iso_ra0_860x1220mm",
-           {PRINT_PREVIEW_MEDIA_ISO_RA0_860X1220MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_RA0_860X1220MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_ra1_610x860mm",
-           {PRINT_PREVIEW_MEDIA_ISO_RA1_610X860MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_RA1_610X860MM, MediaSizeGroup::kSizeNamed}},
           {"iso_ra2_430x610mm",
-           {PRINT_PREVIEW_MEDIA_ISO_RA2_430X610MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_RA2_430X610MM, MediaSizeGroup::kSizeNamed}},
           {"iso_ra3_305x430mm",
-           {PRINT_PREVIEW_MEDIA_ISO_RA3_305X430MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_RA3_305X430MM, MediaSizeGroup::kSizeNamed}},
           {"iso_ra4_215x305mm",
-           {PRINT_PREVIEW_MEDIA_ISO_RA4_215X305MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_RA4_215X305MM, MediaSizeGroup::kSizeNamed}},
           {"iso_sra0_900x1280mm",
-           {PRINT_PREVIEW_MEDIA_ISO_SRA0_900X1280MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_SRA0_900X1280MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_sra1_640x900mm",
-           {PRINT_PREVIEW_MEDIA_ISO_SRA1_640X900MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_SRA1_640X900MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_sra2_450x640mm",
-           {PRINT_PREVIEW_MEDIA_ISO_SRA2_450X640MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_SRA2_450X640MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_sra3_320x450mm",
-           {PRINT_PREVIEW_MEDIA_ISO_SRA3_320X450MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_SRA3_320X450MM,
+            MediaSizeGroup::kSizeNamed}},
           {"iso_sra4_225x320mm",
-           {PRINT_PREVIEW_MEDIA_ISO_SRA4_225X320MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_SRA4_225X320MM,
+            MediaSizeGroup::kSizeNamed}},
           {"jis_b0_1030x1456mm",
-           {PRINT_PREVIEW_MEDIA_JIS_B0_1030X1456MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_JIS_B0_1030X1456MM,
+            MediaSizeGroup::kSizeNamed}},
           {"jis_b1_728x1030mm",
-           {PRINT_PREVIEW_MEDIA_JIS_B1_728X1030MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_JIS_B1_728X1030MM, MediaSizeGroup::kSizeNamed}},
           {"jis_b2_515x728mm",
-           {PRINT_PREVIEW_MEDIA_JIS_B2_515X728MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_JIS_B2_515X728MM, MediaSizeGroup::kSizeNamed}},
           {"jis_b3_364x515mm",
-           {PRINT_PREVIEW_MEDIA_JIS_B3_364X515MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_JIS_B3_364X515MM, MediaSizeGroup::kSizeNamed}},
           {"jis_b4_257x364mm",
-           {PRINT_PREVIEW_MEDIA_JIS_B4_257X364MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_JIS_B4_257X364MM, MediaSizeGroup::kSizeNamed}},
           {"jis_b5_182x257mm",
-           {PRINT_PREVIEW_MEDIA_JIS_B5_182X257MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_JIS_B5_182X257MM, MediaSizeGroup::kSizeNamed}},
           {"jis_b6_128x182mm",
-           {PRINT_PREVIEW_MEDIA_JIS_B6_128X182MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_JIS_B6_128X182MM, MediaSizeGroup::kSizeNamed}},
           {"jis_b7_91x128mm",
-           {PRINT_PREVIEW_MEDIA_JIS_B7_91X128MM, kSizeNamed}},
-          {"jis_b8_64x91mm", {PRINT_PREVIEW_MEDIA_JIS_B8_64X91MM, kSizeNamed}},
-          {"jis_b9_45x64mm", {PRINT_PREVIEW_MEDIA_JIS_B9_45X64MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_JIS_B7_91X128MM, MediaSizeGroup::kSizeNamed}},
+          {"jis_b8_64x91mm",
+           {PRINT_PREVIEW_MEDIA_JIS_B8_64X91MM, MediaSizeGroup::kSizeNamed}},
+          {"jis_b9_45x64mm",
+           {PRINT_PREVIEW_MEDIA_JIS_B9_45X64MM, MediaSizeGroup::kSizeNamed}},
           {"jis_b10_32x45mm",
-           {PRINT_PREVIEW_MEDIA_JIS_B10_32X45MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_JIS_B10_32X45MM, MediaSizeGroup::kSizeNamed}},
           {"jis_exec_216x330mm",
-           {PRINT_PREVIEW_MEDIA_JIS_EXEC_216X330MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_JIS_EXEC_216X330MM,
+            MediaSizeGroup::kSizeNamed}},
           {"jpn_chou2_111.1x146mm",
-           {PRINT_PREVIEW_MEDIA_JPN_CHOU2_111_1X146MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_JPN_CHOU2_111_1X146MM,
+            MediaSizeGroup::kSizeNamed}},
           {"jpn_chou3_120x235mm",
-           {PRINT_PREVIEW_MEDIA_JPN_CHOU3_120X235MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_JPN_CHOU3_120X235MM,
+            MediaSizeGroup::kSizeNamed}},
           {"jpn_chou4_90x205mm",
-           {PRINT_PREVIEW_MEDIA_JPN_CHOU4_90X205MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_JPN_CHOU4_90X205MM,
+            MediaSizeGroup::kSizeNamed}},
           {"jpn_chou40_90x225mm",
-           {PRINT_PREVIEW_MEDIA_JPN_CHOU40_90X225MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_JPN_CHOU40_90X225MM,
+            MediaSizeGroup::kSizeNamed}},
           {"jpn_hagaki_100x148mm",
-           {PRINT_PREVIEW_MEDIA_JPN_HAGAKI_100X148MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_JPN_HAGAKI_100X148MM,
+            MediaSizeGroup::kSizeNamed}},
           {"jpn_kahu_240x322.1mm",
-           {PRINT_PREVIEW_MEDIA_JPN_KAHU_240X322_1MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_JPN_KAHU_240X322_1MM,
+            MediaSizeGroup::kSizeNamed}},
           {"jpn_kaku1_270x382mm",
-           {PRINT_PREVIEW_MEDIA_JPN_KAKU1_270X382MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_JPN_KAKU1_270X382MM,
+            MediaSizeGroup::kSizeNamed}},
           {"jpn_kaku2_240x332mm",
-           {PRINT_PREVIEW_MEDIA_JPN_KAKU2_240X332MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_JPN_KAKU2_240X332MM,
+            MediaSizeGroup::kSizeNamed}},
           {"jpn_kaku3_216x277mm",
-           {PRINT_PREVIEW_MEDIA_JPN_KAKU3_216X277MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_JPN_KAKU3_216X277MM,
+            MediaSizeGroup::kSizeNamed}},
           {"jpn_kaku4_197x267mm",
-           {PRINT_PREVIEW_MEDIA_JPN_KAKU4_197X267MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_JPN_KAKU4_197X267MM,
+            MediaSizeGroup::kSizeNamed}},
           {"jpn_kaku5_190x240mm",
-           {PRINT_PREVIEW_MEDIA_JPN_KAKU5_190X240MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_JPN_KAKU5_190X240MM,
+            MediaSizeGroup::kSizeNamed}},
           {"jpn_kaku7_142x205mm",
-           {PRINT_PREVIEW_MEDIA_JPN_KAKU7_142X205MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_JPN_KAKU7_142X205MM,
+            MediaSizeGroup::kSizeNamed}},
           {"jpn_kaku8_119x197mm",
-           {PRINT_PREVIEW_MEDIA_JPN_KAKU8_119X197MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_JPN_KAKU8_119X197MM,
+            MediaSizeGroup::kSizeNamed}},
           {"jpn_oufuku_148x200mm",
-           {PRINT_PREVIEW_MEDIA_JPN_OUFUKU_148X200MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_JPN_OUFUKU_148X200MM,
+            MediaSizeGroup::kSizeNamed}},
           {"jpn_you4_105x235mm",
-           {PRINT_PREVIEW_MEDIA_JPN_YOU4_105X235MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_JPN_YOU4_105X235MM,
+            MediaSizeGroup::kSizeNamed}},
           {"jpn_you6_98x190mm",
-           {PRINT_PREVIEW_MEDIA_JPN_YOU6_98X190MM, kSizeNamed}},
-          {"na_10x11_10x11in", {PRINT_PREVIEW_MEDIA_NA_10X11_10X11IN, kSizeIn}},
-          {"na_10x13_10x13in", {PRINT_PREVIEW_MEDIA_NA_10X13_10X13IN, kSizeIn}},
-          {"na_10x14_10x14in", {PRINT_PREVIEW_MEDIA_NA_10X14_10X14IN, kSizeIn}},
-          {"na_10x15_10x15in", {PRINT_PREVIEW_MEDIA_NA_10X15_10X15IN, kSizeIn}},
-          {"na_11x12_11x12in", {PRINT_PREVIEW_MEDIA_NA_11X12_11X12IN, kSizeIn}},
-          {"na_11x15_11x15in", {PRINT_PREVIEW_MEDIA_NA_11X15_11X15IN, kSizeIn}},
-          {"na_12x19_12x19in", {PRINT_PREVIEW_MEDIA_NA_12X19_12X19IN, kSizeIn}},
-          {"na_5x7_5x7in", {PRINT_PREVIEW_MEDIA_NA_5X7_5X7IN, kSizeIn}},
-          {"na_6x9_6x9in", {PRINT_PREVIEW_MEDIA_NA_6X9_6X9IN, kSizeNamed}},
-          {"na_7x9_7x9in", {PRINT_PREVIEW_MEDIA_NA_7X9_7X9IN, kSizeNamed}},
-          {"na_9x11_9x11in", {PRINT_PREVIEW_MEDIA_NA_9X11_9X11IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_JPN_YOU6_98X190MM, MediaSizeGroup::kSizeNamed}},
+          {"na_10x11_10x11in",
+           {PRINT_PREVIEW_MEDIA_NA_10X11_10X11IN, MediaSizeGroup::kSizeIn}},
+          {"na_10x13_10x13in",
+           {PRINT_PREVIEW_MEDIA_NA_10X13_10X13IN, MediaSizeGroup::kSizeIn}},
+          {"na_10x14_10x14in",
+           {PRINT_PREVIEW_MEDIA_NA_10X14_10X14IN, MediaSizeGroup::kSizeIn}},
+          {"na_10x15_10x15in",
+           {PRINT_PREVIEW_MEDIA_NA_10X15_10X15IN, MediaSizeGroup::kSizeIn}},
+          {"na_11x12_11x12in",
+           {PRINT_PREVIEW_MEDIA_NA_11X12_11X12IN, MediaSizeGroup::kSizeIn}},
+          {"na_11x15_11x15in",
+           {PRINT_PREVIEW_MEDIA_NA_11X15_11X15IN, MediaSizeGroup::kSizeIn}},
+          {"na_12x19_12x19in",
+           {PRINT_PREVIEW_MEDIA_NA_12X19_12X19IN, MediaSizeGroup::kSizeIn}},
+          {"na_5x7_5x7in",
+           {PRINT_PREVIEW_MEDIA_NA_5X7_5X7IN, MediaSizeGroup::kSizeIn}},
+          {"na_6x9_6x9in",
+           {PRINT_PREVIEW_MEDIA_NA_6X9_6X9IN, MediaSizeGroup::kSizeNamed}},
+          {"na_7x9_7x9in",
+           {PRINT_PREVIEW_MEDIA_NA_7X9_7X9IN, MediaSizeGroup::kSizeNamed}},
+          {"na_9x11_9x11in",
+           {PRINT_PREVIEW_MEDIA_NA_9X11_9X11IN, MediaSizeGroup::kSizeNamed}},
           {"na_a2_4.375x5.75in",
-           {PRINT_PREVIEW_MEDIA_NA_A2_4_375X5_75IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_NA_A2_4_375X5_75IN,
+            MediaSizeGroup::kSizeNamed}},
           {"na_arch-a_9x12in",
-           {PRINT_PREVIEW_MEDIA_NA_ARCH_A_9X12IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_NA_ARCH_A_9X12IN, MediaSizeGroup::kSizeNamed}},
           {"na_arch-b_12x18in",
-           {PRINT_PREVIEW_MEDIA_NA_ARCH_B_12X18IN, kSizeIn}},
+           {PRINT_PREVIEW_MEDIA_NA_ARCH_B_12X18IN, MediaSizeGroup::kSizeIn}},
           {"na_arch-c_18x24in",
-           {PRINT_PREVIEW_MEDIA_NA_ARCH_C_18X24IN, kSizeIn}},
+           {PRINT_PREVIEW_MEDIA_NA_ARCH_C_18X24IN, MediaSizeGroup::kSizeIn}},
           {"na_arch-d_24x36in",
-           {PRINT_PREVIEW_MEDIA_NA_ARCH_D_24X36IN, kSizeIn}},
+           {PRINT_PREVIEW_MEDIA_NA_ARCH_D_24X36IN, MediaSizeGroup::kSizeIn}},
           {"na_arch-e_36x48in",
-           {PRINT_PREVIEW_MEDIA_NA_ARCH_E_36X48IN, kSizeIn}},
+           {PRINT_PREVIEW_MEDIA_NA_ARCH_E_36X48IN, MediaSizeGroup::kSizeIn}},
           {"na_arch-e2_26x38in",
-           {PRINT_PREVIEW_MEDIA_NA_ARCH_E2_26X38IN, kSizeIn}},
+           {PRINT_PREVIEW_MEDIA_NA_ARCH_E2_26X38IN, MediaSizeGroup::kSizeIn}},
           {"na_arch-e3_27x39in",
-           {PRINT_PREVIEW_MEDIA_NA_ARCH_E3_27X39IN, kSizeIn}},
+           {PRINT_PREVIEW_MEDIA_NA_ARCH_E3_27X39IN, MediaSizeGroup::kSizeIn}},
           {"na_b-plus_12x19.17in",
-           {PRINT_PREVIEW_MEDIA_NA_B_PLUS_12X19_17IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_NA_B_PLUS_12X19_17IN,
+            MediaSizeGroup::kSizeNamed}},
           {"na_c5_6.5x9.5in",
-           {PRINT_PREVIEW_MEDIA_NA_C5_6_5X9_5IN, kSizeNamed}},
-          {"na_c_17x22in", {PRINT_PREVIEW_MEDIA_NA_C_17X22IN, kSizeIn}},
-          {"na_d_22x34in", {PRINT_PREVIEW_MEDIA_NA_D_22X34IN, kSizeIn}},
-          {"na_e_34x44in", {PRINT_PREVIEW_MEDIA_NA_E_34X44IN, kSizeIn}},
-          {"na_edp_11x14in", {PRINT_PREVIEW_MEDIA_NA_EDP_11X14IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_NA_C5_6_5X9_5IN, MediaSizeGroup::kSizeNamed}},
+          {"na_c_17x22in",
+           {PRINT_PREVIEW_MEDIA_NA_C_17X22IN, MediaSizeGroup::kSizeIn}},
+          {"na_d_22x34in",
+           {PRINT_PREVIEW_MEDIA_NA_D_22X34IN, MediaSizeGroup::kSizeIn}},
+          {"na_e_34x44in",
+           {PRINT_PREVIEW_MEDIA_NA_E_34X44IN, MediaSizeGroup::kSizeIn}},
+          {"na_edp_11x14in",
+           {PRINT_PREVIEW_MEDIA_NA_EDP_11X14IN, MediaSizeGroup::kSizeNamed}},
           {"na_eur-edp_12x14in",
-           {PRINT_PREVIEW_MEDIA_NA_EUR_EDP_12X14IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_NA_EUR_EDP_12X14IN,
+            MediaSizeGroup::kSizeNamed}},
           {"na_executive_7.25x10.5in",
-           {PRINT_PREVIEW_MEDIA_NA_EXECUTIVE_7_25X10_5IN, kSizeNamed}},
-          {"na_f_44x68in", {PRINT_PREVIEW_MEDIA_NA_F_44X68IN, kSizeIn}},
+           {PRINT_PREVIEW_MEDIA_NA_EXECUTIVE_7_25X10_5IN,
+            MediaSizeGroup::kSizeNamed}},
+          {"na_f_44x68in",
+           {PRINT_PREVIEW_MEDIA_NA_F_44X68IN, MediaSizeGroup::kSizeIn}},
           {"na_fanfold-eur_8.5x12in",
-           {PRINT_PREVIEW_MEDIA_NA_FANFOLD_EUR_8_5X12IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_NA_FANFOLD_EUR_8_5X12IN,
+            MediaSizeGroup::kSizeNamed}},
           {"na_fanfold-us_11x14.875in",
-           {PRINT_PREVIEW_MEDIA_NA_FANFOLD_US_11X14_875IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_NA_FANFOLD_US_11X14_875IN,
+            MediaSizeGroup::kSizeNamed}},
           {"na_foolscap_8.5x13in",
-           {PRINT_PREVIEW_MEDIA_NA_FOOLSCAP_8_5X13IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_NA_FOOLSCAP_8_5X13IN,
+            MediaSizeGroup::kSizeNamed}},
           {"na_govt-legal_8x13in",
-           {PRINT_PREVIEW_MEDIA_NA_GOVT_LEGAL_8X13IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_NA_GOVT_LEGAL_8X13IN,
+            MediaSizeGroup::kSizeNamed}},
           {"na_govt-letter_8x10in",
-           {PRINT_PREVIEW_MEDIA_NA_GOVT_LETTER_8X10IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_NA_GOVT_LETTER_8X10IN,
+            MediaSizeGroup::kSizeNamed}},
           {"na_index-3x5_3x5in",
-           {PRINT_PREVIEW_MEDIA_NA_INDEX_3X5_3X5IN, kSizeIn}},
+           {PRINT_PREVIEW_MEDIA_NA_INDEX_3X5_3X5IN, MediaSizeGroup::kSizeIn}},
           {"na_index-4x6-ext_6x8in",
-           {PRINT_PREVIEW_MEDIA_NA_INDEX_4X6_EXT_6X8IN, kSizeIn}},
+           {PRINT_PREVIEW_MEDIA_NA_INDEX_4X6_EXT_6X8IN,
+            MediaSizeGroup::kSizeIn}},
           {"na_index-4x6_4x6in",
-           {PRINT_PREVIEW_MEDIA_NA_INDEX_4X6_4X6IN, kSizeIn}},
+           {PRINT_PREVIEW_MEDIA_NA_INDEX_4X6_4X6IN, MediaSizeGroup::kSizeIn}},
           {"na_index-5x8_5x8in",
-           {PRINT_PREVIEW_MEDIA_NA_INDEX_5X8_5X8IN, kSizeIn}},
+           {PRINT_PREVIEW_MEDIA_NA_INDEX_5X8_5X8IN, MediaSizeGroup::kSizeIn}},
           {"na_invoice_5.5x8.5in",
-           {PRINT_PREVIEW_MEDIA_NA_INVOICE_5_5X8_5IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_NA_INVOICE_5_5X8_5IN,
+            MediaSizeGroup::kSizeNamed}},
           {"na_ledger_11x17in",
-           {PRINT_PREVIEW_MEDIA_NA_LEDGER_11X17IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_NA_LEDGER_11X17IN, MediaSizeGroup::kSizeNamed}},
           {"na_legal-extra_9.5x15in",
-           {PRINT_PREVIEW_MEDIA_NA_LEGAL_EXTRA_9_5X15IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_NA_LEGAL_EXTRA_9_5X15IN,
+            MediaSizeGroup::kSizeNamed}},
           {"na_legal_8.5x14in",
-           {PRINT_PREVIEW_MEDIA_NA_LEGAL_8_5X14IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_NA_LEGAL_8_5X14IN, MediaSizeGroup::kSizeNamed}},
           {"na_letter-extra_9.5x12in",
-           {PRINT_PREVIEW_MEDIA_NA_LETTER_EXTRA_9_5X12IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_NA_LETTER_EXTRA_9_5X12IN,
+            MediaSizeGroup::kSizeNamed}},
           {"na_letter-plus_8.5x12.69in",
-           {PRINT_PREVIEW_MEDIA_NA_LETTER_PLUS_8_5X12_69IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_NA_LETTER_PLUS_8_5X12_69IN,
+            MediaSizeGroup::kSizeNamed}},
           {"na_letter_8.5x11in",
-           {PRINT_PREVIEW_MEDIA_NA_LETTER_8_5X11IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_NA_LETTER_8_5X11IN,
+            MediaSizeGroup::kSizeNamed}},
           {"na_monarch_3.875x7.5in",
-           {PRINT_PREVIEW_MEDIA_NA_MONARCH_3_875X7_5IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_NA_MONARCH_3_875X7_5IN,
+            MediaSizeGroup::kSizeNamed}},
           {"na_number-9_3.875x8.875in",
-           {PRINT_PREVIEW_MEDIA_NA_NUMBER_9_3_875X8_875IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_NA_NUMBER_9_3_875X8_875IN,
+            MediaSizeGroup::kSizeNamed}},
           {"na_number-10_4.125x9.5in",
-           {PRINT_PREVIEW_MEDIA_NA_NUMBER_10_4_125X9_5IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_NA_NUMBER_10_4_125X9_5IN,
+            MediaSizeGroup::kSizeNamed}},
           {"na_number-11_4.5x10.375in",
-           {PRINT_PREVIEW_MEDIA_NA_NUMBER_11_4_5X10_375IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_NA_NUMBER_11_4_5X10_375IN,
+            MediaSizeGroup::kSizeNamed}},
           {"na_number-12_4.75x11in",
-           {PRINT_PREVIEW_MEDIA_NA_NUMBER_12_4_75X11IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_NA_NUMBER_12_4_75X11IN,
+            MediaSizeGroup::kSizeNamed}},
           {"na_number-14_5x11.5in",
-           {PRINT_PREVIEW_MEDIA_NA_NUMBER_14_5X11_5IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_NA_NUMBER_14_5X11_5IN,
+            MediaSizeGroup::kSizeNamed}},
           {"na_oficio_8.5x13.4in",
-           {PRINT_PREVIEW_MEDIA_NA_OFICIO_8_5X13_4IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_NA_OFICIO_8_5X13_4IN,
+            MediaSizeGroup::kSizeNamed}},
           {"na_personal_3.625x6.5in",
-           {PRINT_PREVIEW_MEDIA_NA_PERSONAL_3_625X6_5IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_NA_PERSONAL_3_625X6_5IN,
+            MediaSizeGroup::kSizeNamed}},
           {"na_quarto_8.5x10.83in",
-           {PRINT_PREVIEW_MEDIA_NA_QUARTO_8_5X10_83IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_NA_QUARTO_8_5X10_83IN,
+            MediaSizeGroup::kSizeNamed}},
           {"na_super-a_8.94x14in",
-           {PRINT_PREVIEW_MEDIA_NA_SUPER_A_8_94X14IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_NA_SUPER_A_8_94X14IN,
+            MediaSizeGroup::kSizeNamed}},
           {"na_super-b_13x19in",
-           {PRINT_PREVIEW_MEDIA_NA_SUPER_B_13X19IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_NA_SUPER_B_13X19IN,
+            MediaSizeGroup::kSizeNamed}},
           {"na_wide-format_30x42in",
-           {PRINT_PREVIEW_MEDIA_NA_WIDE_FORMAT_30X42IN, kSizeIn}},
-          {"oe_12x16_12x16in", {PRINT_PREVIEW_MEDIA_OE_12X16_12X16IN, kSizeIn}},
-          {"oe_14x17_14x17in", {PRINT_PREVIEW_MEDIA_OE_14X17_14X17IN, kSizeIn}},
-          {"oe_18x22_18x22in", {PRINT_PREVIEW_MEDIA_OE_18X22_18X22IN, kSizeIn}},
+           {PRINT_PREVIEW_MEDIA_NA_WIDE_FORMAT_30X42IN,
+            MediaSizeGroup::kSizeIn}},
+          {"oe_12x16_12x16in",
+           {PRINT_PREVIEW_MEDIA_OE_12X16_12X16IN, MediaSizeGroup::kSizeIn}},
+          {"oe_14x17_14x17in",
+           {PRINT_PREVIEW_MEDIA_OE_14X17_14X17IN, MediaSizeGroup::kSizeIn}},
+          {"oe_18x22_18x22in",
+           {PRINT_PREVIEW_MEDIA_OE_18X22_18X22IN, MediaSizeGroup::kSizeIn}},
           {"oe_a2plus_17x24in",
-           {PRINT_PREVIEW_MEDIA_OE_A2PLUS_17X24IN, kSizeIn}},
+           {PRINT_PREVIEW_MEDIA_OE_A2PLUS_17X24IN, MediaSizeGroup::kSizeIn}},
           {"oe_business-card_2x3.5in",
-           {PRINT_PREVIEW_MEDIA_OE_BUSINESS_CARD_2X3_5IN, kSizeIn}},
+           {PRINT_PREVIEW_MEDIA_OE_BUSINESS_CARD_2X3_5IN,
+            MediaSizeGroup::kSizeIn}},
           {"oe_photo-10r_10x12in",
-           {PRINT_PREVIEW_MEDIA_OE_PHOTO_10R_10X12IN, kSizeIn}},
+           {PRINT_PREVIEW_MEDIA_OE_PHOTO_10R_10X12IN, MediaSizeGroup::kSizeIn}},
           {"oe_photo-12r_12x15in",
-           {PRINT_PREVIEW_MEDIA_OE_PHOTO_12R_12X15IN, kSizeIn}},
+           {PRINT_PREVIEW_MEDIA_OE_PHOTO_12R_12X15IN, MediaSizeGroup::kSizeIn}},
           {"oe_photo-14x18_14x18in",
-           {PRINT_PREVIEW_MEDIA_OE_PHOTO_14X18_14X18IN, kSizeIn}},
+           {PRINT_PREVIEW_MEDIA_OE_PHOTO_14X18_14X18IN,
+            MediaSizeGroup::kSizeIn}},
           {"oe_photo-16r_16x20in",
-           {PRINT_PREVIEW_MEDIA_OE_PHOTO_16R_16X20IN, kSizeIn}},
+           {PRINT_PREVIEW_MEDIA_OE_PHOTO_16R_16X20IN, MediaSizeGroup::kSizeIn}},
           {"oe_photo-20r_20x24in",
-           {PRINT_PREVIEW_MEDIA_OE_PHOTO_20R_20X24IN, kSizeIn}},
+           {PRINT_PREVIEW_MEDIA_OE_PHOTO_20R_20X24IN, MediaSizeGroup::kSizeIn}},
           {"oe_photo-22r_22x29.5in",
-           {PRINT_PREVIEW_MEDIA_OE_PHOTO_22R_22X29_5IN, kSizeIn}},
+           {PRINT_PREVIEW_MEDIA_OE_PHOTO_22R_22X29_5IN,
+            MediaSizeGroup::kSizeIn}},
           {"oe_photo-22x28_22x28in",
-           {PRINT_PREVIEW_MEDIA_OE_PHOTO_22X28_22X28IN, kSizeIn}},
+           {PRINT_PREVIEW_MEDIA_OE_PHOTO_22X28_22X28IN,
+            MediaSizeGroup::kSizeIn}},
           {"oe_photo-24r_24x31.5in",
-           {PRINT_PREVIEW_MEDIA_OE_PHOTO_24R_24X31_5IN, kSizeIn}},
+           {PRINT_PREVIEW_MEDIA_OE_PHOTO_24R_24X31_5IN,
+            MediaSizeGroup::kSizeIn}},
           {"oe_photo-24x30_24x30in",
-           {PRINT_PREVIEW_MEDIA_OE_PHOTO_24X30_24X30IN, kSizeIn}},
+           {PRINT_PREVIEW_MEDIA_OE_PHOTO_24X30_24X30IN,
+            MediaSizeGroup::kSizeIn}},
           {"oe_photo-l_3.5x5in",
-           {PRINT_PREVIEW_MEDIA_OE_PHOTO_L_3_5X5IN, kSizeIn}},
+           {PRINT_PREVIEW_MEDIA_OE_PHOTO_L_3_5X5IN, MediaSizeGroup::kSizeIn}},
           {"oe_photo-30r_30x40in",
-           {PRINT_PREVIEW_MEDIA_OE_PHOTO_30R_30X40IN, kSizeIn}},
+           {PRINT_PREVIEW_MEDIA_OE_PHOTO_30R_30X40IN, MediaSizeGroup::kSizeIn}},
           {"oe_photo-s8r_8x12in",
-           {PRINT_PREVIEW_MEDIA_OE_PHOTO_S8R_8X12IN, kSizeIn}},
+           {PRINT_PREVIEW_MEDIA_OE_PHOTO_S8R_8X12IN, MediaSizeGroup::kSizeIn}},
           // Duplicate of na_10x15_10x15in.
           {"oe_photo-s10r_10x15in",
-           {PRINT_PREVIEW_MEDIA_NA_10X15_10X15IN, kSizeIn}},
+           {PRINT_PREVIEW_MEDIA_NA_10X15_10X15IN, MediaSizeGroup::kSizeIn}},
           {"oe_square-photo_4x4in",
-           {PRINT_PREVIEW_MEDIA_OE_SQUARE_PHOTO_4X4IN, kSizeIn}},
+           {PRINT_PREVIEW_MEDIA_OE_SQUARE_PHOTO_4X4IN,
+            MediaSizeGroup::kSizeIn}},
           {"oe_square-photo_5x5in",
-           {PRINT_PREVIEW_MEDIA_OE_SQUARE_PHOTO_5X5IN, kSizeIn}},
-          {"om_16k_184x260mm", {PRINT_PREVIEW_MEDIA_OM_16K_184X260MM, kSizeMm}},
-          {"om_16k_195x270mm", {PRINT_PREVIEW_MEDIA_OM_16K_195X270MM, kSizeMm}},
+           {PRINT_PREVIEW_MEDIA_OE_SQUARE_PHOTO_5X5IN,
+            MediaSizeGroup::kSizeIn}},
+          {"om_16k_184x260mm",
+           {PRINT_PREVIEW_MEDIA_OM_16K_184X260MM, MediaSizeGroup::kSizeMm}},
+          {"om_16k_195x270mm",
+           {PRINT_PREVIEW_MEDIA_OM_16K_195X270MM, MediaSizeGroup::kSizeMm}},
           {"om_business-card_55x85mm",
-           {PRINT_PREVIEW_MEDIA_OM_BUSINESS_CARD_55X85MM, kSizeMm}},
+           {PRINT_PREVIEW_MEDIA_OM_BUSINESS_CARD_55X85MM,
+            MediaSizeGroup::kSizeMm}},
           {"om_business-card_55x91mm",
-           {PRINT_PREVIEW_MEDIA_OM_BUSINESS_CARD_55X91MM, kSizeMm}},
-          {"om_card_54x86mm", {PRINT_PREVIEW_MEDIA_OM_CARD_54X86MM, kSizeMm}},
+           {PRINT_PREVIEW_MEDIA_OM_BUSINESS_CARD_55X91MM,
+            MediaSizeGroup::kSizeMm}},
+          {"om_card_54x86mm",
+           {PRINT_PREVIEW_MEDIA_OM_CARD_54X86MM, MediaSizeGroup::kSizeMm}},
           {"om_dai-pa-kai_275x395mm",
-           {PRINT_PREVIEW_MEDIA_OM_DAI_PA_KAI_275X395MM, kSizeMm}},
+           {PRINT_PREVIEW_MEDIA_OM_DAI_PA_KAI_275X395MM,
+            MediaSizeGroup::kSizeMm}},
           {"om_dsc-photo_89x119mm",
-           {PRINT_PREVIEW_MEDIA_OM_DSC_PHOTO_89X119MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_OM_DSC_PHOTO_89X119MM,
+            MediaSizeGroup::kSizeNamed}},
           {"om_folio-sp_215x315mm",
-           {PRINT_PREVIEW_MEDIA_OM_FOLIO_SP_215X315MM, kSizeMm}},
+           {PRINT_PREVIEW_MEDIA_OM_FOLIO_SP_215X315MM,
+            MediaSizeGroup::kSizeMm}},
           {"om_folio_210x330mm",
-           {PRINT_PREVIEW_MEDIA_OM_FOLIO_210X330MM, kSizeMm}},
+           {PRINT_PREVIEW_MEDIA_OM_FOLIO_210X330MM, MediaSizeGroup::kSizeMm}},
           {"om_invite_220x220mm",
-           {PRINT_PREVIEW_MEDIA_OM_INVITE_220X220MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_OM_INVITE_220X220MM,
+            MediaSizeGroup::kSizeNamed}},
           {"om_italian_110x230mm",
-           {PRINT_PREVIEW_MEDIA_OM_ITALIAN_110X230MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_OM_ITALIAN_110X230MM,
+            MediaSizeGroup::kSizeNamed}},
           {"om_juuro-ku-kai_198x275mm",
-           {PRINT_PREVIEW_MEDIA_OM_JUURO_KU_KAI_198X275MM, kSizeMm}},
+           {PRINT_PREVIEW_MEDIA_OM_JUURO_KU_KAI_198X275MM,
+            MediaSizeGroup::kSizeMm}},
           // Duplicate of the next because this was previously mapped wrong in
           // cups.
           {"om_large-photo_200x300",
-           {PRINT_PREVIEW_MEDIA_OM_LARGE_PHOTO_200X300, kSizeMm}},
+           {PRINT_PREVIEW_MEDIA_OM_LARGE_PHOTO_200X300,
+            MediaSizeGroup::kSizeMm}},
           {"om_large-photo_200x300mm",
-           {PRINT_PREVIEW_MEDIA_OM_LARGE_PHOTO_200X300, kSizeMm}},
+           {PRINT_PREVIEW_MEDIA_OM_LARGE_PHOTO_200X300,
+            MediaSizeGroup::kSizeMm}},
           {"om_medium-photo_130x180mm",
-           {PRINT_PREVIEW_MEDIA_OM_MEDIUM_PHOTO_130X180MM, kSizeMm}},
+           {PRINT_PREVIEW_MEDIA_OM_MEDIUM_PHOTO_130X180MM,
+            MediaSizeGroup::kSizeMm}},
           {"om_pa-kai_267x389mm",
-           {PRINT_PREVIEW_MEDIA_OM_PA_KAI_267X389MM, kSizeMm}},
+           {PRINT_PREVIEW_MEDIA_OM_PA_KAI_267X389MM, MediaSizeGroup::kSizeMm}},
           {"om_photo-30x40_300x400mm",
-           {PRINT_PREVIEW_MEDIA_OM_PHOTO_30X40_300X400MM, kSizeMm}},
+           {PRINT_PREVIEW_MEDIA_OM_PHOTO_30X40_300X400MM,
+            MediaSizeGroup::kSizeMm}},
           {"om_photo-30x45_300x450mm",
-           {PRINT_PREVIEW_MEDIA_OM_PHOTO_30X45_300X450MM, kSizeMm}},
+           {PRINT_PREVIEW_MEDIA_OM_PHOTO_30X45_300X450MM,
+            MediaSizeGroup::kSizeMm}},
           {"om_photo-35x46_350x460mm",
-           {PRINT_PREVIEW_MEDIA_OM_PHOTO_35X46_350X460MM, kSizeMm}},
+           {PRINT_PREVIEW_MEDIA_OM_PHOTO_35X46_350X460MM,
+            MediaSizeGroup::kSizeMm}},
           {"om_photo-40x60_400x600mm",
-           {PRINT_PREVIEW_MEDIA_OM_PHOTO_40X60_400X600MM, kSizeMm}},
+           {PRINT_PREVIEW_MEDIA_OM_PHOTO_40X60_400X600MM,
+            MediaSizeGroup::kSizeMm}},
           {"om_photo-50x75_500x750mm",
-           {PRINT_PREVIEW_MEDIA_OM_PHOTO_50X75_500X750MM, kSizeMm}},
+           {PRINT_PREVIEW_MEDIA_OM_PHOTO_50X75_500X750MM,
+            MediaSizeGroup::kSizeMm}},
           {"om_photo-50x76_500x760mm",
-           {PRINT_PREVIEW_MEDIA_OM_PHOTO_50X76_500X760MM, kSizeMm}},
+           {PRINT_PREVIEW_MEDIA_OM_PHOTO_50X76_500X760MM,
+            MediaSizeGroup::kSizeMm}},
           {"om_photo-60x90_600x900mm",
-           {PRINT_PREVIEW_MEDIA_OM_PHOTO_60X90_600X900MM, kSizeMm}},
+           {PRINT_PREVIEW_MEDIA_OM_PHOTO_60X90_600X900MM,
+            MediaSizeGroup::kSizeMm}},
           // Duplicate of iso_c6c5_114x229mm.
           {"om_postfix_114x229mm",
-           {PRINT_PREVIEW_MEDIA_ISO_C6C5_114X229MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_C6C5_114X229MM,
+            MediaSizeGroup::kSizeNamed}},
           {"om_small-photo_100x150mm",
-           {PRINT_PREVIEW_MEDIA_OM_SMALL_PHOTO_100X150MM, kSizeMm}},
+           {PRINT_PREVIEW_MEDIA_OM_SMALL_PHOTO_100X150MM,
+            MediaSizeGroup::kSizeMm}},
           {"om_square-photo_89x89mm",
-           {PRINT_PREVIEW_MEDIA_OM_SQUARE_PHOTO_89X89MM, kSizeMm}},
+           {PRINT_PREVIEW_MEDIA_OM_SQUARE_PHOTO_89X89MM,
+            MediaSizeGroup::kSizeMm}},
           {"om_wide-photo_100x200mm",
-           {PRINT_PREVIEW_MEDIA_OM_WIDE_PHOTO_100X200MM, kSizeMm}},
+           {PRINT_PREVIEW_MEDIA_OM_WIDE_PHOTO_100X200MM,
+            MediaSizeGroup::kSizeMm}},
           // Duplicate of iso_c3_324x458mm.
           {"prc_10_324x458mm",
-           {PRINT_PREVIEW_MEDIA_ISO_C3_324X458MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_C3_324X458MM, MediaSizeGroup::kSizeNamed}},
           {"prc_16k_146x215mm",
-           {PRINT_PREVIEW_MEDIA_PRC_16K_146X215MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_PRC_16K_146X215MM, MediaSizeGroup::kSizeNamed}},
           {"prc_1_102x165mm",
-           {PRINT_PREVIEW_MEDIA_PRC_1_102X165MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_PRC_1_102X165MM, MediaSizeGroup::kSizeNamed}},
           {"prc_2_102x176mm",
-           {PRINT_PREVIEW_MEDIA_PRC_2_102X176MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_PRC_2_102X176MM, MediaSizeGroup::kSizeNamed}},
           {"prc_32k_97x151mm",
-           {PRINT_PREVIEW_MEDIA_PRC_32K_97X151MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_PRC_32K_97X151MM, MediaSizeGroup::kSizeNamed}},
           // Duplicate of iso_b6_125x176mm.
           {"prc_3_125x176mm",
-           {PRINT_PREVIEW_MEDIA_ISO_B6_125X176MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_B6_125X176MM, MediaSizeGroup::kSizeNamed}},
           {"prc_4_110x208mm",
-           {PRINT_PREVIEW_MEDIA_PRC_4_110X208MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_PRC_4_110X208MM, MediaSizeGroup::kSizeNamed}},
           // Duplicate of iso_dl_110x220mm.
           {"prc_5_110x220mm",
-           {PRINT_PREVIEW_MEDIA_ISO_DL_110X220MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ISO_DL_110X220MM, MediaSizeGroup::kSizeNamed}},
           {"prc_6_120x320mm",
-           {PRINT_PREVIEW_MEDIA_PRC_6_120X320MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_PRC_6_120X320MM, MediaSizeGroup::kSizeNamed}},
           {"prc_7_160x230mm",
-           {PRINT_PREVIEW_MEDIA_PRC_7_160X230MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_PRC_7_160X230MM, MediaSizeGroup::kSizeNamed}},
           {"prc_8_120x309mm",
-           {PRINT_PREVIEW_MEDIA_PRC_8_120X309MM, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_PRC_8_120X309MM, MediaSizeGroup::kSizeNamed}},
           {"roc_16k_7.75x10.75in",
-           {PRINT_PREVIEW_MEDIA_ROC_16K_7_75X10_75IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ROC_16K_7_75X10_75IN,
+            MediaSizeGroup::kSizeNamed}},
           {"roc_8k_10.75x15.5in",
-           {PRINT_PREVIEW_MEDIA_ROC_8K_10_75X15_5IN, kSizeNamed}},
+           {PRINT_PREVIEW_MEDIA_ROC_8K_10_75X15_5IN,
+            MediaSizeGroup::kSizeNamed}},
       });
 
   auto it = media_map->find(vendor_id);
@@ -461,9 +598,6 @@
 // name.  If `pwg_name` is not a valid self-describing media size, the returned
 // name will be empty.
 MediaSizeInfo InfoForSelfDescribingSize(const std::string& pwg_name) {
-  using printing::Unit::kInches;
-  using printing::Unit::kMillimeters;
-
   // The expected format is area_description_dimensions, and dimensions are
   // WxHmm or WxHin.  Both W and H can contain decimals.
   static const base::NoDestructor<re2::RE2> media_name_pattern(
@@ -478,7 +612,7 @@
                        << pwg_name;
     return {u"", MediaSizeGroup::kSizeNamed};
   }
-  printing::Unit units = unit_str == "in" ? kInches : kMillimeters;
+  Unit units = unit_str == "in" ? Unit::kInches : Unit::kMillimeters;
 
   // If the name appears to end with approximately the paper dimensions, just
   // display the dimensions.  This avoids having things like "Card 4x6" and
@@ -492,13 +626,13 @@
       base::StartsWith(width, name_width) &&
       base::StartsWith(height, name_height)) {
     switch (units) {
-      case kInches:
+      case Unit::kInches:
         return {l10n_util::GetStringFUTF16(
                     PRINT_PREVIEW_MEDIA_DIMENSIONS_INCHES,
                     base::ASCIIToUTF16(width), base::ASCIIToUTF16(height)),
                 MediaSizeGroup::kSizeIn};
 
-      case kMillimeters:
+      case Unit::kMillimeters:
         return {l10n_util::GetStringFUTF16(PRINT_PREVIEW_MEDIA_DIMENSIONS_MM,
                                            base::ASCIIToUTF16(width),
                                            base::ASCIIToUTF16(height)),
@@ -525,14 +659,14 @@
   std::string clean_name = base::JoinString(words, " ");
 
   switch (units) {
-    case kInches:
+    case Unit::kInches:
       return {l10n_util::GetStringFUTF16(
                   PRINT_PREVIEW_MEDIA_NAME_WITH_DIMENSIONS_INCHES,
                   base::ASCIIToUTF16(clean_name), base::ASCIIToUTF16(width),
                   base::ASCIIToUTF16(height)),
               MediaSizeGroup::kSizeNamed};
 
-    case kMillimeters:
+    case Unit::kMillimeters:
       return {l10n_util::GetStringFUTF16(
                   PRINT_PREVIEW_MEDIA_NAME_WITH_DIMENSIONS_MM,
                   base::ASCIIToUTF16(clean_name), base::ASCIIToUTF16(width),
diff --git a/chrome/installer/util/install_service_work_item_impl.cc b/chrome/installer/util/install_service_work_item_impl.cc
index f354e27b..b9a413b 100644
--- a/chrome/installer/util/install_service_work_item_impl.cc
+++ b/chrome/installer/util/install_service_work_item_impl.cc
@@ -14,7 +14,6 @@
 #include "base/check.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
-#include "base/metrics/histogram_functions.h"
 #include "base/strings/strcat.h"
 #include "base/strings/stringprintf.h"
 #include "base/time/time.h"
@@ -63,38 +62,6 @@
   kMaxValue = kSucceededRollbackOriginalServiceConfig,
 };
 
-// One value for each possible call to RecordWin32ApiErrorCode. When new values
-// are added here, histogram_suffixes "SetupInstallWin32Apis" needs to be
-// updated in histograms.xml.
-constexpr char kChangeServiceConfig[] = "ChangeServiceConfig";
-constexpr char kCreateService[] = "CreateService";
-constexpr char kDeleteService[] = "DeleteService";
-constexpr char kOpenSCManager[] = "OpenSCManager";
-
-void RecordServiceInstallResult(ServiceInstallResult value) {
-  // Use the histogram function rather than the macro since only one value will
-  // be recorded per run.
-  base::UmaHistogramEnumeration("Setup.Install.ServiceInstallResult", value);
-}
-
-void RecordServiceRollbackResult(ServiceRollbackResult value) {
-  // Uses the histogram function rather than the macro since only one value will
-  // be recorded per run.
-  base::UmaHistogramEnumeration("Setup.Install.ServiceRollbackResult", value);
-}
-
-// Records the last Win32 error in a histogram named
-// "Setup.Install.Win32ApiError.|function|". |function| is one of the values in
-// the list of histogram suffixes "SetupInstallWin32Apis" above.
-void RecordWin32ApiErrorCode(const char* function) {
-  auto error_code = ::GetLastError();
-
-  // Uses the histogram function rather than the macro since the name of the
-  // histogram is computed at runtime.
-  base::UmaHistogramSparse(
-      base::StrCat({"Setup.Install.Win32ApiError.", function}), error_code);
-}
-
 std::wstring GetComRegistryPath(base::WStringPiece hive, const GUID& guid) {
   return base::StrCat(
       {L"Software\\Classes\\", hive, L"\\", base::win::WStringFromGUID(guid)});
@@ -184,23 +151,16 @@
                            SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE));
   if (!scm_.IsValid()) {
     PLOG(ERROR) << "::OpenSCManager Failed";
-    RecordServiceInstallResult(ServiceInstallResult::kFailedOpenSCManager);
-    RecordWin32ApiErrorCode(kOpenSCManager);
     return false;
   }
 
   if (!OpenService()) {
     VPLOG(1) << "Attempting to install new service following failure to open";
-    const bool succeeded = InstallNewService();
-    if (succeeded) {
-      RecordServiceInstallResult(ServiceInstallResult::kSucceededFreshInstall);
-      return succeeded;
-    }
+    if (InstallNewService())
+      return true;
 
     PLOG(ERROR) << "Failed to install service "
                 << GetCurrentServiceName().c_str();
-    RecordServiceInstallResult(ServiceInstallResult::kFailedFreshInstall);
-    RecordWin32ApiErrorCode(kCreateService);
     // Fall through to try installing the service by generating a new name.
   } else if (UpgradeService()) {
     // It is preferable to do a lightweight upgrade of the existing service,
@@ -222,25 +182,14 @@
   ScopedScHandle original_service = std::move(service_);
   if (InstallNewService()) {
     // Delete the previous version of the service.
-    if (DeleteService(std::move(original_service))) {
-      RecordServiceInstallResult(
-          ServiceInstallResult::kSucceededInstallNewAndDeleteOriginal);
-    } else {
+    if (!DeleteService(std::move(original_service)))
       original_service_still_exists_ = true;
 
-      RecordServiceInstallResult(
-          ServiceInstallResult::kSucceededInstallNewAndFailedDeleteOriginal);
-      RecordWin32ApiErrorCode(kDeleteService);
-    }
-
     return true;
   }
 
   PLOG(ERROR) << "Failed to install service with new name "
               << GetCurrentServiceName().c_str();
-  RecordServiceInstallResult(
-      ServiceInstallResult::kFailedInstallNewAfterFailedUpgrade);
-  RecordWin32ApiErrorCode(kCreateService);
   return false;
 }
 
@@ -338,14 +287,7 @@
   if (rollback_existing_service_) {
     DCHECK(service_.IsValid());
     DCHECK(original_service_config_.is_valid);
-    if (RestoreOriginalServiceConfig()) {
-      RecordServiceRollbackResult(
-          ServiceRollbackResult::kSucceededRollbackOriginalServiceConfig);
-    } else {
-      RecordServiceRollbackResult(
-          ServiceRollbackResult::kFailedRollbackOriginalServiceConfig);
-      RecordWin32ApiErrorCode(kChangeServiceConfig);
-    }
+    RestoreOriginalServiceConfig();
     return;
   }
 
@@ -353,14 +295,7 @@
   DCHECK(service_.IsValid());
 
   // Delete the newly created service.
-  if (DeleteCurrentService()) {
-    RecordServiceRollbackResult(
-        ServiceRollbackResult::kSucceededDeleteCurrentService);
-  } else {
-    RecordServiceRollbackResult(
-        ServiceRollbackResult::kFailedDeleteCurrentService);
-    RecordWin32ApiErrorCode(kDeleteService);
-  }
+  DeleteCurrentService();
 
   if (original_service_name_.empty())
     return;
@@ -378,8 +313,7 @@
   // issues with reusing the old name.
   if (!CreateAndSetServiceName())
     PLOG(ERROR) << "Failed to create and set unique service name";
-  if (!ReinstallOriginalService())
-    RecordWin32ApiErrorCode(kCreateService);
+  ReinstallOriginalService();
 }
 
 bool InstallServiceWorkItemImpl::DeleteServiceImpl() {
@@ -631,17 +565,8 @@
 
   // If the service is deleted, `ChangeServiceConfig()` will return false.
   bool success = ChangeServiceConfig(new_config);
-  if (success) {
-    if (upgrade_needed)
-      rollback_existing_service_ = true;
-
-    RecordServiceInstallResult(
-        upgrade_needed
-            ? ServiceInstallResult::kSucceededChangeServiceConfig
-            : ServiceInstallResult::kSucceededServiceCorrectlyConfigured);
-  } else {
-    RecordWin32ApiErrorCode(kChangeServiceConfig);
-  }
+  if (success && upgrade_needed)
+    rollback_existing_service_ = true;
 
   return success;
 }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 15192f17..f897901 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1288,6 +1288,7 @@
       "//chrome/browser/preloading/prerender:browser_tests",
       "//chrome/browser/privacy_budget:browser_tests",
       "//chrome/browser/profiling_host:profiling_browsertests",
+      "//chrome/browser/resource_coordinator:mojo_bindings",
       "//chrome/browser/resource_coordinator:tab_manager_features",
       "//chrome/browser/resource_coordinator:tab_metrics_event_proto",
       "//chrome/browser/safe_browsing:verdict_cache_manager_factory",
@@ -2096,9 +2097,17 @@
       "../browser/sessions/session_service_log_browsertest.cc",
       "../browser/sessions/tab_restore_browsertest.cc",
       "../browser/shared_highlighting/shared_highlighting_browsertest.cc",
+      "../browser/signin/e2e_tests/account_capabilities_observer.cc",
+      "../browser/signin/e2e_tests/account_capabilities_observer.h",
+      "../browser/signin/e2e_tests/accounts_removed_waiter.cc",
+      "../browser/signin/e2e_tests/accounts_removed_waiter.h",
       "../browser/signin/e2e_tests/live_sign_in_test.cc",
       "../browser/signin/e2e_tests/live_test.cc",
       "../browser/signin/e2e_tests/live_test.h",
+      "../browser/signin/e2e_tests/sign_in_test_observer.cc",
+      "../browser/signin/e2e_tests/sign_in_test_observer.h",
+      "../browser/signin/e2e_tests/signin_util.cc",
+      "../browser/signin/e2e_tests/signin_util.h",
       "../browser/signin/remove_local_account_browsertest.cc",
       "../browser/signin/signin_browser_test_base.cc",
       "../browser/signin/signin_browser_test_base.h",
@@ -6769,7 +6778,6 @@
       "../browser/resource_coordinator/tab_lifecycle_unit_source_unittest.cc",
       "../browser/resource_coordinator/tab_lifecycle_unit_unittest.cc",
       "../browser/resource_coordinator/tab_manager_unittest.cc",
-      "../browser/resource_coordinator/tab_manager_web_contents_data_unittest.cc",
       "../browser/resource_coordinator/tab_memory_metrics_reporter_unittest.cc",
       "../browser/resource_coordinator/tab_metrics_logger_unittest.cc",
       "../browser/resource_coordinator/tab_ranker/tab_features_unittest.cc",
diff --git a/chrome/test/data/webui/chromeos/personalization_app/personalization_app_component_browsertest.js b/chrome/test/data/webui/chromeos/personalization_app/personalization_app_component_browsertest.js
index 1fab3c1..07bc7ebb 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/personalization_app_component_browsertest.js
+++ b/chrome/test/data/webui/chromeos/personalization_app/personalization_app_component_browsertest.js
@@ -23,8 +23,7 @@
   get featureList() {
     return {
       enabled: [
-        'ash::features::kWallpaperGooglePhotosIntegration',
-        'ash::features::kAmbientSubpageUIChange'
+        'ash::features::kAmbientSubpageUIChange',
       ]
     };
   }
diff --git a/chrome/test/data/webui/chromeos/personalization_app/wallpaper_collections_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/wallpaper_collections_element_test.ts
index f3cbb2d..aeacf80 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/wallpaper_collections_element_test.ts
+++ b/chrome/test/data/webui/chromeos/personalization_app/wallpaper_collections_element_test.ts
@@ -5,7 +5,7 @@
 import 'chrome://personalization/strings.m.js';
 import 'chrome://webui-test/mojo_webui_test_support.js';
 
-import {emptyState, kDefaultImageSymbol, WallpaperActionName, WallpaperCollections} from 'chrome://personalization/js/personalization_app.js';
+import {emptyState, kDefaultImageSymbol, WallpaperActionName, WallpaperCollections, WallpaperGridItem} from 'chrome://personalization/js/personalization_app.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {assertDeepEquals, assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
 import {waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js';
@@ -114,19 +114,26 @@
     wallpaperCollectionsElement = initElement(WallpaperCollections);
     await waitAfterNextRender(wallpaperCollectionsElement);
 
-    assertEquals(
-        'chrome://personalization/images/no_images.svg',
-        wallpaperCollectionsElement.shadowRoot!
-            .querySelector<HTMLImageElement>('.local img')
-            ?.src,
+    const localTile = wallpaperCollectionsElement.shadowRoot!
+                          .querySelector<WallpaperGridItem>(
+                              `${WallpaperGridItem.is}[collage]`);
+
+    assertTrue(!!localTile, 'local tile is present');
+
+    assertDeepEquals(
+        [{url: 'chrome://personalization/images/no_images.svg'}], localTile.src,
         'no local images present');
 
     assertEquals(
+        loadTimeData.getString('myImagesLabel'), localTile.primaryText,
+        'correct local tile primary text');
+
+    assertEquals(
         loadTimeData.getString('zeroImages'),
         wallpaperCollectionsElement.shadowRoot!
-            .querySelector<HTMLParagraphElement>(
-                '.local .photo-text-container p:last-child')
-            ?.textContent,
+            .querySelector<WallpaperGridItem>(
+                `${WallpaperGridItem.is}[collage]`)
+            ?.secondaryText,
         'no images text is displayed');
   });
 
@@ -139,19 +146,15 @@
     wallpaperCollectionsElement = initElement(WallpaperCollections);
     await waitAfterNextRender(wallpaperCollectionsElement);
 
-    assertEquals(
-        'data:image/png;base64,qqqq',
-        wallpaperCollectionsElement.shadowRoot!
-            .querySelector<HTMLImageElement>('.local img')
-            ?.src,
-        'default image thumbnail present');
+    const localTile = wallpaperCollectionsElement.shadowRoot!
+                          .querySelector<WallpaperGridItem>(
+                              `${WallpaperGridItem.is}[collage]`);
 
-    assertEquals(
-        1,
-        wallpaperCollectionsElement.shadowRoot!
-            .querySelectorAll<HTMLImageElement>('.local img')
-            .length,
-        'only 1 local image preview');
+    assertTrue(!!localTile, 'local tile is present');
+
+    assertDeepEquals(
+        [{url: 'data:image/png;base64,qqqq'}], localTile.src,
+        'default image thumbnail present');
   });
 
   test('mixes local images in with default image thumbnail', async () => {
@@ -171,16 +174,18 @@
     wallpaperCollectionsElement = initElement(WallpaperCollections);
     await waitAfterNextRender(wallpaperCollectionsElement);
 
+    const localTile = wallpaperCollectionsElement.shadowRoot!
+                          .querySelector<WallpaperGridItem>(
+                              `${WallpaperGridItem.is}[collage]`);
+
+    assertTrue(!!localTile, 'local tile is present');
+
     assertDeepEquals(
         [
-          'data:image/png;base64,qqqq',
-          'data:image/png;base64,asdf',
-          'data:image/png;base64,qwer',
+          {url: 'data:image/png;base64,qqqq'},
+          {url: 'data:image/png;base64,asdf'},
+          {url: 'data:image/png;base64,qwer'},
         ],
-        Array
-            .from(wallpaperCollectionsElement.shadowRoot
-                      ?.querySelectorAll<HTMLImageElement>('.local img')!)
-            .map(img => img.src),
-        'all three images are displayed');
+        localTile.src, 'all three images are displayed');
   });
 });
diff --git a/chrome/test/data/webui/chromeos/personalization_app/wallpaper_grid_item_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/wallpaper_grid_item_element_test.ts
index 26ceb3b..fe2259b8 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/wallpaper_grid_item_element_test.ts
+++ b/chrome/test/data/webui/chromeos/personalization_app/wallpaper_grid_item_element_test.ts
@@ -7,7 +7,7 @@
 
 import {WallpaperGridItem} from 'chrome://personalization/js/personalization_app.js';
 import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js';
-import {assertEquals, assertFalse, assertNotEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
+import {assertDeepEquals, assertEquals, assertFalse, assertNotEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
 import {waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js';
 
 import {createSvgDataUrl, initElement, teardownElement} from './personalization_app_test_utils.js';
@@ -287,4 +287,25 @@
         'false', wallpaperGridItemElement.getAttribute('aria-disabled'),
         'disabled false sets aria-disabled attribute false');
   });
+
+  test('collage shows up to four images', async () => {
+    const src: Url[] =
+        [0, 1, 2, 3, 4, 5].map(i => ({url: createSvgDataUrl(`${i}`)}));
+    wallpaperGridItemElement = initElement(WallpaperGridItem, {src});
+    await waitAfterNextRender(wallpaperGridItemElement);
+
+    assertEquals(
+        2, wallpaperGridItemElement.shadowRoot!.querySelectorAll('img').length,
+        'only 2 images shown by default');
+
+    wallpaperGridItemElement.collage = true;
+    await waitAfterNextRender(wallpaperGridItemElement);
+
+    const images = Array.from(
+        wallpaperGridItemElement.shadowRoot!.querySelectorAll('img'));
+    assertEquals(4, images.length, 'collage shows 4 images');
+    assertDeepEquals(
+        src.slice(0, 4).map(({url}) => url), images.map(img => img.src),
+        'first four image urls are shown');
+  });
 });
diff --git a/chrome/test/data/webui/cr_elements/cr_lottie_tests.ts b/chrome/test/data/webui/cr_elements/cr_lottie_tests.ts
index 8e5e0bd..9e1181a 100644
--- a/chrome/test/data/webui/cr_elements/cr_lottie_tests.ts
+++ b/chrome/test/data/webui/cr_elements/cr_lottie_tests.ts
@@ -5,7 +5,7 @@
 // clang-format off
 import 'chrome://resources/cr_elements/cr_lottie/cr_lottie.js';
 
-import {CrLottieElement, LOTTIE_JS_URL} from 'chrome://resources/cr_elements/cr_lottie/cr_lottie.js';
+import {CrLottieElement} from 'chrome://resources/cr_elements/cr_lottie/cr_lottie.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {assertDeepEquals, assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
 import {MockController, MockMethod} from 'chrome://webui-test/mock_controller.js';
@@ -53,7 +53,6 @@
 
   let container: HTMLElement;
   let canvas: HTMLCanvasElement;
-  let lottieWorkerJs: Blob;
 
   let waitForInitializeEvent: Promise<void>;
   let waitForPlayingEvent: Promise<void>;
@@ -61,20 +60,8 @@
   const defaultWidth = 300;
   const defaultHeight = 200;
 
-  setup(function(done) {
+  setup(function() {
     mockController = new MockController();
-
-    const xhr = new XMLHttpRequest();
-    xhr.open('GET', LOTTIE_JS_URL, true);
-    xhr.responseType = 'blob';
-    xhr.send();
-    xhr.onreadystatechange = function() {
-      if (xhr.readyState === 4) {
-        assertEquals(200, xhr.status);
-        lottieWorkerJs = xhr.response;
-        done();
-      }
-    };
   });
 
   teardown(function() {
@@ -326,13 +313,6 @@
     const mockXhrConstructor =
         mockController.createFunctionMock(window, 'XMLHttpRequest');
 
-    // Expectations for loading the worker.
-    mockXhrConstructor.addExpectation();
-    (mockXhr.open as unknown as MockMethod)
-        .addExpectation(
-            'GET', 'chrome://resources/lottie/lottie_worker.min.js', true);
-    (mockXhr.send as unknown as MockMethod).addExpectation();
-
     // Expectations for loading the image and aborting it.
     mockXhrConstructor.addExpectation();
     (mockXhr.open as unknown as MockMethod)
@@ -344,12 +324,6 @@
 
     createLottieElement(/*autoplay=*/ true);
 
-    // Return the lottie worker.
-    Object.defineProperty(mockXhr, 'response', {value: lottieWorkerJs});
-    Object.defineProperty(mockXhr, 'readyState', {value: 4});
-    Object.defineProperty(mockXhr, 'status', {value: 200});
-    mockXhr.onreadystatechange!(new Event('readystatchange'));
-
     // Detaching the element before the image has loaded should abort the
     // request.
     crLottieElement.remove();
@@ -368,13 +342,6 @@
     const mockXhrConstructor =
         mockController.createFunctionMock(window, 'XMLHttpRequest');
 
-    // Expectations for loading the worker.
-    mockXhrConstructor.addExpectation();
-    (mockXhr.open as unknown as MockMethod)
-        .addExpectation(
-            'GET', 'chrome://resources/lottie/lottie_worker.min.js', true);
-    (mockXhr.send as unknown as MockMethod).addExpectation();
-
     // Expectations for loading the first image and aborting it.
     mockXhrConstructor.addExpectation();
     (mockXhr.open as unknown as MockMethod)
@@ -392,12 +359,6 @@
 
     createLottieElement(/*autoplay=*/ true);
 
-    // Return the lottie worker.
-    Object.defineProperty(mockXhr, 'response', {value: lottieWorkerJs});
-    Object.defineProperty(mockXhr, 'readyState', {value: 4});
-    Object.defineProperty(mockXhr, 'status', {value: 200});
-    mockXhr.onreadystatechange!(new Event('readystatchange'));
-
     // Attempting to load a new image should abort the first request and start a
     // new one.
     crLottieElement.animationUrl = SAMPLE_LOTTIE_BLUE;
diff --git a/chrome/test/enterprise/e2e/connector/__init__.py b/chrome/test/enterprise/e2e/connector/__init__.py
index ef3831c..fcdcb4ba 100644
--- a/chrome/test/enterprise/e2e/connector/__init__.py
+++ b/chrome/test/enterprise/e2e/connector/__init__.py
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 from .realtime_reporting_bce.realtime_reporting_bce_test import *
+from .reporting_connector_chronicle.reporting_connector_chronicle_test import *
 from .reporting_connector_crowdstrike.reporting_connector_crowdstrike_test import *
 from .reporting_connector_pubsub.reporting_connector_pubsub_test import *
 from .reporting_connector_splunk.reporting_connector_splunk_test import *
diff --git a/chrome/test/enterprise/e2e/connector/reporting_connector_chronicle/__init__.py b/chrome/test/enterprise/e2e/connector/reporting_connector_chronicle/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/chrome/test/enterprise/e2e/connector/reporting_connector_chronicle/__init__.py
diff --git a/chrome/test/enterprise/e2e/connector/reporting_connector_chronicle/chronicle_api_service.py b/chrome/test/enterprise/e2e/connector/reporting_connector_chronicle/chronicle_api_service.py
new file mode 100644
index 0000000..8e997003
--- /dev/null
+++ b/chrome/test/enterprise/e2e/connector/reporting_connector_chronicle/chronicle_api_service.py
@@ -0,0 +1,83 @@
+# Copyright 2022 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from datetime import datetime, timedelta
+import json
+from google.oauth2 import service_account
+from googleapiclient import _auth
+
+
+class ChronicleApiService(object):
+  """This class handles retrieving and verifying chronicle messages"""
+  messages = []
+  serviceAccountInfo = None
+
+  def __init__(self, credentials):
+    """Construct a ChronicleApiService instance.
+
+    Args:
+      credentials: the account key details.
+    """
+    try:
+      self.serviceAccountInfo = json.loads(credentials)
+    except json.JSONDecodeError:
+      print('Decoding PubsubApiService credentials JSON has failed')
+
+  def doesEventExist(self, deviceId, eventName):
+    """Verifies if a specific message was sent. Lazy loads messages
+
+    Args:
+      deviceId: A GUID device id that made the action.
+      eventName: A string containing the event name we're looking for
+    """
+    return eventName in json.dumps(self.messages)
+
+  def _datetimeToIso(self, date):
+    return date.strftime('%Y-%m-%dT%H:%M:%S.%f%zZ')
+
+  def loadEvents(self, testStartTime, deviceId):
+    """Calls Chronicle API to fetch events
+
+    Args:
+      deviceId: A GUID device id that made the action.
+      testStartTime: A datetime of the start time for the events
+    """
+    # Create a credential using Google Developer Service
+    # Account Credential and Chronicle API scope.
+    SCOPES = ['https://www.googleapis.com/auth/chronicle-backstory']
+    credentials = service_account.Credentials.from_service_account_info(
+        self.serviceAccountInfo, scopes=SCOPES)
+
+    # Build an HTTP client that can make authorized OAuth requests.
+    http_client = _auth.authorized_http(credentials)
+
+    # Construct the URL
+    RESULT_EVENTS_KEY = 'events'
+    BACKSTORY_API_V1_URL = 'https://backstory.googleapis.com/v1'
+    start_time = self._datetimeToIso(testStartTime - timedelta(minutes=15))
+    end_time = self._datetimeToIso(datetime.utcnow())
+    list_event_url = (
+        '{}/events:udmSearch?query=principal.resource.id+%3D+%22{}%22'
+        '&time_range.start_time={}&time_range.end_time={}'
+        '&limit=100').format(BACKSTORY_API_V1_URL, deviceId, start_time,
+                             end_time)
+
+    # Make a request
+    print('GET', list_event_url)
+    response = http_client.request(list_event_url, 'GET')
+
+    # Parse the response
+    if response[0].status == 200:
+      events = response[1]
+      # List of events returned for further processing
+      try:
+        events = json.loads(events.decode("utf-8"))
+      except json.JSONDecodeError:
+        print('Decoding chronicle events JSON response has failed')
+
+      self.messages = events.get(RESULT_EVENTS_KEY, [])
+    else:
+      # Something went wrong, please see the response detail
+      err = response[1]
+      print(err)
diff --git a/chrome/test/enterprise/e2e/connector/reporting_connector_chronicle/reporting_connector_chronicle_test.py b/chrome/test/enterprise/e2e/connector/reporting_connector_chronicle/reporting_connector_chronicle_test.py
new file mode 100644
index 0000000..bddc748
--- /dev/null
+++ b/chrome/test/enterprise/e2e/connector/reporting_connector_chronicle/reporting_connector_chronicle_test.py
@@ -0,0 +1,72 @@
+# Copyright 2022 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import re
+import time
+from datetime import datetime
+
+from chrome_ent_test.infra.core import before_all
+from chrome_ent_test.infra.core import category
+from chrome_ent_test.infra.core import environment
+from chrome_ent_test.infra.core import test
+from infra import ChromeEnterpriseTestCase
+from .chronicle_api_service import ChronicleApiService
+
+
+@category("chrome_only")
+@environment(file="../connector_test.asset.textpb")
+class ReportingConnectorwithChronicleTest(ChromeEnterpriseTestCase):
+  """Test the Realtime Reporting pipeline events"""
+
+  def getCredentials(self):
+    path = "gs://%s/secrets/chronicleCredentials.json" % self.gsbucket
+    cmd = r'gsutil cat ' + path
+    return self.RunCommand(self.win_config['dc'], cmd).rstrip().decode()
+
+  @before_all
+  def setup(self):
+    self.InstallChrome(self.win_config['client'])
+    self.EnableUITest(self.win_config['client'])
+
+  @test
+  def test_browser_enrolled_prod(self):
+    eventFound = False
+    path = "gs://%s/secrets/CELabOrg-enrollToken" % self.gsbucket
+    cmd = r'gsutil cat ' + path
+    token = self.RunCommand(self.win_config['dc'], cmd).rstrip().decode()
+    self.SetPolicy(self.win_config['dc'], r'CloudManagementEnrollmentToken',
+                   token, 'String')
+
+    self.SetPolicy(self.win_config['dc'], r'SafeBrowsingEnabled', 1, 'DWORD')
+    self.RunCommand(self.win_config['client'], 'gpupdate /force')
+    testStartTime = datetime.utcnow()
+    # trigger malware event & get device id from browser
+    localDir = os.path.dirname(os.path.abspath(__file__))
+    commonDir = os.path.dirname(localDir)
+    clientId = self.RunUITest(
+        self.win_config['client'],
+        os.path.join(commonDir, 'common', 'realtime_reporting_ui_test.py'),
+        timeout=600)
+    clientId = re.search(r'DeviceId:.*$',
+                         clientId.strip()).group(0).replace('DeviceId:',
+                                                            '').rstrip("\\rn'")
+
+    # wait until events are logged in the connector
+    max_wait_time_secs = 360
+    delta_secs = 10
+    total_wait_time_secs = 0
+    crendentials = self.getCredentials()
+
+    while total_wait_time_secs < max_wait_time_secs:
+      chronicleService = ChronicleApiService(crendentials)
+      chronicleService.loadEvents(
+          testStartTime=testStartTime, deviceId=clientId)
+      if chronicleService.doesEventExist(
+          eventName='badNavigationEvent', deviceId=clientId):
+        return
+      time.sleep(delta_secs)
+      total_wait_time_secs += delta_secs
+
+    raise Exception('Timed out ' 'badNavigationEvent event not found')
diff --git a/chrome/test/interaction/webcontents_interaction_test_util_browsertest.cc b/chrome/test/interaction/webcontents_interaction_test_util_browsertest.cc
index 0a64b6ab..083fc2d 100644
--- a/chrome/test/interaction/webcontents_interaction_test_util_browsertest.cc
+++ b/chrome/test/interaction/webcontents_interaction_test_util_browsertest.cc
@@ -11,6 +11,7 @@
 #include "base/time/time.h"
 #include "base/timer/elapsed_timer.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/resource_coordinator/lifecycle_unit_state.mojom-shared.h"
 #include "chrome/browser/resource_coordinator/tab_manager.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
diff --git a/chrome/updater/BUILD.gn b/chrome/updater/BUILD.gn
index 31b51cf..758b4a7 100644
--- a/chrome/updater/BUILD.gn
+++ b/chrome/updater/BUILD.gn
@@ -709,6 +709,9 @@
 
     if (is_win) {
       sources += [
+        # TODO(crbug.com/1392429) - eliminate the dependency on //chrome/test.
+        "//chrome/test/base/process_inspector_win.cc",
+        "//chrome/test/base/process_inspector_win.h",
         "activity_impl_win_unittest.cc",
         "app/server/win/com_classes_legacy_unittest.cc",
         "auto_run_on_os_upgrade_task_unittest.cc",
diff --git a/chrome/updater/test/integration_tests_win.cc b/chrome/updater/test/integration_tests_win.cc
index 7c23541e..a1b6a9e1f 100644
--- a/chrome/updater/test/integration_tests_win.cc
+++ b/chrome/updater/test/integration_tests_win.cc
@@ -47,6 +47,7 @@
 #include "base/win/scoped_variant.h"
 #include "base/win/win_util.h"
 #include "build/build_config.h"
+#include "chrome/test/base/process_inspector_win.h"
 #include "chrome/updater/app/server/win/com_classes.h"
 #include "chrome/updater/app/server/win/updater_idl.h"
 #include "chrome/updater/app/server/win/updater_internal_idl.h"
@@ -549,7 +550,12 @@
   const base::ProcessIterator::ProcessEntries& process_entries =
       process_iterator.Snapshot();
   for (const base::ProcessEntry& entry : process_entries) {
-    VLOG(0) << entry.exe_file();
+    VLOG(0) << entry.exe_file() << ", cmdline=" << [](base::ProcessId pid) {
+      std::unique_ptr<ProcessInspector> process_inspector =
+          ProcessInspector::Create(
+              base::Process::OpenWithAccess(pid, PROCESS_ALL_ACCESS));
+      return process_inspector ? process_inspector->command_line() : L"n/a";
+    }(entry.pid());
   }
   VLOG(0) << demarcation;
 }
diff --git a/chromeos/ash/components/device_activity/BUILD.gn b/chromeos/ash/components/device_activity/BUILD.gn
index 73ecbe7c..f793067 100644
--- a/chromeos/ash/components/device_activity/BUILD.gn
+++ b/chromeos/ash/components/device_activity/BUILD.gn
@@ -52,7 +52,6 @@
     "fresnel_pref_names.h",
     "monthly_use_case_impl.cc",
     "monthly_use_case_impl.h",
-    "trigger.h",
   ]
 }
 
diff --git a/chromeos/ash/components/device_activity/trigger.h b/chromeos/ash/components/device_activity/trigger.h
deleted file mode 100644
index 3452e74f..0000000
--- a/chromeos/ash/components/device_activity/trigger.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_COMPONENTS_DEVICE_ACTIVITY_TRIGGER_H_
-#define CHROMEOS_ASH_COMPONENTS_DEVICE_ACTIVITY_TRIGGER_H_
-
-namespace ash::device_activity {
-
-// Device actives are measured according to trigger enums.
-// TODO(https://crbug.com/1262178): Add another trigger for when sign-in occurs.
-enum class Trigger {
-  kNetwork  // Network state becomes connected.
-};
-
-}  // namespace ash::device_activity
-
-#endif  // CHROMEOS_ASH_COMPONENTS_DEVICE_ACTIVITY_TRIGGER_H_
diff --git a/chromeos/ui/frame/multitask_menu/multitask_menu_view.cc b/chromeos/ui/frame/multitask_menu/multitask_menu_view.cc
index a574c4d6..a179dafd 100644
--- a/chromeos/ui/frame/multitask_menu/multitask_menu_view.cc
+++ b/chromeos/ui/frame/multitask_menu/multitask_menu_view.cc
@@ -16,6 +16,7 @@
 #include "chromeos/ui/frame/multitask_menu/split_button_view.h"
 #include "chromeos/ui/wm/features.h"
 #include "ui/aura/window.h"
+#include "ui/aura/window_delegate.h"
 #include "ui/base/default_style.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
@@ -49,6 +50,18 @@
   return container;
 }
 
+// Returns true if the window is too wide (or tall, in portrait mode) to be put
+// into one third split.
+bool ShouldDisableOneThirdSplit(aura::Window* window, bool is_portrait_mode) {
+  if (!window || !window->delegate())
+    return false;
+  const gfx::Size minimum_size = window->delegate()->GetMinimumSize();
+  const gfx::Rect work_area =
+      display::Screen::GetScreen()->GetDisplayNearestWindow(window).work_area();
+  return is_portrait_mode ? minimum_size.height() > work_area.height() * 0.33f
+                          : minimum_size.width() > work_area.width() * 0.33f;
+}
+
 }  // namespace
 
 MultitaskMenuView::MultitaskMenuView(
@@ -91,6 +104,8 @@
                             base::Unretained(this), /*left_top=*/false),
         is_portrait_mode);
     partial_button_ = partial_button.get();
+    if (ShouldDisableOneThirdSplit(window, is_portrait_mode))
+      partial_button_->DisableOneThirdSplit();
     AddChildView(CreateButtonContainer(std::move(partial_button),
                                        IDS_APP_ACCNAME_PARTIAL));
   }
diff --git a/chromeos/ui/frame/multitask_menu/split_button_view.cc b/chromeos/ui/frame/multitask_menu/split_button_view.cc
index 59371f7..c6df235 100644
--- a/chromeos/ui/frame/multitask_menu/split_button_view.cc
+++ b/chromeos/ui/frame/multitask_menu/split_button_view.cc
@@ -74,6 +74,8 @@
     cc::PaintFlags pattern_flags;
     pattern_flags.setAntiAlias(true);
     pattern_flags.setColor(button_color_);
+    pattern_flags.setColor(GetEnabled() ? button_color_
+                                        : kMultitaskButtonDisabledColor);
     pattern_flags.setStyle(cc::PaintFlags::kFill_Style);
     gfx::Rect pattern_bounds = GetLocalBounds();
     pattern_bounds.Inset(insets_);
@@ -139,6 +141,10 @@
           : gfx::Size(secondary_width, kMultitaskHalfButtonHeight));
 }
 
+void SplitButtonView::DisableOneThirdSplit() {
+  secondary_button_->SetEnabled(false);
+}
+
 void SplitButtonView::OnButtonHovered() {
   border_color_ = kMultitaskButtonPrimaryHoverColor;
   fill_color_ = kMultitaskButtonViewHoverColor;
diff --git a/chromeos/ui/frame/multitask_menu/split_button_view.h b/chromeos/ui/frame/multitask_menu/split_button_view.h
index afed11c..2d4296c 100644
--- a/chromeos/ui/frame/multitask_menu/split_button_view.h
+++ b/chromeos/ui/frame/multitask_menu/split_button_view.h
@@ -33,6 +33,10 @@
 
   ~SplitButtonView() override = default;
 
+  // Only one of the split buttons may be disabled for some windows. This
+  // disables only the one third button in the split button view.
+  void DisableOneThirdSplit();
+
  private:
   class SplitButton;
 
diff --git a/components/creator/creator_api_impl.cc b/components/creator/creator_api_impl.cc
index 06c41626..e5e8248 100644
--- a/components/creator/creator_api_impl.cc
+++ b/components/creator/creator_api_impl.cc
@@ -12,6 +12,6 @@
 namespace creator {
 Creator CreatorApiImpl::GetCreator(std::string channel_id) {
   // TODO(crbug.com/1365645) query actual data for given channel id.
-  return Creator{/*url=*/GURL("example.com"), /*title=*/u"Example Domain"};
+  return Creator{u"alexainsley.com", /*title=*/u"Alex Ainsley"};
 }
 }  // namespace creator
\ No newline at end of file
diff --git a/components/creator/public/creator_api.h b/components/creator/public/creator_api.h
index bc0f270a..a0df6e3 100644
--- a/components/creator/public/creator_api.h
+++ b/components/creator/public/creator_api.h
@@ -7,12 +7,10 @@
 
 #include <string>
 
-#include "url/gurl.h"
-
 namespace creator {
 
 struct Creator {
-  GURL url;
+  std::u16string url;
   std::u16string title;
 };
 
diff --git a/components/exo/shell_surface_base.cc b/components/exo/shell_surface_base.cc
index 8c3f8b0..de31a67 100644
--- a/components/exo/shell_surface_base.cc
+++ b/components/exo/shell_surface_base.cc
@@ -10,40 +10,31 @@
 #include "ash/display/screen_orientation_controller.h"
 #include "ash/frame/non_client_frame_view_ash.h"
 #include "ash/metrics/login_unlock_throughput_recorder.h"
-#include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/rounded_corner_utils.h"
-#include "ash/public/cpp/shelf_types.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/public/cpp/window_properties.h"
-#include "ash/screen_util.h"
 #include "ash/shell.h"
 #include "ash/wm/desks/desks_controller.h"
 #include "ash/wm/desks/desks_util.h"
-#include "ash/wm/drag_window_resizer.h"
 #include "ash/wm/resize_shadow_controller.h"
-#include "ash/wm/screen_pinning_controller.h"
 #include "ash/wm/window_resizer.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "base/check.h"
-#include "base/debug/stack_trace.h"
+#include "base/containers/contains.h"
+#include "base/containers/flat_set.h"
 #include "base/logging.h"
-#include "base/memory/ptr_util.h"
-#include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/traced_value.h"
 #include "build/chromeos_buildflags.h"
-#include "cc/trees/layer_tree_frame_sink.h"
-#include "chromeos/crosapi/cpp/crosapi_constants.h"
 #include "chromeos/ui/base/chromeos_ui_constants.h"
 #include "chromeos/ui/base/window_pin_type.h"
 #include "chromeos/ui/base/window_properties.h"
 #include "chromeos/ui/base/window_state_type.h"
 #include "chromeos/ui/frame/caption_buttons/snap_controller.h"
 #include "chromeos/ui/frame/multitask_menu/float_controller_base.h"
-#include "components/app_restore/app_restore_info.h"
 #include "components/app_restore/app_restore_utils.h"
 #include "components/app_restore/window_properties.h"
 #include "components/exo/custom_window_state_delegate.h"
@@ -53,21 +44,15 @@
 #include "components/exo/window_properties.h"
 #include "components/exo/wm_helper.h"
 #include "third_party/skia/include/core/SkPath.h"
-#include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/capture_client.h"
-#include "ui/aura/client/cursor_client.h"
 #include "ui/aura/client/focus_client.h"
-#include "ui/aura/window.h"
 #include "ui/aura/window_observer.h"
 #include "ui/aura/window_occlusion_tracker.h"
 #include "ui/aura/window_targeter.h"
-#include "ui/aura/window_tree_host.h"
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/base/class_property.h"
-#include "ui/base/ui_base_features.h"
-#include "ui/compositor/compositor.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor_extra/shadow.h"
 #include "ui/display/display.h"
@@ -75,9 +60,7 @@
 #include "ui/gfx/geometry/size_conversions.h"
 #include "ui/gfx/geometry/vector2d_conversions.h"
 #include "ui/views/accessibility/view_accessibility.h"
-#include "ui/views/layout/fill_layout.h"
 #include "ui/views/widget/widget.h"
-#include "ui/wm/core/coordinate_conversion.h"
 #include "ui/wm/core/shadow_controller.h"
 #include "ui/wm/core/shadow_types.h"
 #include "ui/wm/core/window_animations.h"
@@ -1093,24 +1076,99 @@
 
 void ShellSurfaceBase::OnCaptureChanged(aura::Window* lost_capture,
                                         aura::Window* gained_capture) {
-  if (lost_capture == widget_->GetNativeWindow() && is_popup_) {
-    WMHelper::GetInstance()->GetCaptureClient()->RemoveObserver(this);
-    if (gained_capture &&
-        lost_capture == wm::GetTransientParent(gained_capture)) {
-      // Don't close if the capture has been transferred to the child popup.
-      return;
+  if (lost_capture != widget_->GetNativeWindow() || !is_popup_)
+    return;
+
+  WMHelper::GetInstance()->GetCaptureClient()->RemoveObserver(this);
+
+  // Fast return for a simple case: if `lost_capture` is the parent of
+  // `gained_capture`, do nothing.
+  aura::Window* gained_capture_parent =
+      gained_capture ? wm::GetTransientParent(gained_capture) : nullptr;
+  if (lost_capture == gained_capture_parent)
+    return;
+
+  if (!gained_capture) {
+    // If `gained_capture` is nullptr, find the closest ancestor of
+    // `lost_capture` that is a popup with grab.
+    for (aura::Window* next = wm::GetTransientParent(lost_capture);
+         next != nullptr; next = wm::GetTransientParent(next)) {
+      if (IsPopupWithGrab(next)) {
+        gained_capture = next;
+        break;
+      }
     }
-    aura::Window* parent = wm::GetTransientParent(lost_capture);
-    if (parent) {
-      // The capture needs to be transferred to the parent if it had grab.
-      views::Widget* parent_widget =
-          views::Widget::GetWidgetForNativeWindow(parent);
-      ShellSurfaceBase* parent_shell_surface = static_cast<ShellSurfaceBase*>(
-          parent_widget->widget_delegate()->GetContentsView());
-      if (parent_shell_surface->has_grab_)
-        parent_shell_surface->StartCapture();
+    // Give capture to the new `gained_capture`.
+    if (gained_capture) {
+      ShellSurfaceBase* parent_shell_surface =
+          GetShellSurfaceBaseForWindow(gained_capture);
+      parent_shell_surface->StartCapture();
     }
-    widget_->Close();
+  }
+
+  // Close any popup that satisfies the following conditions:
+  // 1) it has grab, and it is not `gained_capture` or any of its ancestors; or
+  // 2) descendants of any popup satisfying (1).
+  //
+  // Imagine there are the following popups:
+  //
+  //    popup_e
+  //   (no grab)
+  //       |
+  //    popup_d
+  // (has grab; lost_capture)
+  //       |
+  //    popup_c       popup_b
+  //   (no grab) (has grab; gained_capture)
+  //         \         /
+  //          \       /
+  //           popup_a
+  //
+  // In this case, popup_e and popup_d are the ones to close, in the order
+  // from leaf to root.
+
+  // Please note that `gained_capture_ancestors` also includes `gained_capture`.
+  base::flat_set<aura::Window*> gained_capture_ancestors;
+  for (aura::Window* next = gained_capture; next != nullptr;
+       next = wm::GetTransientParent(next)) {
+    gained_capture_ancestors.insert(next);
+  }
+
+  // BFS to collect all transient windows. The boolean field indicates whether
+  // the corresponding window is a popup to be closed.
+  std::vector<std::pair<aura::Window*, bool>> all;
+
+  auto is_close_candidate_with_popup_grab =
+      [&gained_capture_ancestors](aura::Window* window) {
+        return IsPopupWithGrab(window) &&
+               !base::Contains(gained_capture_ancestors, window);
+      };
+
+  aura::Window* root = wm::GetTransientRoot(lost_capture);
+  all.emplace_back(root, is_close_candidate_with_popup_grab(root));
+
+  // Use index instead of iterator because the vector grows during the
+  // iteration.
+  for (size_t i = 0; i < all.size(); ++i) {
+    const std::vector<aura::Window*>& children =
+        wm::GetTransientChildren(all[i].first);
+    for (aura::Window* child : children) {
+      const bool to_close =
+          all[i].second || is_close_candidate_with_popup_grab(child);
+      all.emplace_back(child, to_close);
+    }
+  }
+
+  // Traverse backwards so that popups are closed in the direction from leaf to
+  // root.
+  for (auto iter = all.rbegin(); iter != all.rend(); ++iter) {
+    if (!iter->second)
+      continue;
+
+    ShellSurfaceBase* shell_surface =
+        exo::GetShellSurfaceBaseForWindow(iter->first);
+    DCHECK(shell_surface);
+    shell_surface->widget_->Close();
   }
 }
 
@@ -1880,4 +1938,15 @@
   initial_z_order_ = z_order;
 }
 
+// static
+bool ShellSurfaceBase::IsPopupWithGrab(aura::Window* window) {
+  ShellSurfaceBase* shell_surface = exo::GetShellSurfaceBaseForWindow(window);
+  if (shell_surface && shell_surface->has_grab_) {
+    DCHECK(shell_surface->is_popup_);
+    return true;
+  }
+
+  return false;
+}
+
 }  // namespace exo
diff --git a/components/exo/shell_surface_base.h b/components/exo/shell_surface_base.h
index 5be8115..c8b4e7ff 100644
--- a/components/exo/shell_surface_base.h
+++ b/components/exo/shell_surface_base.h
@@ -399,6 +399,8 @@
   // maximize request. Currently only true for Lacros.
   bool ShouldExitFullscreenFromRestoreOrMaximized();
 
+  static bool IsPopupWithGrab(aura::Window* window);
+
   views::Widget* widget_ = nullptr;
   bool movement_disabled_ = false;
   gfx::Point origin_;
diff --git a/components/exo/shell_surface_unittest.cc b/components/exo/shell_surface_unittest.cc
index c19e912..f5688024 100644
--- a/components/exo/shell_surface_unittest.cc
+++ b/components/exo/shell_surface_unittest.cc
@@ -121,6 +121,12 @@
   return 0;
 }
 
+bool IsCaptureWindow(ShellSurface* shell_surface) {
+  aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
+  return WMHelper::GetInstance()->GetCaptureClient()->GetCaptureWindow() ==
+         window;
+}
+
 }  // namespace
 
 TEST_F(ShellSurfaceTest, AcknowledgeConfigure) {
@@ -1400,18 +1406,17 @@
   // Verify that created shell surface is popup and has capture.
   EXPECT_EQ(aura::client::WINDOW_TYPE_POPUP,
             popup_shell_surface->GetWidget()->GetNativeWindow()->GetType());
-  EXPECT_EQ(WMHelper::GetInstance()->GetCaptureClient()->GetCaptureWindow(),
-            popup_shell_surface->GetWidget()->GetNativeWindow());
+  EXPECT_TRUE(IsCaptureWindow(popup_shell_surface.get()));
 
   // Setting frame type on popup should have no effect.
   popup_surface->SetFrame(SurfaceFrameType::NORMAL);
   EXPECT_FALSE(popup_shell_surface->frame_enabled());
 
-  // ShellSurface can capture the event even after it is craeted.
+  // ShellSurface can capture the event even after it is created.
   std::unique_ptr<Buffer> sub_popup_buffer(
       new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
   std::unique_ptr<Surface> sub_popup_surface(new Surface);
-  sub_popup_surface->Attach(popup_buffer.get());
+  sub_popup_surface->Attach(sub_popup_buffer.get());
   std::unique_ptr<ShellSurface> sub_popup_shell_surface(CreatePopupShellSurface(
       sub_popup_surface.get(), popup_shell_surface.get(), gfx::Point(100, 50)));
   sub_popup_shell_surface->Grab();
@@ -1420,10 +1425,9 @@
             sub_popup_shell_surface->GetWidget()->GetWindowBoundsInScreen());
   aura::Window* target =
       sub_popup_shell_surface->GetWidget()->GetNativeWindow();
-  // The capture should be on sub_popup_shell_surface.
-  EXPECT_EQ(WMHelper::GetInstance()->GetCaptureClient()->GetCaptureWindow(),
-            target);
   EXPECT_EQ(aura::client::WINDOW_TYPE_POPUP, target->GetType());
+  // The capture should be on `sub_popup_shell_surface`.
+  EXPECT_TRUE(IsCaptureWindow(sub_popup_shell_surface.get()));
 
   {
     // Mouse is on the top most popup.
@@ -1449,18 +1453,216 @@
 
   // Removing top most popup moves the grab to parent popup.
   sub_popup_shell_surface.reset();
-  target = popup_shell_surface->GetWidget()->GetNativeWindow();
-  EXPECT_EQ(WMHelper::GetInstance()->GetCaptureClient()->GetCaptureWindow(),
-            target);
+  EXPECT_TRUE(IsCaptureWindow(popup_shell_surface.get()));
+
   {
     // Targetting should still work.
     ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(0, 0),
                          gfx::Point(50, 50), ui::EventTimeForNow(), 0, 0);
-    ui::Event::DispatcherApi(&event).set_target(target);
+    ui::Event::DispatcherApi(&event).set_target(
+        popup_shell_surface->GetWidget()->GetNativeWindow());
     EXPECT_EQ(popup_surface.get(), GetTargetSurfaceForLocatedEvent(&event));
   }
 }
 
+TEST_F(ShellSurfaceTest, GainCaptureFromSiblingSubPopup) {
+  // Test that in the following setup:
+  //
+  //     popup_shell_surface1     popup_shell_surface2
+  //  (has grab, loses capture) (has grab, gains capture)
+  //                 \                /
+  //                popup_shell_surface
+  //
+  // when popup_shell_surface2 is added, capture is correctly transferred to it
+  // from popup_shell_surface1.
+
+  gfx::Size buffer_size(256, 256);
+  auto buffer = std::make_unique<Buffer>(
+      exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+  auto surface = std::make_unique<Surface>();
+  auto shell_surface = std::make_unique<ShellSurface>(surface.get());
+  surface->Attach(buffer.get());
+  surface->Commit();
+  shell_surface->GetWidget()->SetBounds(gfx::Rect(0, 0, 256, 256));
+
+  auto popup_buffer = std::make_unique<Buffer>(
+      exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+  auto popup_surface = std::make_unique<Surface>();
+  popup_surface->Attach(popup_buffer.get());
+  std::unique_ptr<ShellSurface> popup_shell_surface(CreatePopupShellSurface(
+      popup_surface.get(), shell_surface.get(), gfx::Point(50, 50)));
+  popup_shell_surface->Grab();
+  popup_surface->Commit();
+  EXPECT_TRUE(IsCaptureWindow(popup_shell_surface.get()));
+
+  auto popup_buffer1 = std::make_unique<Buffer>(
+      exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+  auto popup_surface1 = std::make_unique<Surface>();
+  popup_surface1->Attach(popup_buffer1.get());
+  std::unique_ptr<ShellSurface> popup_shell_surface1(CreatePopupShellSurface(
+      popup_surface1.get(), popup_shell_surface.get(), gfx::Point(100, 50)));
+  popup_shell_surface1->Grab();
+  popup_surface1->Commit();
+  EXPECT_TRUE(IsCaptureWindow(popup_shell_surface1.get()));
+
+  auto popup_buffer2 = std::make_unique<Buffer>(
+      exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+  auto popup_surface2 = std::make_unique<Surface>();
+  popup_surface2->Attach(popup_buffer2.get());
+  std::unique_ptr<ShellSurface> popup_shell_surface2(CreatePopupShellSurface(
+      popup_surface2.get(), popup_shell_surface.get(), gfx::Point(50, 100)));
+  popup_shell_surface2->Grab();
+  popup_surface2->Commit();
+  EXPECT_TRUE(IsCaptureWindow(popup_shell_surface2.get()));
+}
+
+TEST_F(ShellSurfaceTest, GainCaptureFromNieceSubPopup) {
+  // Test that in the following setup:
+  //
+  //    popup_shell_surface3
+  //           (no grab)
+  //              |
+  //    popup_shell_surface2
+  //  (has grab; loses capture)
+  //              |
+  //    popup_shell_surface1    popup_shell_surface4
+  //         (no grab)        (has grab; gains capture)
+  //                 \                /
+  //                popup_shell_surface
+  //
+  // when popup_shell_surface4 is added, capture is correctly transferred to
+  // it from popup_shell_surface2.
+
+  gfx::Size buffer_size(256, 256);
+  auto buffer = std::make_unique<Buffer>(
+      exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+  auto surface = std::make_unique<Surface>();
+  auto shell_surface = std::make_unique<ShellSurface>(surface.get());
+  surface->Attach(buffer.get());
+  surface->Commit();
+  shell_surface->GetWidget()->SetBounds(gfx::Rect(0, 0, 256, 256));
+
+  auto popup_buffer = std::make_unique<Buffer>(
+      exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+  auto popup_surface = std::make_unique<Surface>();
+  popup_surface->Attach(popup_buffer.get());
+  std::unique_ptr<ShellSurface> popup_shell_surface(CreatePopupShellSurface(
+      popup_surface.get(), shell_surface.get(), gfx::Point(50, 50)));
+  popup_shell_surface->Grab();
+  popup_surface->Commit();
+  EXPECT_TRUE(IsCaptureWindow(popup_shell_surface.get()));
+
+  auto popup_buffer1 = std::make_unique<Buffer>(
+      exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+  auto popup_surface1 = std::make_unique<Surface>();
+  popup_surface1->Attach(popup_buffer1.get());
+  std::unique_ptr<ShellSurface> popup_shell_surface1(CreatePopupShellSurface(
+      popup_surface1.get(), popup_shell_surface.get(), gfx::Point(100, 50)));
+  popup_surface1->Commit();
+  // Doesn't change capture.
+  EXPECT_TRUE(IsCaptureWindow(popup_shell_surface.get()));
+
+  auto popup_buffer2 = std::make_unique<Buffer>(
+      exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+  auto popup_surface2 = std::make_unique<Surface>();
+  popup_surface2->Attach(popup_buffer2.get());
+  std::unique_ptr<ShellSurface> popup_shell_surface2(CreatePopupShellSurface(
+      popup_surface2.get(), popup_shell_surface1.get(), gfx::Point(150, 50)));
+  popup_shell_surface2->Grab();
+  popup_surface2->Commit();
+  EXPECT_TRUE(IsCaptureWindow(popup_shell_surface2.get()));
+
+  auto popup_buffer3 = std::make_unique<Buffer>(
+      exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+  auto popup_surface3 = std::make_unique<Surface>();
+  popup_surface3->Attach(popup_buffer3.get());
+  std::unique_ptr<ShellSurface> popup_shell_surface3(CreatePopupShellSurface(
+      popup_surface3.get(), popup_shell_surface2.get(), gfx::Point(200, 50)));
+  popup_surface3->Commit();
+  // Doesn't change capture.
+  EXPECT_TRUE(IsCaptureWindow(popup_shell_surface2.get()));
+
+  auto popup_buffer4 = std::make_unique<Buffer>(
+      exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+  auto popup_surface4 = std::make_unique<Surface>();
+  popup_surface4->Attach(popup_buffer4.get());
+  std::unique_ptr<ShellSurface> popup_shell_surface4(CreatePopupShellSurface(
+      popup_surface4.get(), popup_shell_surface.get(), gfx::Point(50, 100)));
+  popup_shell_surface4->Grab();
+  popup_surface4->Commit();
+  EXPECT_TRUE(IsCaptureWindow(popup_shell_surface4.get()));
+}
+
+TEST_F(ShellSurfaceTest, GainCaptureFromDescendantSubPopup) {
+  // Test that in the following setup:
+  //
+  //    popup_shell_surface3
+  //  (has grab; loses capture)
+  //              |
+  //    popup_shell_surface2
+  //          (no grab)
+  //              |
+  //    popup_shell_surface1
+  //  (has grab; gains capture)
+  //              |
+  //    popup_shell_surface
+  //
+  // when popup_shell_surface3 is closed, capture is correctly transferred to
+  // popup_shell_surface1.
+
+  gfx::Size buffer_size(256, 256);
+  auto buffer = std::make_unique<Buffer>(
+      exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+  auto surface = std::make_unique<Surface>();
+  auto shell_surface = std::make_unique<ShellSurface>(surface.get());
+  surface->Attach(buffer.get());
+  surface->Commit();
+  shell_surface->GetWidget()->SetBounds(gfx::Rect(0, 0, 256, 256));
+
+  auto popup_buffer = std::make_unique<Buffer>(
+      exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+  auto popup_surface = std::make_unique<Surface>();
+  popup_surface->Attach(popup_buffer.get());
+  std::unique_ptr<ShellSurface> popup_shell_surface(CreatePopupShellSurface(
+      popup_surface.get(), shell_surface.get(), gfx::Point(50, 50)));
+  popup_shell_surface->Grab();
+  popup_surface->Commit();
+  EXPECT_TRUE(IsCaptureWindow(popup_shell_surface.get()));
+
+  auto popup_buffer1 = std::make_unique<Buffer>(
+      exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+  auto popup_surface1 = std::make_unique<Surface>();
+  popup_surface1->Attach(popup_buffer1.get());
+  std::unique_ptr<ShellSurface> popup_shell_surface1(CreatePopupShellSurface(
+      popup_surface1.get(), popup_shell_surface.get(), gfx::Point(100, 50)));
+  popup_shell_surface1->Grab();
+  popup_surface1->Commit();
+  EXPECT_TRUE(IsCaptureWindow(popup_shell_surface1.get()));
+
+  auto popup_buffer2 = std::make_unique<Buffer>(
+      exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+  auto popup_surface2 = std::make_unique<Surface>();
+  popup_surface2->Attach(popup_buffer2.get());
+  std::unique_ptr<ShellSurface> popup_shell_surface2(CreatePopupShellSurface(
+      popup_surface2.get(), popup_shell_surface1.get(), gfx::Point(150, 50)));
+  popup_surface2->Commit();
+  // Doesn't change capture.
+  EXPECT_TRUE(IsCaptureWindow(popup_shell_surface1.get()));
+
+  auto popup_buffer3 = std::make_unique<Buffer>(
+      exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+  auto popup_surface3 = std::make_unique<Surface>();
+  popup_surface3->Attach(popup_buffer3.get());
+  std::unique_ptr<ShellSurface> popup_shell_surface3(CreatePopupShellSurface(
+      popup_surface3.get(), popup_shell_surface2.get(), gfx::Point(200, 50)));
+  popup_shell_surface3->Grab();
+  popup_surface3->Commit();
+  EXPECT_TRUE(IsCaptureWindow(popup_shell_surface3.get()));
+
+  popup_shell_surface3.reset();
+  EXPECT_TRUE(IsCaptureWindow(popup_shell_surface1.get()));
+}
+
 TEST_F(ShellSurfaceTest, Menu) {
   std::unique_ptr<ShellSurface> root_shell_surface =
       test::ShellSurfaceBuilder({256, 256}).BuildShellSurface();
diff --git a/components/lookalikes/core/lookalike_url_util.cc b/components/lookalikes/core/lookalike_url_util.cc
index 9580357..682ac68 100644
--- a/components/lookalikes/core/lookalike_url_util.cc
+++ b/components/lookalikes/core/lookalike_url_util.cc
@@ -943,7 +943,7 @@
 }
 
 bool ShouldBlockLookalikeUrlNavigation(LookalikeUrlMatchType match_type) {
-  if (match_type == LookalikeUrlMatchType::kSiteEngagement) {
+  if (match_type == LookalikeUrlMatchType::kSkeletonMatchSiteEngagement) {
     return true;
   }
   if (match_type == LookalikeUrlMatchType::kTargetEmbedding) {
@@ -980,7 +980,7 @@
     DCHECK_NE(navigated_domain.domain_and_registry, matched_engaged_domain);
     if (!matched_engaged_domain.empty()) {
       *matched_domain = matched_engaged_domain;
-      *match_type = LookalikeUrlMatchType::kSiteEngagement;
+      *match_type = LookalikeUrlMatchType::kSkeletonMatchSiteEngagement;
       return true;
     }
 
@@ -1052,7 +1052,7 @@
 
 void RecordUMAFromMatchType(LookalikeUrlMatchType match_type) {
   switch (match_type) {
-    case LookalikeUrlMatchType::kSiteEngagement:
+    case LookalikeUrlMatchType::kSkeletonMatchSiteEngagement:
       RecordEvent(NavigationSuggestionEvent::kMatchSiteEngagement);
       break;
     case LookalikeUrlMatchType::kEditDistance:
diff --git a/components/lookalikes/core/lookalike_url_util.h b/components/lookalikes/core/lookalike_url_util.h
index 5bf89f7..fd997a59 100644
--- a/components/lookalikes/core/lookalike_url_util.h
+++ b/components/lookalikes/core/lookalike_url_util.h
@@ -57,7 +57,7 @@
   kNone = 0,
   // DEPRECATED: Use kSkeletonMatchTop500 or kSkeletonMatchTop5k.
   // kTopSite = 1,
-  kSiteEngagement = 2,
+  kSkeletonMatchSiteEngagement = 2,
   kEditDistance = 3,
   kEditDistanceSiteEngagement = 4,
   kTargetEmbedding = 5,
diff --git a/components/omnibox/browser/autocomplete_controller.cc b/components/omnibox/browser/autocomplete_controller.cc
index 43a109c..d6bb3fd 100644
--- a/components/omnibox/browser/autocomplete_controller.cc
+++ b/components/omnibox/browser/autocomplete_controller.cc
@@ -1238,6 +1238,7 @@
   if (notify_default_match)
     notify_changed_default_match_ = true;
   if (done_ || in_start_) {
+    notify_changed_debouncer_.ResetTimeLastRun();
     NotifyChanged();
   } else {
     notify_changed_debouncer_.RequestRun(base::BindOnce(
diff --git a/components/omnibox/browser/autocomplete_match.cc b/components/omnibox/browser/autocomplete_match.cc
index a2a2299..ea2f81a 100644
--- a/components/omnibox/browser/autocomplete_match.cc
+++ b/components/omnibox/browser/autocomplete_match.cc
@@ -833,21 +833,8 @@
     const GURL& url,
     const AutocompleteInput& input,
     const TemplateURLService* template_url_service,
-    const std::u16string& keyword) {
-  static const bool optimize =
-      base::FeatureList::IsEnabled(omnibox::kStrippedGurlOptimization);
-  return optimize ? GURLToStrippedGURLOptimized(url, input,
-                                                template_url_service, keyword)
-                  : GURLToStrippedGURLControl(url, input, template_url_service,
-                                              keyword);
-}
-
-// static
-GURL AutocompleteMatch::GURLToStrippedGURLControl(
-    const GURL& url,
-    const AutocompleteInput& input,
-    const TemplateURLService* template_url_service,
-    const std::u16string& keyword) {
+    const std::u16string& keyword,
+    const bool keep_search_intent_params) {
   if (!url.is_valid())
     return url;
 
@@ -860,106 +847,33 @@
   GURL stripped_destination_url = url;
 
   // If the destination URL looks like it was generated from a TemplateURL,
-  // remove all substitutions other than the search terms.  This allows us
-  // to eliminate cases like past search URLs from history that differ only
-  // by some obscure query param from each other or from the search/keyword
-  // provider matches.
+  // remove all substitutions other than the search terms and optionally the
+  // search intent params. This allows eliminating cases like past search URLs
+  // from history that differ only by some obscure query param from each other
+  // or from the search/keyword provider matches.
   const TemplateURL* template_url = GetTemplateURLWithKeyword(
       template_url_service, keyword, stripped_destination_url.host());
   if (template_url != nullptr &&
       template_url->SupportsReplacement(
           template_url_service->search_terms_data())) {
-    std::u16string search_terms;
-    if (template_url->ExtractSearchTermsFromURL(
-            stripped_destination_url, template_url_service->search_terms_data(),
-            &search_terms)) {
-      stripped_destination_url =
-          GURL(template_url->url_ref().ReplaceSearchTerms(
-              TemplateURLRef::SearchTermsArgs(search_terms),
-              template_url_service->search_terms_data()));
-    }
-  }
-
-  // |replacements| keeps all the substitutions we're going to make to
-  // from {destination_url} to {stripped_destination_url}.  |need_replacement|
-  // is a helper variable that helps us keep track of whether we need
-  // to apply the replacement.
-  bool needs_replacement = false;
-  GURL::Replacements replacements;
-
-  // Remove the www. prefix from the host.
-  static const char prefix[] = "www.";
-  static const size_t prefix_len = std::size(prefix) - 1;
-  std::string host = stripped_destination_url.host();
-  if (host.compare(0, prefix_len, prefix) == 0 && host.length() > prefix_len) {
-    replacements.SetHostStr(base::StringPiece(host).substr(prefix_len));
-    needs_replacement = true;
-  }
-
-  // Replace https protocol with http, as long as the user didn't explicitly
-  // specify one of the two.
-  if (stripped_destination_url.SchemeIs(url::kHttpsScheme) &&
-      (input.terms_prefixed_by_http_or_https().empty() ||
-       !WordMatchesURLContent(input.terms_prefixed_by_http_or_https(), url))) {
-    replacements.SetSchemeStr(url::kHttpScheme);
-    needs_replacement = true;
-  }
-
-  if (input.parts().ref.is_empty() && url.has_ref()) {
-    replacements.ClearRef();
-    needs_replacement = true;
-  }
-
-  if (needs_replacement)
-    stripped_destination_url =
-        stripped_destination_url.ReplaceComponents(replacements);
-  return stripped_destination_url;
-}
-
-// static
-GURL AutocompleteMatch::GURLToStrippedGURLOptimized(
-    const GURL& url,
-    const AutocompleteInput& input,
-    const TemplateURLService* template_url_service,
-    const std::u16string& keyword) {
-  if (!url.is_valid())
-    return url;
-
-  // Special-case canonicalizing Docs URLs. This logic is self-contained and
-  // will not participate in the TemplateURL canonicalization.
-  GURL docs_url = DocumentProvider::GetURLForDeduping(url);
-  if (docs_url.is_valid())
-    return docs_url;
-
-  GURL stripped_destination_url = url;
-
-  // If the destination URL looks like it was generated from a TemplateURL,
-  // remove all substitutions other than the search terms.  This allows us
-  // to eliminate cases like past search URLs from history that differ only
-  // by some obscure query param from each other or from the search/keyword
-  // provider matches.
-  const TemplateURL* template_url = GetTemplateURLWithKeyword(
-      template_url_service, keyword, stripped_destination_url.host());
-  if (template_url != nullptr &&
-      template_url->SupportsReplacement(
-          template_url_service->search_terms_data())) {
-    static base::LRUCache<std::pair<const TemplateURL*, GURL>, GURL>
-        template_cache(30);
-    const std::pair<const TemplateURL*, GURL> cache_key = {template_url, url};
-    const auto& cached = template_cache.Get(cache_key);
-    if (cached != template_cache.end()) {
-      stripped_destination_url = cached->second;
-    } else {
-      std::u16string search_terms;
-      if (template_url->ExtractSearchTermsFromURL(
-              stripped_destination_url,
-              template_url_service->search_terms_data(), &search_terms)) {
-        stripped_destination_url =
-            GURL(template_url->url_ref().ReplaceSearchTerms(
-                TemplateURLRef::SearchTermsArgs(search_terms),
-                template_url_service->search_terms_data()));
+    static const bool optimize =
+        base::FeatureList::IsEnabled(omnibox::kStrippedGurlOptimization);
+    if (optimize) {
+      using CacheKey = std::tuple<const TemplateURL*, GURL, bool>;
+      static base::LRUCache<CacheKey, GURL> template_cache(30);
+      const CacheKey cache_key = {template_url, url, keep_search_intent_params};
+      const auto& cached = template_cache.Get(cache_key);
+      if (cached != template_cache.end()) {
+        stripped_destination_url = cached->second;
+      } else if (template_url->KeepSearchTermsInURL(
+                     url, template_url_service->search_terms_data(),
+                     keep_search_intent_params, &stripped_destination_url)) {
         template_cache.Put(cache_key, stripped_destination_url);
       }
+    } else {
+      template_url->KeepSearchTermsInURL(
+          url, template_url_service->search_terms_data(),
+          keep_search_intent_params, &stripped_destination_url);
     }
   }
 
@@ -1083,8 +997,9 @@
   // the document provider, and overwriting them here would be wasteful and, in
   // the case of the document provider, prevent potential deduping.
   if (stripped_destination_url.is_empty()) {
-    stripped_destination_url = GURLToStrippedGURL(
-        destination_url, input, template_url_service, keyword);
+    stripped_destination_url =
+        GURLToStrippedGURL(destination_url, input, template_url_service,
+                           keyword, /*keep_search_intent_params=*/false);
   }
 }
 
diff --git a/components/omnibox/browser/autocomplete_match.h b/components/omnibox/browser/autocomplete_match.h
index f3e4b08d..1473aba 100644
--- a/components/omnibox/browser/autocomplete_match.h
+++ b/components/omnibox/browser/autocomplete_match.h
@@ -370,41 +370,41 @@
       const std::u16string& keyword,
       const std::string& host);
 
-  // Returns |url| altered by stripping off "www.", converting https protocol
-  // to http, and stripping excess query parameters.  These conversions are
-  // merely to allow comparisons to remove likely duplicates; these URLs are
-  // not used as actual destination URLs.
-  // - |input| is used to decide if the scheme is allowed to be altered during
+  // Returns `url` altered by stripping off "www.", converting https protocol
+  // to http, and stripping query params other than the search terms. If
+  // `keep_search_intent_params` is true, also keep search intent params which
+  // disambiguate the search terms and determine the fulfillment.
+  // These conversions are meant to allow URL comparisons to find likely
+  // duplicates; and these URLs are not used as actual destination URLs.
+  // In most use cases `keep_search_intent_params` need not be true, e.g., when
+  // computing `stripped_destination_url` for matches. Otherwise, keeping the
+  // search intent params would create an unnecessary level of granularity which
+  // prevents proper deduping of matches from various local or remote providers.
+  // If a provider wishes to prevent its matches (or a subset of them) from
+  // being deduped with other matches with the same search terms, it must
+  // precompute `stripped_destination_url` while maintaining the search intent
+  // params. A notable example is when multiple entity suggestions with the same
+  // search terms are offered by SearchProvider or ZeroSuggestProvider. In that
+  // case, the entity matches (with the exception of the first one) keep their
+  // search intent params in `stripped_destination_url` to avoid being deduped.
+  // - `input` is used to decide if the scheme is allowed to be altered during
   //   stripping.  If this URL, minus the scheme and separator, starts with any
   //   the terms in input.terms_prefixed_by_http_or_https(), we avoid converting
   //   an HTTPS scheme to HTTP.  This means URLs that differ only by these
   //   schemes won't be marked as dupes, since the distinction seems to matter
   //   to the user.
-  // - If |template_url_service| is not NULL, it is used to get a template URL
-  //   corresponding to this match, which is used to strip off query args other
-  //   than the search terms themselves that would otherwise prevent doing
-  //   proper deduping.
-  // - If the match's keyword is known, it can be provided in |keyword|.
+  // - If `template_url_service` is not NULL, it is used to get a template URL
+  //   corresponding to this match, which is used to strip off query params
+  //   other than the search terms (and optionally search intent params) that
+  //   would otherwise prevent proper comparison/deduping.
+  // - If the match's keyword is known, it can be provided in `keyword`.
   //   Otherwise, it can be left empty and the template URL (if any) is
   //   determined from the destination's hostname.
   static GURL GURLToStrippedGURL(const GURL& url,
                                  const AutocompleteInput& input,
                                  const TemplateURLService* template_url_service,
-                                 const std::u16string& keyword);
-
-  // One of these 2 helpers are called by `GURLToStrippedGURL()` depending on
-  // whether optimizations (i.e., caching search term replacements) are enabled.
-  // They will be removed after experiments end.
-  static GURL GURLToStrippedGURLControl(
-      const GURL& url,
-      const AutocompleteInput& input,
-      const TemplateURLService* template_url_service,
-      const std::u16string& keyword);
-  static GURL GURLToStrippedGURLOptimized(
-      const GURL& url,
-      const AutocompleteInput& input,
-      const TemplateURLService* template_url_service,
-      const std::u16string& keyword);
+                                 const std::u16string& keyword,
+                                 const bool keep_search_intent_params);
 
   // Sets the |match_in_scheme| and |match_in_subdomain| flags based on the
   // provided |url| and list of substring |match_positions|. |match_positions|
diff --git a/components/omnibox/browser/autocomplete_provider_debouncer.cc b/components/omnibox/browser/autocomplete_provider_debouncer.cc
index 2be736e..c36ff61 100644
--- a/components/omnibox/browser/autocomplete_provider_debouncer.cc
+++ b/components/omnibox/browser/autocomplete_provider_debouncer.cc
@@ -32,6 +32,12 @@
   timer_.Stop();
 }
 
+void AutocompleteProviderDebouncer::ResetTimeLastRun() {
+  time_last_run_ = base::TimeTicks::Now();
+  if (timer_.IsRunning())
+    RequestRun(std::move(callback_));
+}
+
 void AutocompleteProviderDebouncer::Run() {
   time_last_run_ = base::TimeTicks::Now();
   std::move(callback_).Run();
diff --git a/components/omnibox/browser/autocomplete_provider_debouncer.h b/components/omnibox/browser/autocomplete_provider_debouncer.h
index 00504c1..faccb62f 100644
--- a/components/omnibox/browser/autocomplete_provider_debouncer.h
+++ b/components/omnibox/browser/autocomplete_provider_debouncer.h
@@ -10,7 +10,8 @@
 #include "base/timer/timer.h"
 
 // Debounces a method call, i.e. throttles its call rate by delaying its
-// invocations and cancelling pending ones when new ones are requested.
+// invocations and cancelling pending ones when new ones are requested. Each
+// instance should be used in a single thread to avoid bad `callback_`.
 class AutocompleteProviderDebouncer {
  public:
   AutocompleteProviderDebouncer(bool from_last_run, int delay_ms);
@@ -25,6 +26,16 @@
   // Cancels any pending request.
   void CancelRequest();
 
+  // Resets `time_last_run_` to now. Should be called when the debounced method
+  // was called externally. E.g., if there are 2 flows to call `X()`:
+  // 1) `X()`
+  // 2) `debouncer.RequestRun(base::BindOnce(&X))`
+  // When (1) occurs prior to (2), it might want to also invoke
+  // `debouncer.ResetTimeLastRan()` to make sure the 2nd call to `X()` doesn't
+  // occur in rapid succession.
+  // Will delay both future `RequestRun()` as well as any pending requests.
+  void ResetTimeLastRun();
+
  private:
   void Run();
 
diff --git a/components/omnibox/browser/document_provider.cc b/components/omnibox/browser/document_provider.cc
index 0fc85b77..4fa943b 100644
--- a/components/omnibox/browser/document_provider.cc
+++ b/components/omnibox/browser/document_provider.cc
@@ -953,7 +953,7 @@
       // |matches_cache_|.
       match.stripped_destination_url = AutocompleteMatch::GURLToStrippedGURL(
           GURL(*original_url), input_, client_->GetTemplateURLService(),
-          std::u16string());
+          std::u16string(), /*keep_search_intent_params=*/false);
     }
 
     match.contents =
diff --git a/components/omnibox/browser/shortcuts_provider.cc b/components/omnibox/browser/shortcuts_provider.cc
index 97645a72..354d076 100644
--- a/components/omnibox/browser/shortcuts_provider.cc
+++ b/components/omnibox/browser/shortcuts_provider.cc
@@ -261,7 +261,7 @@
 
     const GURL stripped_destination_url(AutocompleteMatch::GURLToStrippedGURL(
         shortcut.match_core.destination_url, input, template_url_service,
-        shortcut.match_core.keyword));
+        shortcut.match_core.keyword, /*keep_search_intent_params=*/false));
     shortcuts_by_url[stripped_destination_url].push_back(&shortcut);
   }
 
diff --git a/components/omnibox/common/omnibox_features.cc b/components/omnibox/common/omnibox_features.cc
index f8fdb4c..0e9d268 100644
--- a/components/omnibox/common/omnibox_features.cc
+++ b/components/omnibox/common/omnibox_features.cc
@@ -156,6 +156,12 @@
              "DisambiguateEntitySuggestions",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
+// If enabled, takes the search intent query params into account for triggering
+// switch to tab actions on matches.
+BASE_FEATURE(kDisambiguateTabMatchingForEntitySuggestions,
+             "DisambiguateTabMatchingForEntitySuggestions",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
 // Used to adjust the relevance for the local history zero-prefix suggestions.
 // If enabled, the relevance is determined by this feature's companion
 // parameter, OmniboxFieldTrial::kLocalHistoryZeroSuggestRelevanceScore.
diff --git a/components/omnibox/common/omnibox_features.h b/components/omnibox/common/omnibox_features.h
index 85f23c0..66a47d5 100644
--- a/components/omnibox/common/omnibox_features.h
+++ b/components/omnibox/common/omnibox_features.h
@@ -44,6 +44,7 @@
 
 // Entity suggestion disambiguation.
 BASE_DECLARE_FEATURE(kDisambiguateEntitySuggestions);
+BASE_DECLARE_FEATURE(kDisambiguateTabMatchingForEntitySuggestions);
 
 // Local history zero-prefix (aka zero-suggest) and prefix suggestions.
 BASE_DECLARE_FEATURE(kAdjustLocalHistoryZeroSuggestRelevanceScore);
diff --git a/components/remote_cocoa/app_shim/immersive_mode_controller.h b/components/remote_cocoa/app_shim/immersive_mode_controller.h
index d2dc1a2..f0f0dd4 100644
--- a/components/remote_cocoa/app_shim/immersive_mode_controller.h
+++ b/components/remote_cocoa/app_shim/immersive_mode_controller.h
@@ -59,10 +59,30 @@
   NSWindow* const browser_widget_;
   NSWindow* const overlay_widget_;
 
+  // A controller for top chrome.
   base::scoped_nsobject<ImmersiveModeTitlebarViewController>
       immersive_mode_titlebar_view_controller_;
+
+  // A "clear" controller for locking the titlebar in place. Unfortunately
+  // there is no discovered way to make a controller actually clear. The
+  // controller's view is added to a discrete NSWindow controlled by AppKit.
+  // Making the view clear will simply make the underling portion of the
+  // NSWindow visible. To achieve "clear" this controller immediately hides
+  // itself. This has the side effect of still extending the mouse capture area
+  // allowing the title bar to stay visible while this controller's view is
+  // hidden.
   base::scoped_nsobject<ClearTitlebarViewController>
       clear_titlebar_view_controller_;
+
+  // A controller that keeps a small portion (0.5px) of the fullscreen AppKit
+  // NSWindow on screen.
+  // This controller is used as a workaround for an AppKit bug that displays a
+  // black bar when changing a NSTitlebarAccessoryViewController's
+  // fullScreenMinHeight from zero to non-zero.
+  // TODO(https://crbug.com/1369643): Remove when fixed by Apple.
+  base::scoped_nsobject<NSTitlebarAccessoryViewController>
+      thin_titlebar_view_controller_;
+
   base::scoped_nsobject<ImmersiveModeMapper> immersive_mode_mapper_;
   base::scoped_nsobject<ImmersiveModeWindowObserver>
       immersive_mode_window_observer_;
diff --git a/components/remote_cocoa/app_shim/immersive_mode_controller.mm b/components/remote_cocoa/app_shim/immersive_mode_controller.mm
index 5b69d4b..494df274 100644
--- a/components/remote_cocoa/app_shim/immersive_mode_controller.mm
+++ b/components/remote_cocoa/app_shim/immersive_mode_controller.mm
@@ -14,6 +14,8 @@
 
 namespace {
 
+const double kThinControllerHeight = 0.5;
+
 // TODO(https://crbug.com/1373552): use constraints / autoresizingmask instead
 // of manually setting the frame size.
 void PropagateFrameSizeToViewsSubviews(NSView* view) {
@@ -275,6 +277,14 @@
   immersive_mode_window_observer_.reset([[ImmersiveModeWindowObserver alloc]
       initWithController:weak_ptr_factory_.GetWeakPtr()]);
 
+  // A style of NSTitlebarSeparatorStyleAutomatic (default) will show a black
+  // line separator when removing the NSWindowStyleMaskFullSizeContentView style
+  // bit. We do not want a separator. Pre-macOS 11 there is no titlebar
+  // separator.
+  if (@available(macOS 11.0, *)) {
+    browser_widget_.titlebarSeparatorStyle = NSTitlebarSeparatorStyleNone;
+  }
+
   // Create a new NSTitlebarAccessoryViewController that will host the
   // overlay_view_.
   immersive_mode_titlebar_view_controller_.reset(
@@ -322,6 +332,15 @@
   immersive_mode_titlebar_view_controller_.get().layoutAttribute =
       NSLayoutAttributeBottom;
 
+  thin_titlebar_view_controller_.reset(
+      [[NSTitlebarAccessoryViewController alloc] init]);
+  thin_titlebar_view_controller_.get().view =
+      [[[NSView alloc] init] autorelease];
+  thin_titlebar_view_controller_.get().layoutAttribute =
+      NSLayoutAttributeBottom;
+  thin_titlebar_view_controller_.get().fullScreenMinHeight =
+      kThinControllerHeight;
+
   ObserveOverlayChildWindows();
 }
 
@@ -330,6 +349,7 @@
   [immersive_mode_titlebar_view_controller_ setTitlebarObserver:nil];
 
   // Rollback the view shuffling from enablement.
+  [thin_titlebar_view_controller_ removeFromParentViewController];
   NSView* overlay_content_view =
       immersive_mode_titlebar_view_controller_.get().view.subviews.firstObject;
   [overlay_content_view removeFromSuperview];
@@ -338,6 +358,9 @@
   [immersive_mode_titlebar_view_controller_.get().view release];
   immersive_mode_titlebar_view_controller_.reset();
   browser_widget_.styleMask |= NSWindowStyleMaskFullSizeContentView;
+  if (@available(macOS 11.0, *)) {
+    browser_widget_.titlebarSeparatorStyle = NSTitlebarSeparatorStyleAutomatic;
+  }
 }
 
 void ImmersiveModeController::Enable() {
@@ -345,6 +368,11 @@
   enabled_ = true;
   [browser_widget_ addTitlebarAccessoryViewController:
                        immersive_mode_titlebar_view_controller_];
+  [browser_widget_
+      addTitlebarAccessoryViewController:thin_titlebar_view_controller_];
+  NSRect frame = thin_titlebar_view_controller_.get().view.frame;
+  frame.size.height = kThinControllerHeight;
+  thin_titlebar_view_controller_.get().view.frame = frame;
 }
 
 void ImmersiveModeController::OnTopViewBoundsChanged(const gfx::Rect& bounds) {
@@ -372,6 +400,7 @@
     case mojom::ToolbarVisibilityStyle::kAlways:
       immersive_mode_titlebar_view_controller_.get().fullScreenMinHeight =
           immersive_mode_titlebar_view_controller_.get().view.frame.size.height;
+      thin_titlebar_view_controller_.get().hidden = YES;
       browser_widget_.styleMask &= ~NSWindowStyleMaskFullSizeContentView;
 
       // Toggling the controller will allow the content view to resize below Top
@@ -381,10 +410,17 @@
       break;
     case mojom::ToolbarVisibilityStyle::kAutohide:
       immersive_mode_titlebar_view_controller_.get().hidden = NO;
+
+      // The thin titlebar controller keeps a tiny portion of the AppKit
+      // fullscreen NSWindow on screen as a workaround for
+      // https://crbug.com/1369643.
+      thin_titlebar_view_controller_.get().hidden = NO;
+
       immersive_mode_titlebar_view_controller_.get().fullScreenMinHeight = 0;
       browser_widget_.styleMask |= NSWindowStyleMaskFullSizeContentView;
       break;
     case mojom::ToolbarVisibilityStyle::kNone:
+      thin_titlebar_view_controller_.get().hidden = YES;
       immersive_mode_titlebar_view_controller_.get().hidden = YES;
       break;
   }
@@ -409,7 +445,8 @@
   }
 
   clear_titlebar_view_controller_.reset([[ClearTitlebarViewController alloc]
-      initWithHeight:browser_widget_.contentView.frame.size.height]);
+      initWithHeight:browser_widget_.contentView.frame.size.height -
+                     kThinControllerHeight]);
   clear_titlebar_view_controller_.get().view =
       [[[NSView alloc] init] autorelease];
   clear_titlebar_view_controller_.get().layoutAttribute =
diff --git a/components/reporting/client/report_queue.cc b/components/reporting/client/report_queue.cc
index d3fb73a..26c8895 100644
--- a/components/reporting/client/report_queue.cc
+++ b/components/reporting/client/report_queue.cc
@@ -12,6 +12,7 @@
 #include "base/callback.h"
 #include "base/json/json_writer.h"
 #include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/sequence_checker.h"
 #include "base/strings/strcat.h"
 #include "base/time/time.h"
@@ -45,6 +46,12 @@
   }
   return protobuf_record;
 }
+
+void EnqueueResponded(ReportQueue::EnqueueCallback callback, Status status) {
+  base::UmaHistogramEnumeration(ReportQueue::kEnqueueMetricsName, status.code(),
+                                error::Code::MAX_VALUE);
+  std::move(callback).Run(status);
+}
 }  // namespace
 
 ReportQueue::~ReportQueue() = default;
@@ -57,14 +64,15 @@
                           return std::move(record);
                         },
                         std::move(record)),
-                    priority, std::move(callback));
+                    priority,
+                    base::BindOnce(&EnqueueResponded, std::move(callback)));
 }
 
 void ReportQueue::Enqueue(base::Value::Dict record,
                           Priority priority,
                           ReportQueue::EnqueueCallback callback) const {
   AddProducedRecord(base::BindOnce(&ValueToJson, std::move(record)), priority,
-                    std::move(callback));
+                    base::BindOnce(&EnqueueResponded, std::move(callback)));
 }
 
 void ReportQueue::Enqueue(
@@ -72,7 +80,7 @@
     Priority priority,
     ReportQueue::EnqueueCallback callback) const {
   AddProducedRecord(base::BindOnce(&ProtoToString, std::move(record)), priority,
-                    std::move(callback));
+                    base::BindOnce(&EnqueueResponded, std::move(callback)));
 }
 
 }  // namespace reporting
diff --git a/components/reporting/client/report_queue.h b/components/reporting/client/report_queue.h
index 7db0dfb..2800b579 100644
--- a/components/reporting/client/report_queue.h
+++ b/components/reporting/client/report_queue.h
@@ -113,6 +113,10 @@
   // A FlushCallback is called on the completion of |Flush| call.
   using FlushCallback = base::OnceCallback<void(Status)>;
 
+  // Enqueue metrics name
+  static constexpr char kEnqueueMetricsName[] =
+      "Browser.ERP.EventEnqueueResult";
+
   virtual ~ReportQueue();
 
   // Enqueue asynchronously stores and delivers a record.  The |callback| will
diff --git a/components/reporting/client/report_queue_unittest.cc b/components/reporting/client/report_queue_unittest.cc
index b975111..441c042c 100644
--- a/components/reporting/client/report_queue_unittest.cc
+++ b/components/reporting/client/report_queue_unittest.cc
@@ -5,7 +5,9 @@
 #include "components/reporting/client/report_queue.h"
 
 #include "base/bind.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/strings/strcat.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/task_environment.h"
 #include "components/reporting/client/mock_report_queue.h"
 #include "components/reporting/proto/synced/record.pb.h"
@@ -17,6 +19,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 using ::testing::_;
+using ::testing::Eq;
 using ::testing::Invoke;
 using ::testing::WithArg;
 
@@ -29,6 +32,8 @@
 
   base::test::TaskEnvironment task_environment_{
       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+
+  base::HistogramTester histogram_tester_;
 };
 
 TEST_F(ReportQueueTest, EnqueueTest) {
@@ -40,6 +45,29 @@
   test::TestEvent<Status> e;
   queue.Enqueue("Record", FAST_BATCH, e.cb());
   ASSERT_OK(e.result());
+  histogram_tester_.ExpectBucketCount(ReportQueue::kEnqueueMetricsName,
+                                      error::OK,
+                                      /*expected_count=*/1);
+  histogram_tester_.ExpectTotalCount(ReportQueue::kEnqueueMetricsName,
+                                     /*count=*/1);
+}
+
+TEST_F(ReportQueueTest, EnqueueWithErrorTest) {
+  MockReportQueue queue;
+  EXPECT_CALL(queue, AddRecord(_, _, _))
+      .WillOnce(WithArg<2>(Invoke([](ReportQueue::EnqueueCallback cb) {
+        std::move(cb).Run(Status(error::CANCELLED, "Cancelled by test"));
+      })));
+  test::TestEvent<Status> e;
+  queue.Enqueue("Record", FAST_BATCH, e.cb());
+  const auto result = e.result();
+  ASSERT_FALSE(result.ok());
+  ASSERT_THAT(result.error_code(), Eq(error::CANCELLED));
+  histogram_tester_.ExpectBucketCount(ReportQueue::kEnqueueMetricsName,
+                                      error::CANCELLED,
+                                      /*expected_count=*/1);
+  histogram_tester_.ExpectTotalCount(ReportQueue::kEnqueueMetricsName,
+                                     /*count=*/1);
 }
 
 TEST_F(ReportQueueTest, FlushTest) {
@@ -52,6 +80,5 @@
   queue.Flush(MANUAL_BATCH, e.cb());
   ASSERT_OK(e.result());
 }
-
 }  // namespace
 }  // namespace reporting
diff --git a/components/reporting/util/status.cc b/components/reporting/util/status.cc
index f3e4e53b..11a2630 100644
--- a/components/reporting/util/status.cc
+++ b/components/reporting/util/status.cc
@@ -11,6 +11,8 @@
 
 #include "base/no_destructor.h"
 #include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_number_conversions_internal.h"
 #include "components/reporting/proto/synced/status.pb.h"
 
 namespace reporting {
@@ -33,8 +35,6 @@
       return "ALREADY_EXISTS";
     case PERMISSION_DENIED:
       return "PERMISSION_DENIED";
-    case UNAUTHENTICATED:
-      return "UNAUTHENTICATED";
     case RESOURCE_EXHAUSTED:
       return "RESOURCE_EXHAUSTED";
     case FAILED_PRECONDITION:
@@ -51,11 +51,11 @@
       return "UNAVAILABLE";
     case DATA_LOSS:
       return "DATA_LOSS";
+    case UNAUTHENTICATED:
+      return "UNAUTHENTICATED";
+    default:
+      return base::StrCat({"ILLEGAL[", base::NumberToString(code), "]"});
   }
-
-  // No default clause, clang will abort if a code is missing from
-  // above switch.
-  return "UNKNOWN";
 }
 }  // namespace error.
 
diff --git a/components/reporting/util/status.h b/components/reporting/util/status.h
index da771ad6..1306c20b 100644
--- a/components/reporting/util/status.h
+++ b/components/reporting/util/status.h
@@ -29,7 +29,6 @@
   NOT_FOUND = 5,
   ALREADY_EXISTS = 6,
   PERMISSION_DENIED = 7,
-  UNAUTHENTICATED = 16,
   RESOURCE_EXHAUSTED = 8,
   FAILED_PRECONDITION = 9,
   ABORTED = 10,
@@ -38,6 +37,7 @@
   INTERNAL = 13,
   UNAVAILABLE = 14,
   DATA_LOSS = 15,
+  UNAUTHENTICATED = 16,
   // The value should always be kept last.
   MAX_VALUE
 };
diff --git a/components/subresource_filter/core/common/indexed_ruleset.cc b/components/subresource_filter/core/common/indexed_ruleset.cc
index 1b0626f..b7b1120 100644
--- a/components/subresource_filter/core/common/indexed_ruleset.cc
+++ b/components/subresource_filter/core/common/indexed_ruleset.cc
@@ -138,7 +138,8 @@
       document_url, parent_document_origin, proto::ELEMENT_TYPE_UNSPECIFIED,
       activation_type,
       FirstPartyOrigin::IsThirdParty(document_url, parent_document_origin),
-      false, EmbedderConditionsMatcher(), FindRuleStrategy::kAny);
+      false, EmbedderConditionsMatcher(), FindRuleStrategy::kAny,
+      {} /* disabled_rule_ids */);
 }
 
 LoadPolicy IndexedRulesetMatcher::GetLoadPolicyForResourceLoad(
@@ -167,11 +168,11 @@
 
   auto find_match =
       [&](const url_pattern_index::UrlPatternIndexMatcher& matcher) {
-        return matcher.FindMatch(url, first_party.origin(), element_type,
-                                 proto::ACTIVATION_TYPE_UNSPECIFIED,
-                                 is_third_party, disable_generic_rules,
-                                 embedder_conditions_matcher,
-                                 FindRuleStrategy::kAny);
+        return matcher.FindMatch(
+            url, first_party.origin(), element_type,
+            proto::ACTIVATION_TYPE_UNSPECIFIED, is_third_party,
+            disable_generic_rules, embedder_conditions_matcher,
+            FindRuleStrategy::kAny, {} /* disabled_rule_ids */);
       };
 
   // Always check the allowlist for subdocuments. For other forms of resources,
diff --git a/components/url_pattern_index/url_pattern_index.cc b/components/url_pattern_index/url_pattern_index.cc
index 0f6cca5..2a804cc 100644
--- a/components/url_pattern_index/url_pattern_index.cc
+++ b/components/url_pattern_index/url_pattern_index.cc
@@ -10,6 +10,7 @@
 
 #include "base/callback.h"
 #include "base/check_op.h"
+#include "base/containers/contains.h"
 #include "base/containers/flat_map.h"
 #include "base/memory/raw_ref.h"
 #include "base/no_destructor.h"
@@ -636,7 +637,8 @@
     bool disable_generic_rules,
     const UrlPatternIndexMatcher::EmbedderConditionsMatcher&
         embedder_conditions_matcher,
-    std::vector<const flat::UrlRule*>* matched_rules) {
+    std::vector<const flat::UrlRule*>* matched_rules,
+    const base::flat_set<int>& disabled_rule_ids) {
   if (!sorted_candidates)
     return nullptr;
 
@@ -664,6 +666,9 @@
     if (!DoesURLMatchRequestDomainList(url, *rule))
       continue;
 
+    if (base::Contains(disabled_rule_ids, rule->id()))
+      continue;
+
     if (matched_rules)
       matched_rules->push_back(rule);
     else
@@ -690,7 +695,8 @@
     const UrlPatternIndexMatcher::EmbedderConditionsMatcher&
         embedder_conditions_matcher,
     UrlPatternIndexMatcher::FindRuleStrategy strategy,
-    std::vector<const flat::UrlRule*>* matched_rules) {
+    std::vector<const flat::UrlRule*>* matched_rules,
+    const base::flat_set<int>& disabled_rule_ids) {
   using FindRuleStrategy = UrlPatternIndexMatcher::FindRuleStrategy;
 
   // Check that the outparam |matched_rules| is specified if and only if
@@ -735,7 +741,7 @@
     const flat::UrlRule* rule = FindMatchAmongCandidates(
         entry->rule_list(), url, document_origin, element_type, activation_type,
         request_method, is_third_party, disable_generic_rules,
-        embedder_conditions_matcher, matched_rules);
+        embedder_conditions_matcher, matched_rules, disabled_rule_ids);
     if (!rule)
       continue;
 
@@ -755,7 +761,7 @@
   const flat::UrlRule* rule = FindMatchAmongCandidates(
       index.fallback_rules(), url, document_origin, element_type,
       activation_type, request_method, is_third_party, disable_generic_rules,
-      embedder_conditions_matcher, matched_rules);
+      embedder_conditions_matcher, matched_rules, disabled_rule_ids);
 
   switch (strategy) {
     case FindRuleStrategy::kAny:
@@ -908,12 +914,13 @@
     bool is_third_party,
     bool disable_generic_rules,
     const EmbedderConditionsMatcher& embedder_conditions_matcher,
-    FindRuleStrategy strategy) const {
+    FindRuleStrategy strategy,
+    const base::flat_set<int>& disabled_rule_ids) const {
   return FindMatch(
       url, first_party_origin, ProtoToFlatElementType(element_type),
       ProtoToFlatActivationType(activation_type), flat::RequestMethod_NONE,
       is_third_party, disable_generic_rules, embedder_conditions_matcher,
-      strategy);
+      strategy, disabled_rule_ids);
 }
 
 const flat::UrlRule* UrlPatternIndexMatcher::FindMatch(
@@ -925,7 +932,8 @@
     bool is_third_party,
     bool disable_generic_rules,
     const EmbedderConditionsMatcher& embedder_conditions_matcher,
-    FindRuleStrategy strategy) const {
+    FindRuleStrategy strategy,
+    const base::flat_set<int>& disabled_rule_ids) const {
   // Ignore URLs that are greater than the max URL length. Since those will be
   // disallowed elsewhere in the loading stack, we can save compute time by
   // avoiding matching here.
@@ -944,7 +952,8 @@
   auto* rule = FindMatchInFlatUrlPatternIndex(
       *flat_index_, UrlPattern::UrlInfo(url), first_party_origin, element_type,
       activation_type, request_method, is_third_party, disable_generic_rules,
-      embedder_conditions_matcher, strategy, nullptr /* matched_rules */);
+      embedder_conditions_matcher, strategy, nullptr /* matched_rules */,
+      disabled_rule_ids);
   if (rule) {
     TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("loading"),
                  "UrlPatternIndexMatcher::FindMatch", "pattern",
@@ -960,11 +969,13 @@
     proto::ActivationType activation_type,
     bool is_third_party,
     bool disable_generic_rules,
-    const EmbedderConditionsMatcher& embedder_conditions_matcher) const {
+    const EmbedderConditionsMatcher& embedder_conditions_matcher,
+    const base::flat_set<int>& disabled_rule_ids) const {
   return FindAllMatches(
       url, first_party_origin, ProtoToFlatElementType(element_type),
       ProtoToFlatActivationType(activation_type), flat::RequestMethod_NONE,
-      is_third_party, disable_generic_rules, embedder_conditions_matcher);
+      is_third_party, disable_generic_rules, embedder_conditions_matcher,
+      disabled_rule_ids);
 }
 
 std::vector<const flat::UrlRule*> UrlPatternIndexMatcher::FindAllMatches(
@@ -975,7 +986,8 @@
     flat::RequestMethod request_method,
     bool is_third_party,
     bool disable_generic_rules,
-    const EmbedderConditionsMatcher& embedder_conditions_matcher) const {
+    const EmbedderConditionsMatcher& embedder_conditions_matcher,
+    const base::flat_set<int>& disabled_rule_ids) const {
   // Ignore URLs that are greater than the max URL length. Since those will be
   // disallowed elsewhere in the loading stack, we can save compute time by
   // avoiding matching here.
@@ -992,7 +1004,8 @@
   FindMatchInFlatUrlPatternIndex(
       *flat_index_, UrlPattern::UrlInfo(url), first_party_origin, element_type,
       activation_type, request_method, is_third_party, disable_generic_rules,
-      embedder_conditions_matcher, FindRuleStrategy::kAll, &rules);
+      embedder_conditions_matcher, FindRuleStrategy::kAll, &rules,
+      disabled_rule_ids);
 
   return rules;
 }
diff --git a/components/url_pattern_index/url_pattern_index.h b/components/url_pattern_index/url_pattern_index.h
index b487136e..f067ad7 100644
--- a/components/url_pattern_index/url_pattern_index.h
+++ b/components/url_pattern_index/url_pattern_index.h
@@ -12,6 +12,7 @@
 #include <vector>
 
 #include "base/callback_forward.h"
+#include "base/containers/flat_set.h"
 #include "base/memory/raw_ptr.h"
 #include "base/strings/string_piece_forward.h"
 #include "components/url_pattern_index/closed_hash_map.h"
@@ -201,7 +202,8 @@
       bool is_third_party,
       bool disable_generic_rules,
       const EmbedderConditionsMatcher& embedder_conditions_matcher,
-      FindRuleStrategy strategy) const;
+      FindRuleStrategy strategy,
+      const base::flat_set<int>& disabled_rule_ids) const;
 
   // Helper function to work with flat::*Type(s). If the index contains one or
   // more UrlRules that match the request, returns one of them depending on
@@ -215,7 +217,8 @@
       bool is_third_party,
       bool disable_generic_rules,
       const EmbedderConditionsMatcher& embedder_conditions_matcher,
-      FindRuleStrategy strategy) const;
+      FindRuleStrategy strategy,
+      const base::flat_set<int>& disabled_rule_ids) const;
 
   // Same as FindMatch, except this function returns all UrlRules that match the
   // request for the index. If no UrlRules match, returns an empty vector.
@@ -226,7 +229,8 @@
       proto::ActivationType activation_type,
       bool is_third_party,
       bool disable_generic_rules,
-      const EmbedderConditionsMatcher& embedder_conditions_matcher) const;
+      const EmbedderConditionsMatcher& embedder_conditions_matcher,
+      const base::flat_set<int>& disabled_rule_ids) const;
 
   // Helper function to work with flat::*Type(s). Returns all UrlRules that
   // match the request for the index. If no UrlRules match, returns an empty
@@ -239,7 +243,8 @@
       flat::RequestMethod request_method,
       bool is_third_party,
       bool disable_generic_rules,
-      const EmbedderConditionsMatcher& embedder_conditions_matcher) const;
+      const EmbedderConditionsMatcher& embedder_conditions_matcher,
+      const base::flat_set<int>& disabled_rule_ids) const;
 
  private:
   // Must outlive this instance.
diff --git a/components/url_pattern_index/url_pattern_index_unittest.cc b/components/url_pattern_index/url_pattern_index_unittest.cc
index cc4b23d..47bc145 100644
--- a/components/url_pattern_index/url_pattern_index_unittest.cc
+++ b/components/url_pattern_index/url_pattern_index_unittest.cc
@@ -13,6 +13,7 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/containers/flat_set.h"
 #include "base/rand_util.h"
 #include "base/ranges/algorithm.h"
 #include "base/strings/string_piece.h"
@@ -100,7 +101,8 @@
       base::StringPiece document_origin_string = base::StringPiece(),
       proto::ElementType element_type = testing::kOther,
       proto::ActivationType activation_type = kNoActivation,
-      bool disable_generic_rules = false) const {
+      bool disable_generic_rules = false,
+      const base::flat_set<int>& disabled_rule_ids = {}) const {
     const GURL url(url_string);
     const url::Origin document_origin =
         testing::GetOrigin(document_origin_string);
@@ -108,7 +110,7 @@
         url, document_origin, element_type, activation_type,
         testing::IsThirdParty(url, document_origin), disable_generic_rules,
         UrlPatternIndexMatcher::EmbedderConditionsMatcher(),
-        UrlPatternIndexMatcher::FindRuleStrategy::kAny);
+        UrlPatternIndexMatcher::FindRuleStrategy::kAny, disabled_rule_ids);
   }
 
   const flat::UrlRule* FindMatch(
@@ -127,7 +129,8 @@
         url, document_origin, element_type, activation_type, request_method,
         testing::IsThirdParty(url, document_origin), disable_generic_rules,
         embedder_conditions_matcher,
-        UrlPatternIndexMatcher::FindRuleStrategy::kAny);
+        UrlPatternIndexMatcher::FindRuleStrategy::kAny,
+        {} /* disabled_rule_ids */);
   }
 
   std::vector<const flat::UrlRule*> FindAllMatches(
@@ -135,25 +138,27 @@
       base::StringPiece document_origin_string,
       proto::ElementType element_type,
       proto::ActivationType activation_type,
-      bool disable_generic_rules) const {
+      bool disable_generic_rules,
+      const base::flat_set<int>& disabled_rule_ids = {}) const {
     const GURL url(url_string);
     const url::Origin document_origin =
         testing::GetOrigin(document_origin_string);
     return index_matcher_->FindAllMatches(
         url, document_origin, element_type, activation_type,
         testing::IsThirdParty(url, document_origin), disable_generic_rules,
-        UrlPatternIndexMatcher::EmbedderConditionsMatcher());
+        UrlPatternIndexMatcher::EmbedderConditionsMatcher(), disabled_rule_ids);
   }
 
   const flat::UrlRule* FindHighestPriorityMatch(
-      base::StringPiece url_string) const {
+      base::StringPiece url_string,
+      const base::flat_set<int>& disabled_rule_ids = {}) const {
     return index_matcher_->FindMatch(
         GURL(url_string), url::Origin(), testing::kOther /*element_type*/,
         kNoActivation /*activation_type*/, true /*is_third_party*/,
         false /*disable_generic_rules*/,
         UrlPatternIndexMatcher::EmbedderConditionsMatcher(),
-        UrlPatternIndexMatcher::FindRuleStrategy::
-            kHighestPriority /*strategy*/);
+        UrlPatternIndexMatcher::FindRuleStrategy::kHighestPriority /*strategy*/,
+        disabled_rule_ids);
   }
 
   bool IsOutOfRange(const flat::UrlRule* rule) const {
@@ -1156,4 +1161,123 @@
   }
 }
 
+TEST_F(UrlPatternIndexTest, FindMatchWithDisabledRuleIds) {
+  const struct {
+    uint32_t id;
+    const char* url_pattern;
+    uint32_t priority;
+  } kRules[] = {{0, "ex1", 0}, {1, "ex11", 1}, {2, "ex111", 2}};
+
+  for (const auto& rule_data : kRules) {
+    AddSimpleUrlRule(rule_data.url_pattern, rule_data.id, rule_data.priority,
+                     flat::OptionFlag_ANY, flat::ElementType_ANY,
+                     flat::RequestMethod_ANY);
+  }
+  Finish();
+
+  const struct {
+    const char* url;
+    base::flat_set<int> disabled_rule_ids;
+    const bool expected_match;
+    // Fields below are valid only if `expected_match` is true.
+    const uint32_t expected_highest_priority_id = UINT32_MAX;
+  } kTestCases[] = {{"http://ex1.com", {}, true, 0},
+                    {"http://ex1.com", {}, true, 0},
+                    {"http://ex1.com", {0}, false},
+                    {"http://ex1.com", {1}, true, 0},
+                    {"http://ex1.com", {0, 1}, false},
+                    {"http://ex11.com", {}, true, 1},
+                    {"http://ex11.com", {}, true, 1},
+                    {"http://ex11.com", {0}, true, 1},
+                    {"http://ex11.com", {1}, true, 0},
+                    {"http://ex11.com", {0, 1}, false},
+                    {"http://ex11.com", {2}, true, 1},
+                    {"http://ex11.com", {0, 2}, true, 1},
+                    {"http://ex11.com", {1, 2}, true, 0},
+                    {"http://ex111.com", {}, true, 2},
+                    {"http://ex111.com", {}, true, 2},
+                    {"http://ex111.com", {0}, true, 2},
+                    {"http://ex111.com", {0, 1}, true, 2},
+                    {"http://ex111.com", {2}, true, 1},
+                    {"http://ex111.com", {0, 2}, true, 1},
+                    {"http://ex111.com", {1, 2}, true, 0},
+                    {"http://ex111.com", {0, 1, 2}, false},
+                    {"http://ex111.com", {3}, true, 2},
+                    {"http://ex111.com", {2, 3}, true, 1}};
+
+  for (const auto& test_case : kTestCases) {
+    SCOPED_TRACE(::testing::Message()
+                 << "UrlPattern: " << test_case.url << "; DisabledRuleIds: "
+                 << ::testing::PrintToString(test_case.disabled_rule_ids));
+
+    const flat::UrlRule* rule = FindMatch(
+        test_case.url, base::StringPiece(), testing::kOther, kNoActivation,
+        false /* disable_generic_rules */, test_case.disabled_rule_ids);
+
+    EXPECT_EQ(test_case.expected_match, !!rule);
+
+    rule = FindHighestPriorityMatch(test_case.url, test_case.disabled_rule_ids);
+    EXPECT_EQ(test_case.expected_match, !!rule);
+    if (test_case.expected_match && rule)
+      EXPECT_EQ(test_case.expected_highest_priority_id, rule->id());
+  }
+}
+
+TEST_F(UrlPatternIndexTest, FindAllMatchesWithDisabledRuleIds) {
+  const struct {
+    uint32_t id;
+    const char* url_pattern;
+  } kRules[] = {{0, "ex1"}, {1, "ex11"}, {2, "ex111"}};
+
+  for (const auto& rule_data : kRules) {
+    AddSimpleUrlRule(rule_data.url_pattern, rule_data.id, 0 /* priority */,
+                     flat::OptionFlag_ANY, flat::ElementType_ANY,
+                     flat::RequestMethod_ANY);
+  }
+  Finish();
+
+  const struct {
+    const char* url;
+    base::flat_set<int> disabled_rule_ids;
+    std::vector<uint32_t> expected_matched_ids;
+  } kTestCases[] = {{"http://ex1.com", {}, {0}},
+                    {"http://ex1.com", {}, {0}},
+                    {"http://ex1.com", {0}, {}},
+                    {"http://ex1.com", {1}, {0}},
+                    {"http://ex1.com", {0, 1}, {}},
+                    {"http://ex11.com", {}, {0, 1}},
+                    {"http://ex11.com", {0}, {1}},
+                    {"http://ex11.com", {1}, {0}},
+                    {"http://ex11.com", {0, 1}, {}},
+                    {"http://ex11.com", {2}, {0, 1}},
+                    {"http://ex11.com", {0, 2}, {1}},
+                    {"http://ex111.com", {}, {0, 1, 2}},
+                    {"http://ex111.com", {}, {0, 1, 2}},
+                    {"http://ex111.com", {0}, {1, 2}},
+                    {"http://ex111.com", {1}, {0, 2}},
+                    {"http://ex111.com", {2}, {0, 1}},
+                    {"http://ex111.com", {0, 2}, {1}},
+                    {"http://ex111.com", {0, 1, 2}, {}},
+                    {"http://ex111.com", {3}, {0, 1, 2}},
+                    {"http://ex111.com", {1, 3}, {0, 2}}};
+
+  for (const auto& test_case : kTestCases) {
+    SCOPED_TRACE(::testing::Message()
+                 << "UrlPattern: " << test_case.url << "; DisabledRuleIds: "
+                 << ::testing::PrintToString(test_case.disabled_rule_ids));
+
+    std::vector<const flat::UrlRule*> matched_rules = FindAllMatches(
+        test_case.url, "" /* document_origin_string */,
+        proto::ELEMENT_TYPE_OTHER, kNoActivation,
+        false /* disable_generic_rules */, test_case.disabled_rule_ids);
+
+    std::vector<uint32_t> actual_matched_ids;
+    for (const auto* rule : matched_rules)
+      actual_matched_ids.push_back(rule->id());
+
+    EXPECT_THAT(actual_matched_ids, ::testing::UnorderedElementsAreArray(
+                                        test_case.expected_matched_ids));
+  }
+}
+
 }  // namespace url_pattern_index
diff --git a/components/viz/common/resources/shared_image_format.cc b/components/viz/common/resources/shared_image_format.cc
index 47d432f..fc541e1 100644
--- a/components/viz/common/resources/shared_image_format.cc
+++ b/components/viz/common/resources/shared_image_format.cc
@@ -152,6 +152,20 @@
   }
 }
 
+int SharedImageFormat::NumChannelsInPlane(int plane_index) const {
+  DCHECK(IsValidPlaneIndex(plane_index));
+  switch (plane_config()) {
+    case PlaneConfig::kY_V_U:
+      return 1;
+    case PlaneConfig::kY_UV:
+      return plane_index == 1 ? 2 : 1;
+    case PlaneConfig::kY_UV_A:
+      return plane_index == 1 ? 2 : 1;
+  }
+  NOTREACHED();
+  return 0;
+}
+
 std::string SharedImageFormat::ToString() const {
   switch (plane_type_) {
     case PlaneType::kUnknown:
diff --git a/components/viz/common/resources/shared_image_format.h b/components/viz/common/resources/shared_image_format.h
index ef7309a4..fe692d9e 100644
--- a/components/viz/common/resources/shared_image_format.h
+++ b/components/viz/common/resources/shared_image_format.h
@@ -113,6 +113,9 @@
   // Returns the size for a plane given `plane_index`.
   gfx::Size GetPlaneSize(int plane_index, const gfx::Size& size) const;
 
+  // Returns number of channels for a plane for multiplanar formats.
+  int NumChannelsInPlane(int plane_index) const;
+
   std::string ToString() const;
 
   // Returns true if the format contains alpha.
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index ac6cba6..a1362429e 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1764,6 +1764,7 @@
     "renderer_host/navigation_request_info.h",
     "renderer_host/navigation_throttle_runner.cc",
     "renderer_host/navigation_throttle_runner.h",
+    "renderer_host/navigation_type.h",
     "renderer_host/navigator.cc",
     "renderer_host/navigator.h",
     "renderer_host/navigator_delegate.h",
diff --git a/content/browser/preloading/prerender/prerender_browsertest.cc b/content/browser/preloading/prerender/prerender_browsertest.cc
index ef04ea90..6328594 100644
--- a/content/browser/preloading/prerender/prerender_browsertest.cc
+++ b/content/browser/preloading/prerender/prerender_browsertest.cc
@@ -45,6 +45,7 @@
 #include "content/browser/renderer_host/frame_tree_node.h"
 #include "content/browser/renderer_host/input/synthetic_tap_gesture.h"
 #include "content/browser/renderer_host/navigation_request.h"
+#include "content/browser/renderer_host/navigation_type.h"
 #include "content/browser/renderer_host/render_frame_host_impl.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
@@ -57,7 +58,6 @@
 #include "content/public/browser/document_user_data.h"
 #include "content/public/browser/global_routing_id.h"
 #include "content/public/browser/navigation_handle.h"
-#include "content/public/browser/navigation_type.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_frame_host.h"
diff --git a/content/browser/renderer_host/navigation_controller_impl.cc b/content/browser/renderer_host/navigation_controller_impl.cc
index 5e36c661..f4fb450 100644
--- a/content/browser/renderer_host/navigation_controller_impl.cc
+++ b/content/browser/renderer_host/navigation_controller_impl.cc
@@ -1416,7 +1416,9 @@
   }
 
   // Do navigation-type specific actions. These will make and commit an entry.
-  details->type = ClassifyNavigation(rfh, params, navigation_request);
+  NavigationType navigation_type =
+      ClassifyNavigation(rfh, params, navigation_request);
+  navigation_request->set_navigation_type(navigation_type);
 
   if (ShouldMaintainTrivialSessionHistory(rfh->frame_tree_node())) {
     // Ensure that this navigation does not add a navigation entry, since
@@ -1431,7 +1433,7 @@
     // pointed out in the issue.
     DCHECK(navigation_request->common_params().should_replace_current_entry ||
            navigation_request->GetReloadType() != ReloadType::NONE ||
-           details->type == NAVIGATION_TYPE_AUTO_SUBFRAME);
+           navigation_type == NAVIGATION_TYPE_AUTO_SUBFRAME);
   }
 
   if (GetLastCommittedEntry()->IsInitialEntry()) {
@@ -1448,8 +1450,8 @@
       // means every subframe navigation that happens while we're on the initial
       // NavigationEntry will always reuse the existing NavigationEntry and
       // just update the corresponding FrameNavigationEntry.
-      DCHECK_EQ(details->type, NAVIGATION_TYPE_AUTO_SUBFRAME);
-    } else if (details->type == NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY) {
+      DCHECK_EQ(navigation_type, NAVIGATION_TYPE_AUTO_SUBFRAME);
+    } else if (navigation_type == NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY) {
       // This is a navigation that modifies the initial NavigationEntry, either
       // for a replacement or a reload. The initial NavigationEntry should
       // retain its "initial NavigationEntry" status in this case.
@@ -1489,10 +1491,10 @@
   // TODO(crbug.com/926009): Handle history.pushState() as well.
   bool keep_pending_entry =
       is_same_document_navigation &&
-      details->type == NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY &&
+      navigation_type == NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY &&
       pending_entry_ && !PendingEntryMatchesRequest(navigation_request);
 
-  switch (details->type) {
+  switch (navigation_type) {
     case NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY:
       RendererDidNavigateToNewEntry(
           rfh, params, details->is_same_document, details->did_replace_entry,
@@ -1563,7 +1565,7 @@
     // These are both only available from details at this point, so we capture
     // them here.
     SCOPED_CRASH_KEY_NUMBER("BFCacheMismatch", "navigation_type",
-                            details->type);
+                            navigation_type);
     SCOPED_CRASH_KEY_BOOL("BFCacheMismatch", "did_replace",
                           details->did_replace_entry);
     active_entry->back_forward_cache_metrics()->DidCommitNavigation(
diff --git a/content/browser/renderer_host/navigation_controller_impl.h b/content/browser/renderer_host/navigation_controller_impl.h
index b825b00..24c0acb 100644
--- a/content/browser/renderer_host/navigation_controller_impl.h
+++ b/content/browser/renderer_host/navigation_controller_impl.h
@@ -23,11 +23,11 @@
 #include "content/browser/renderer_host/back_forward_cache_impl.h"
 #include "content/browser/renderer_host/navigation_controller_delegate.h"
 #include "content/browser/renderer_host/navigation_entry_impl.h"
+#include "content/browser/renderer_host/navigation_type.h"
 #include "content/browser/ssl/ssl_manager.h"
 #include "content/common/content_export.h"
 #include "content/common/navigation_client.mojom-forward.h"
 #include "content/public/browser/navigation_controller.h"
-#include "content/public/browser/navigation_type.h"
 #include "content/public/browser/reload_type.h"
 #include "mojo/public/cpp/bindings/pending_associated_remote.h"
 #include "services/network/public/mojom/source_location.mojom-forward.h"
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index 60177b7..d349de1a 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -6300,8 +6300,7 @@
     const mojom::DidCommitProvisionalLoadParams& params,
     bool navigation_entry_committed,
     bool did_replace_entry,
-    const GURL& previous_main_frame_url,
-    NavigationType navigation_type) {
+    const GURL& previous_main_frame_url) {
   common_params_->url = params.url;
   did_replace_entry_ = did_replace_entry;
   should_update_history_ = params.should_update_history;
@@ -6319,7 +6318,6 @@
     should_update_history_ = false;
   }
   previous_main_frame_url_ = previous_main_frame_url;
-  navigation_type_ = navigation_type;
 
   // When the embedder navigates a fenced frame root, the navigation
   // installs a new set of inner fenced frame properties.
diff --git a/content/browser/renderer_host/navigation_request.h b/content/browser/renderer_host/navigation_request.h
index ab63175..000ce98 100644
--- a/content/browser/renderer_host/navigation_request.h
+++ b/content/browser/renderer_host/navigation_request.h
@@ -30,6 +30,7 @@
 #include "content/browser/renderer_host/navigation_entry_impl.h"
 #include "content/browser/renderer_host/navigation_policy_container_builder.h"
 #include "content/browser/renderer_host/navigation_throttle_runner.h"
+#include "content/browser/renderer_host/navigation_type.h"
 #include "content/browser/renderer_host/policy_container_host.h"
 #include "content/browser/renderer_host/render_frame_host_csp_context.h"
 #include "content/browser/renderer_host/render_frame_host_impl.h"
@@ -41,7 +42,6 @@
 #include "content/public/browser/global_routing_id.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/navigation_throttle.h"
-#include "content/public/browser/navigation_type.h"
 #include "content/public/browser/peak_gpu_memory_tracker.h"
 #include "content/public/browser/prerender_trigger_type.h"
 #include "content/public/browser/render_process_host_observer.h"
@@ -575,14 +575,17 @@
   void DidCommitNavigation(const mojom::DidCommitProvisionalLoadParams& params,
                            bool navigation_entry_committed,
                            bool did_replace_entry,
-                           const GURL& previous_main_frame_url,
-                           NavigationType navigation_type);
+                           const GURL& previous_main_frame_url);
 
   NavigationType navigation_type() const {
     DCHECK(state_ == DID_COMMIT || state_ == DID_COMMIT_ERROR_PAGE);
     return navigation_type_;
   }
 
+  void set_navigation_type(NavigationType navigation_type) {
+    navigation_type_ = navigation_type;
+  }
+
   const std::string& post_commit_error_page_html() {
     return post_commit_error_page_html_;
   }
diff --git a/content/public/browser/navigation_type.h b/content/browser/renderer_host/navigation_type.h
similarity index 94%
rename from content/public/browser/navigation_type.h
rename to content/browser/renderer_host/navigation_type.h
index 8f67e05..9bc2a43 100644
--- a/content/public/browser/navigation_type.h
+++ b/content/browser/renderer_host/navigation_type.h
@@ -2,14 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_PUBLIC_BROWSER_NAVIGATION_TYPE_H_
-#define CONTENT_PUBLIC_BROWSER_NAVIGATION_TYPE_H_
+#ifndef CONTENT_BROWSER_RENDERER_HOST_NAVIGATION_TYPE_H_
+#define CONTENT_BROWSER_RENDERER_HOST_NAVIGATION_TYPE_H_
 
 namespace content {
 
 // Indicates different types of navigations that can occur that we will handle
 // separately.
-// TODO(crbug.com/1268254): Stop exposing NavigationType outside of //content.
 enum NavigationType {
   // Unknown type.
   NAVIGATION_TYPE_UNKNOWN,
@@ -77,4 +76,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_PUBLIC_BROWSER_NAVIGATION_TYPE_H_
+#endif  // CONTENT_BROWSER_RENDERER_HOST_NAVIGATION_TYPE_H_
diff --git a/content/browser/renderer_host/navigator.cc b/content/browser/renderer_host/navigator.cc
index d24d37fc..8a8b4f5 100644
--- a/content/browser/renderer_host/navigator.cc
+++ b/content/browser/renderer_host/navigator.cc
@@ -633,9 +633,9 @@
   DCHECK(delegate_);
   DCHECK_EQ(!render_frame_host->GetParent(),
             did_navigate ? details.is_main_frame : false);
-  navigation_request->DidCommitNavigation(
-      params, did_navigate, details.did_replace_entry,
-      details.previous_main_frame_url, details.type);
+  navigation_request->DidCommitNavigation(params, did_navigate,
+                                          details.did_replace_entry,
+                                          details.previous_main_frame_url);
 
   // Dispatch PrimaryPageChanged notification when a main frame
   // non-same-document navigation changes the current Page in the FrameTree.
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 1bdcd70..b0ea916 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -13464,7 +13464,7 @@
   if (!GetContentClient()
            ->browser()
            ->GetWebAuthenticationDelegate()
-           ->IsSecurityLevelAcceptableForWebAuthn(this)) {
+           ->IsSecurityLevelAcceptableForWebAuthn(this, effective_origin)) {
     return std::make_pair(blink::mojom::AuthenticatorStatus::CERTIFICATE_ERROR,
                           is_cross_origin);
   }
@@ -13498,7 +13498,7 @@
   if (!GetContentClient()
            ->browser()
            ->GetWebAuthenticationDelegate()
-           ->IsSecurityLevelAcceptableForWebAuthn(this)) {
+           ->IsSecurityLevelAcceptableForWebAuthn(this, effective_origin)) {
     return blink::mojom::AuthenticatorStatus::CERTIFICATE_ERROR;
   }
 
diff --git a/content/browser/renderer_host/render_frame_host_impl_unittest.cc b/content/browser/renderer_host/render_frame_host_impl_unittest.cc
index ede83dd..110959a 100644
--- a/content/browser/renderer_host/render_frame_host_impl_unittest.cc
+++ b/content/browser/renderer_host/render_frame_host_impl_unittest.cc
@@ -693,7 +693,7 @@
  public:
   MOCK_METHOD(bool,
               IsSecurityLevelAcceptableForWebAuthn,
-              (RenderFrameHost*),
+              (RenderFrameHost*, const url::Origin& origin),
               ());
 };
 
@@ -738,8 +738,9 @@
 TEST_F(RenderFrameHostImplWebAuthnTest,
        PerformGetAssertionWebAuthSecurityChecks_TLSError) {
   GURL url("https://doofenshmirtz.evil");
+  const auto origin = url::Origin::Create(url);
   EXPECT_CALL(*webauthn_delegate_,
-              IsSecurityLevelAcceptableForWebAuthn(main_test_rfh()))
+              IsSecurityLevelAcceptableForWebAuthn(main_test_rfh(), origin))
       .WillOnce(testing::Return(false));
   std::pair<blink::mojom::AuthenticatorStatus, bool> result =
       main_test_rfh()->PerformGetAssertionWebAuthSecurityChecks(
@@ -753,8 +754,9 @@
 TEST_F(RenderFrameHostImplWebAuthnTest,
        PerformMakeCredentialWebAuthSecurityChecks_TLSError) {
   GURL url("https://doofenshmirtz.evil");
+  const auto origin = url::Origin::Create(url);
   EXPECT_CALL(*webauthn_delegate_,
-              IsSecurityLevelAcceptableForWebAuthn(main_test_rfh()))
+              IsSecurityLevelAcceptableForWebAuthn(main_test_rfh(), origin))
       .WillOnce(testing::Return(false));
   blink::mojom::AuthenticatorStatus result =
       main_test_rfh()->PerformMakeCredentialWebAuthSecurityChecks(
@@ -767,8 +769,9 @@
 TEST_F(RenderFrameHostImplWebAuthnTest,
        PerformGetAssertionWebAuthSecurityChecks_Success) {
   GURL url("https://owca.org");
+  const auto origin = url::Origin::Create(url);
   EXPECT_CALL(*webauthn_delegate_,
-              IsSecurityLevelAcceptableForWebAuthn(main_test_rfh()))
+              IsSecurityLevelAcceptableForWebAuthn(main_test_rfh(), origin))
       .WillOnce(testing::Return(true));
   std::pair<blink::mojom::AuthenticatorStatus, bool> result =
       main_test_rfh()->PerformGetAssertionWebAuthSecurityChecks(
@@ -782,8 +785,9 @@
 TEST_F(RenderFrameHostImplWebAuthnTest,
        PerformMakeCredentialWebAuthSecurityChecks_Success) {
   GURL url("https://owca.org");
+  const auto origin = url::Origin::Create(url);
   EXPECT_CALL(*webauthn_delegate_,
-              IsSecurityLevelAcceptableForWebAuthn(main_test_rfh()))
+              IsSecurityLevelAcceptableForWebAuthn(main_test_rfh(), origin))
       .WillOnce(testing::Return(true));
   blink::mojom::AuthenticatorStatus result =
       main_test_rfh()->PerformMakeCredentialWebAuthSecurityChecks(
diff --git a/content/browser/renderer_host/render_widget_host_browsertest.cc b/content/browser/renderer_host/render_widget_host_browsertest.cc
index 12b3955..cafc7df 100644
--- a/content/browser/renderer_host/render_widget_host_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_browsertest.cc
@@ -10,6 +10,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/run_loop.h"
 #include "base/test/bind.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/test_timeouts.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
@@ -36,6 +37,7 @@
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/common/input/synthetic_web_input_event_builders.h"
 #include "third_party/blink/public/common/input/web_input_event.h"
 #include "third_party/blink/public/common/input/web_mouse_event.h"
@@ -646,57 +648,68 @@
 }
 #endif
 
-// Tests that the renderer receives the display::ScreenInfo size overrides
-// while the page is in fullscreen mode. This is a regression test for
-// https://crbug.com/1060795.
-IN_PROC_BROWSER_TEST_F(RenderWidgetHostBrowserTest,
-                       PropagatesFullscreenSizeOverrides) {
-  class FullscreenWaiter : public WebContentsObserver {
-   public:
-    explicit FullscreenWaiter(WebContents* wc) : WebContentsObserver(wc) {}
+class RenderWidgetHostFullscreenScreenSizeBrowserTest
+    : public RenderWidgetHostBrowserTest,
+      public testing::WithParamInterface<bool> {
+ public:
+  RenderWidgetHostFullscreenScreenSizeBrowserTest() {
+    scoped_feature_list_.InitWithFeatureState(
+        blink::features::kFullscreenScreenSizeMatchesDisplay,
+        FullscreenScreenSizeMatchesDisplayEnabled());
+  }
+  bool FullscreenScreenSizeMatchesDisplayEnabled() { return GetParam(); }
 
-    void Wait(bool enter) {
-      if (web_contents()->IsFullscreen() != enter) {
-        run_loop_.Run();
-      }
-      EXPECT_EQ(enter, web_contents()->IsFullscreen());
-    }
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
 
-   private:
-    void DidToggleFullscreenModeForTab(bool entered,
-                                       bool will_resize) override {
-      run_loop_.Quit();
-    }
+INSTANTIATE_TEST_SUITE_P(All,
+                         RenderWidgetHostFullscreenScreenSizeBrowserTest,
+                         testing::Bool());
 
-    base::RunLoop run_loop_;
-  };
-
-  // Sanity-check: Ensure the Shell and WebContents both agree the browser is
-  // not currently in fullscreen.
+// Tests `window.screen` dimensions in fullscreen. Note that Content Shell does
+// not resize the viewport to fill the screen in fullscreen on some platforms.
+// `window.screen` may provide viewport dimensions while the frame is fullscreen
+// as a speculative site compatibility measure, because web authors may assume
+// that screen dimensions match window.innerWidth/innerHeight while a page is
+// fullscreen, but that is not always true. crbug.com/1367416
+IN_PROC_BROWSER_TEST_P(RenderWidgetHostFullscreenScreenSizeBrowserTest,
+                       FullscreenSize) {
+  // Check initial dimensions before entering fullscreen.
   ASSERT_FALSE(shell()->IsFullscreenForTabOrPending(web_contents()));
   ASSERT_FALSE(web_contents()->IsFullscreen());
-
-  // While not fullscreened, expect the screen size to not be overridden.
-  display::ScreenInfo screen_info = host()->GetScreenInfo();
   WaitForVisualPropertiesAck();
-  EXPECT_EQ(screen_info.rect.size().ToString(),
+  EXPECT_EQ(host()->GetScreenInfo().rect.size().ToString(),
             EvalJs(web_contents(), "`${screen.width}x${screen.height}`"));
 
-  // Enter fullscreen mode. The Content Shell does not resize the view to fill
-  // the entire screen, and so the page will see the view's size as the screen
-  // size. This confirms the ScreenInfo override logic is working.
-  ASSERT_TRUE(ExecJs(web_contents(), "document.body.requestFullscreen();"));
-  FullscreenWaiter(web_contents()).Wait(true);
-  WaitForVisualPropertiesAck();
-  EXPECT_EQ(view()->GetRequestedRendererSize().ToString(),
-            EvalJs(web_contents(), "`${screen.width}x${screen.height}`"));
+  // Enter fullscreen; Content Shell does not resize the viewport to fill the
+  // screen in fullscreen on some platforms.
+  constexpr char kEnterFullscreenScript[] = R"JS(
+    document.documentElement.requestFullscreen().then(() => {
+        return !!document.fullscreenElement;
+    });
+  )JS";
+  ASSERT_TRUE(EvalJs(web_contents(), kEnterFullscreenScript).ExtractBool());
 
-  // Exit fullscreen mode, and then the page should see the screen size again.
-  ASSERT_TRUE(ExecJs(web_contents(), "document.exitFullscreen();"));
-  FullscreenWaiter(web_contents()).Wait(false);
-  screen_info = host()->GetScreenInfo();
-  WaitForVisualPropertiesAck();
-  EXPECT_EQ(screen_info.rect.size().ToString(),
+  if (FullscreenScreenSizeMatchesDisplayEnabled()) {
+    // `window.screen` dimensions match the display size.
+    EXPECT_EQ(host()->GetScreenInfo().rect.size().ToString(),
+              EvalJs(web_contents(), "`${screen.width}x${screen.height}`"));
+  } else {
+    // `window.screen` dimensions match the potentially smaller viewport size.
+    EXPECT_EQ(view()->GetRequestedRendererSize().ToString(),
+              EvalJs(web_contents(), "`${screen.width}x${screen.height}`"));
+  }
+
+  // Check dimensions again after exiting fullscreen.
+  constexpr char kExitFullscreenScript[] = R"JS(
+    document.exitFullscreen().then(() => {
+        return !document.fullscreenElement;
+    });
+  )JS";
+  ASSERT_TRUE(EvalJs(web_contents(), kExitFullscreenScript).ExtractBool());
+  ASSERT_FALSE(web_contents()->IsFullscreen());
+  EXPECT_EQ(host()->GetScreenInfo().rect.size().ToString(),
             EvalJs(web_contents(), "`${screen.width}x${screen.height}`"));
 }
 
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index eabc4cf..5a5a4f6 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -1000,8 +1000,6 @@
   const bool is_frame_widget = !self_owned_;
 
   blink::VisualProperties visual_properties;
-
-  // Note: Later in this method, ScreenInfo rects might be overridden!
   visual_properties.screen_infos = GetScreenInfos();
   auto& current_screen_info = visual_properties.screen_infos.mutable_current();
 
@@ -1051,14 +1049,15 @@
 
   visual_properties.new_size = view_->GetRequestedRendererSize();
 
-  // While in fullscreen mode, set the ScreenInfo rects to match the view size.
-  // This is needed because web authors often assume screen.width/height are
-  // identical to window.innerWidth/innerHeight while a page is in fullscreen,
-  // and this is not always true for some browser UI features.
-  // https://crbug.com/1060795
-  if (visual_properties.is_fullscreen_granted) {
-    current_screen_info.rect.set_size(visual_properties.new_size);
-    current_screen_info.available_rect.set_size(visual_properties.new_size);
+  // While in fullscreen, provide the view size as a ScreenInfo size override.
+  // This lets `window.screen` provide viewport dimensions while the frame is
+  // fullscreen as a speculative site compatibility measure, because web authors
+  // may assume that screen dimensions match window.innerWidth/innerHeight while
+  // a page is fullscreen, but that is not always true. crbug.com/1367416
+  if (visual_properties.is_fullscreen_granted &&
+      !base::FeatureList::IsEnabled(
+          blink::features::kFullscreenScreenSizeMatchesDisplay)) {
+    current_screen_info.size_override = visual_properties.new_size;
   }
 
   // This widget is for a frame that is the main frame of the outermost frame
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc
index 1e1fe1e..9b379c2 100644
--- a/content/browser/renderer_host/render_widget_host_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -1070,10 +1070,8 @@
 // after a ScreenInfo change.
 TEST_F(RenderWidgetHostTest, ResizeScreenInfo) {
   display::ScreenInfo screen_info;
-  screen_info.device_scale_factor = 1.f;
   screen_info.rect = gfx::Rect(0, 0, 800, 600);
   screen_info.available_rect = gfx::Rect(0, 0, 800, 600);
-  screen_info.orientation_angle = 0;
   screen_info.orientation_type =
       display::mojom::ScreenOrientation::kPortraitPrimary;
 
@@ -1122,17 +1120,38 @@
   EXPECT_FALSE(host_->visual_properties_ack_pending_);
 }
 
-// Tests that a resize event is sent when entering fullscreen mode, and the
-// screen_info rects are overridden to match the view bounds.
-TEST_F(RenderWidgetHostTest, OverrideScreenInfoDuringFullscreenMode) {
+class RenderWidgetHostFullscreenScreenSizeTest
+    : public RenderWidgetHostTest,
+      public testing::WithParamInterface<bool> {
+ public:
+  RenderWidgetHostFullscreenScreenSizeTest() {
+    scoped_feature_list_.InitWithFeatureState(
+        blink::features::kFullscreenScreenSizeMatchesDisplay,
+        FullscreenScreenSizeMatchesDisplayEnabled());
+  }
+  bool FullscreenScreenSizeMatchesDisplayEnabled() { return GetParam(); }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+INSTANTIATE_TEST_SUITE_P(All,
+                         RenderWidgetHostFullscreenScreenSizeTest,
+                         testing::Bool());
+
+// Test that VisualProperties conveys a ScreenInfo size override with the view's
+// size for the current screen, when the frame is fullscreen.
+// This lets `window.screen` provide viewport dimensions while the frame is
+// fullscreen as a speculative site compatibility measure, because web authors
+// may assume that screen dimensions match window.innerWidth/innerHeight while
+// a page is fullscreen, but that is not always true. crbug.com/1367416
+TEST_P(RenderWidgetHostFullscreenScreenSizeTest, ScreenSizeInFullscreen) {
   const gfx::Rect kScreenBounds(0, 0, 800, 600);
   const gfx::Rect kViewBounds(55, 66, 600, 500);
 
   display::ScreenInfo screen_info;
-  screen_info.device_scale_factor = 1.f;
   screen_info.rect = kScreenBounds;
   screen_info.available_rect = kScreenBounds;
-  screen_info.orientation_angle = 0;
   screen_info.orientation_type =
       display::mojom::ScreenOrientation::kPortraitPrimary;
   view_->SetScreenInfo(screen_info);
@@ -1147,8 +1166,10 @@
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1u, widget_.ReceivedVisualProperties().size());
   blink::VisualProperties props = widget_.ReceivedVisualProperties().at(0);
+  EXPECT_EQ(absl::nullopt, props.screen_infos.current().size_override);
   EXPECT_EQ(kScreenBounds, props.screen_infos.current().rect);
   EXPECT_EQ(kScreenBounds, props.screen_infos.current().available_rect);
+  EXPECT_EQ(kViewBounds.size(), props.new_size);
 
   // Enter fullscreen and do another VisualProperties sync.
   delegate_->set_is_fullscreen(true);
@@ -1157,9 +1178,13 @@
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(2u, widget_.ReceivedVisualProperties().size());
   props = widget_.ReceivedVisualProperties().at(1);
-  EXPECT_EQ(kViewBounds.size(), props.screen_infos.current().rect.size());
-  EXPECT_EQ(kViewBounds.size(),
-            props.screen_infos.current().available_rect.size());
+  if (FullscreenScreenSizeMatchesDisplayEnabled())
+    EXPECT_EQ(absl::nullopt, props.screen_infos.current().size_override);
+  else
+    EXPECT_EQ(kViewBounds.size(), props.screen_infos.current().size_override);
+  EXPECT_EQ(kScreenBounds, props.screen_infos.current().rect);
+  EXPECT_EQ(kScreenBounds, props.screen_infos.current().available_rect);
+  EXPECT_EQ(kViewBounds.size(), props.new_size);
 
   // Exit fullscreen and do another VisualProperties sync.
   delegate_->set_is_fullscreen(false);
@@ -1168,17 +1193,17 @@
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(3u, widget_.ReceivedVisualProperties().size());
   props = widget_.ReceivedVisualProperties().at(2);
+  EXPECT_EQ(absl::nullopt, props.screen_infos.current().size_override);
   EXPECT_EQ(kScreenBounds, props.screen_infos.current().rect);
   EXPECT_EQ(kScreenBounds, props.screen_infos.current().available_rect);
+  EXPECT_EQ(kViewBounds.size(), props.new_size);
 }
 
 TEST_F(RenderWidgetHostTest, RootWindowSegments) {
   gfx::Rect screen_rect(0, 0, 800, 600);
   display::ScreenInfo screen_info;
-  screen_info.device_scale_factor = 1.f;
   screen_info.rect = screen_rect;
   screen_info.available_rect = screen_rect;
-  screen_info.orientation_angle = 0;
   screen_info.orientation_type =
       display::mojom::ScreenOrientation::kPortraitPrimary;
   view_->SetScreenInfo(screen_info);
diff --git a/content/browser/resources/gpu/info_view.html b/content/browser/resources/gpu/info_view.html
index d2fa3e6..000911d 100644
--- a/content/browser/resources/gpu/info_view.html
+++ b/content/browser/resources/gpu/info_view.html
@@ -83,6 +83,10 @@
     box-shadow: none;
     text-shadow: none;
   }
+
+  #copy-to-clipboard:enabled:focus {
+    border-color: rgb(77, 144, 254);
+  }
 </style>
 
 <div>
diff --git a/content/browser/web_package/web_bundle_browsertest_base.h b/content/browser/web_package/web_bundle_browsertest_base.h
index 41c2de8..cfdae5c3 100644
--- a/content/browser/web_package/web_bundle_browsertest_base.h
+++ b/content/browser/web_package/web_bundle_browsertest_base.h
@@ -14,12 +14,12 @@
 #include "components/web_package/test_support/mock_web_bundle_parser_factory.h"
 #include "components/web_package/web_bundle_builder.h"
 #include "content/browser/renderer_host/frame_tree_node.h"
+#include "content/browser/renderer_host/navigation_type.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/download_manager.h"
 #include "content/public/browser/navigation_handle.h"
-#include "content/public/browser/navigation_type.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
diff --git a/content/browser/webauth/authenticator_common_impl.cc b/content/browser/webauth/authenticator_common_impl.cc
index 099c24a..dbef052 100644
--- a/content/browser/webauth/authenticator_common_impl.cc
+++ b/content/browser/webauth/authenticator_common_impl.cc
@@ -524,7 +524,7 @@
   make_credential_response_callback_ = std::move(callback);
 
   if (!GetWebAuthenticationDelegate()->IsSecurityLevelAcceptableForWebAuthn(
-          GetRenderFrameHost())) {
+          GetRenderFrameHost(), caller_origin)) {
     CompleteMakeCredentialRequest(
         blink::mojom::AuthenticatorStatus::CERTIFICATE_ERROR);
     return;
@@ -842,7 +842,7 @@
   get_assertion_response_callback_ = std::move(callback);
 
   if (!GetWebAuthenticationDelegate()->IsSecurityLevelAcceptableForWebAuthn(
-          GetRenderFrameHost())) {
+          GetRenderFrameHost(), caller_origin)) {
     CompleteGetAssertionRequest(
         blink::mojom::AuthenticatorStatus::CERTIFICATE_ERROR);
     return;
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc
index baf910fd..a565a1e 100644
--- a/content/browser/webauth/authenticator_impl_unittest.cc
+++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -1696,7 +1696,8 @@
   }
 
   bool IsSecurityLevelAcceptableForWebAuthn(
-      content::RenderFrameHost* rfh) override {
+      content::RenderFrameHost* rfh,
+      const url::Origin& origin) override {
     return is_webauthn_security_level_acceptable;
   }
 
diff --git a/content/browser/webid/webid_utils.cc b/content/browser/webid/webid_utils.cc
index 73502767..e302f9a5 100644
--- a/content/browser/webid/webid_utils.cc
+++ b/content/browser/webid/webid_utils.cc
@@ -28,6 +28,10 @@
                         const url::Origin& origin,
                         blink::mojom::IdpSigninStatus status) {
   auto* delegate = context->GetFederatedIdentitySharingPermissionContext();
+  if (!delegate) {
+    // The embedder may not have a delegate (e.g. webview)
+    return;
+  }
   delegate->SetIdpSigninStatus(
       origin, status == blink::mojom::IdpSigninStatus::kSignedIn);
 }
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn
index d395973a..b7864d0 100644
--- a/content/public/browser/BUILD.gn
+++ b/content/public/browser/BUILD.gn
@@ -258,7 +258,6 @@
     "navigation_handle_user_data.h",
     "navigation_throttle.cc",
     "navigation_throttle.h",
-    "navigation_type.h",
     "navigation_ui_data.h",
     "network_context_client_base.h",
     "network_quality_observer_factory.h",
diff --git a/content/public/browser/authenticator_request_client_delegate.cc b/content/public/browser/authenticator_request_client_delegate.cc
index a31c803d..fffa03ae 100644
--- a/content/public/browser/authenticator_request_client_delegate.cc
+++ b/content/public/browser/authenticator_request_client_delegate.cc
@@ -42,7 +42,8 @@
 }
 
 bool WebAuthenticationDelegate::IsSecurityLevelAcceptableForWebAuthn(
-    content::RenderFrameHost* rfh) {
+    content::RenderFrameHost* rfh,
+    const url::Origin& caller_origin) {
   return true;
 }
 
diff --git a/content/public/browser/authenticator_request_client_delegate.h b/content/public/browser/authenticator_request_client_delegate.h
index 4a19b0b5..2388d1f 100644
--- a/content/public/browser/authenticator_request_client_delegate.h
+++ b/content/public/browser/authenticator_request_client_delegate.h
@@ -81,7 +81,8 @@
   // Returns true if the tab security level is acceptable to allow WebAuthn
   // requests, false otherwise.
   virtual bool IsSecurityLevelAcceptableForWebAuthn(
-      content::RenderFrameHost* rfh);
+      content::RenderFrameHost* rfh,
+      const url::Origin& caller_origin);
 
 #if !BUILDFLAG(IS_ANDROID)
   // Permits the embedder to override the Relying Party ID for a WebAuthn call,
diff --git a/content/public/browser/navigation_details.h b/content/public/browser/navigation_details.h
index 5fd45e1..4e4a9d2 100644
--- a/content/public/browser/navigation_details.h
+++ b/content/public/browser/navigation_details.h
@@ -7,7 +7,6 @@
 
 #include "base/memory/raw_ptr.h"
 #include "content/common/content_export.h"
-#include "content/public/browser/navigation_type.h"
 #include "url/gurl.h"
 
 namespace content {
@@ -26,11 +25,6 @@
   // The committed entry. This will be the active entry in the controller.
   raw_ptr<NavigationEntry> entry = nullptr;
 
-  // The type of navigation that just occurred. Note that not all types of
-  // navigations in the enum are valid here, since some of them don't actually
-  // cause a "commit" and won't generate this notification.
-  content::NavigationType type = content::NAVIGATION_TYPE_UNKNOWN;
-
   // The index of the previously committed navigation entry. This will be -1
   // if there are no previous entries.
   int previous_entry_index = -1;
diff --git a/content/test/content_browser_test_utils_internal.h b/content/test/content_browser_test_utils_internal.h
index 9a21c5ed..4df2233 100644
--- a/content/test/content_browser_test_utils_internal.h
+++ b/content/test/content_browser_test_utils_internal.h
@@ -20,9 +20,9 @@
 #include "build/build_config.h"
 #include "content/browser/bad_message.h"
 #include "content/browser/renderer_host/back_forward_cache_metrics.h"
+#include "content/browser/renderer_host/navigation_type.h"
 #include "content/public/browser/devtools_agent_host.h"
 #include "content/public/browser/javascript_dialog_manager.h"
-#include "content/public/browser/navigation_type.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/test/browser_test_utils.h"
diff --git a/docs/accessibility/os/chromevox.md b/docs/accessibility/os/chromevox.md
index 1e9574c..546cb0f 100644
--- a/docs/accessibility/os/chromevox.md
+++ b/docs/accessibility/os/chromevox.md
@@ -112,4 +112,55 @@
 example, most of the ChromeVox Next tests have "E2E" in them (for "end-to-end"),
 so to only run those:
 
-```out/Release/browser_tests --test-launcher-jobs=20 --gtest_filter="*E2E*"```
+```out/Release/browser_tests --test-launcher-jobs=20 --gtest_filter="*ChromeVox*E2E*"```
+
+## Code Structure
+
+The `chromevox/` extension directory is broken into subdirectories, based on what context
+the code runs in. The different contexts are as follows:
+
+* The background context (`chromevox/background/`) contains the bulk of the ChromeVox logic,
+and runs in the background page (soon to be a background service worker).
+
+* The content script context (`chromevox/injected/`) contains the code that is injected into
+web pages. At this point, this is only used to support the Google Docs workaround. When that
+is resolved, it is anticipated this directory will be removed.
+
+* The learn mode context (`chromevox/learn_mode/`) contains the code to render and run the
+ChromeVox learn mode (which is different from the tutorial).
+
+* The log context (`chromevox/log_page/`) contains the code specific to showing the ChromeVox
+log page.
+
+* The options context (`chromevox/options/`) contains the code for the ChromeVox settings page.
+There is an ongoing effort to migrate this page into the ChromeOS settings app, after which
+this directory will be unneeded.
+
+* The panel context (`chromevox/panel/`) contains the code that renders and performs the logic
+of the ChromeVox panel, shown at the top of the screen. When the onscreen command menus are
+shown, that is also rendered in this context.
+
+* The tutorial context (`chromevox/tutorial/`) contains resources used exclusively by the
+ChromeVox tutorial.
+
+Other subdirectories also have specific purposes:
+
+* The common directory (`chromevox/common/`) contains files that can safely be shared between
+multiple contexts. These files must have no global state, as each context has its own global
+namespace. To get information between the contexts, bridge objects are used to pass structured
+messages. Any data passed through these bridges loses any and all class information, as it is
+converted to JSON in the process of being sent.
+
+* The earcons directory (`chromevox/earcons/`) contains the audio files for any short indicator
+sounds (earcons) used by ChromeVox to express information without words.
+
+* The images directory (`chromevox/images/`) contains any images used in any context.
+
+* The testing directory (`chromevox/testing/`) contains files that are used exclusively in
+testing.
+
+* The third_party directory (`chromevox/third_party`) contains open source code from other
+developers that is used in the ChromeVox extension.
+
+* The tools directory (`chromevox/tools`) contains python scrips used for building ChromeVox.
+Eventually these should be moved into the common accessibility directory.
\ No newline at end of file
diff --git a/extensions/browser/api/declarative_net_request/extension_url_pattern_index_matcher.cc b/extensions/browser/api/declarative_net_request/extension_url_pattern_index_matcher.cc
index d19311b4..62af52d8 100644
--- a/extensions/browser/api/declarative_net_request/extension_url_pattern_index_matcher.cc
+++ b/extensions/browser/api/declarative_net_request/extension_url_pattern_index_matcher.cc
@@ -162,7 +162,8 @@
   return matchers_[index].FindMatch(
       *params.url, params.first_party_origin, params.element_type,
       flat_rule::ActivationType_NONE, params.method, params.is_third_party,
-      kDisableGenericRules, params.embedder_conditions_matcher, strategy);
+      kDisableGenericRules, params.embedder_conditions_matcher, strategy,
+      disabled_rule_ids_);
 }
 
 std::vector<const url_pattern_index::flat::UrlRule*>
@@ -180,7 +181,19 @@
   return matchers_[index].FindAllMatches(
       *params.url, params.first_party_origin, params.element_type,
       flat_rule::ActivationType_NONE, params.method, params.is_third_party,
-      kDisableGenericRules, params.embedder_conditions_matcher);
+      kDisableGenericRules, params.embedder_conditions_matcher,
+      disabled_rule_ids_);
+}
+
+void ExtensionUrlPatternIndexMatcher::SetDisabledRuleIds(
+    base::flat_set<int> disabled_rule_ids) {
+  disabled_rule_ids_ = std::move(disabled_rule_ids);
+  disabled_rule_ids_.shrink_to_fit();
+}
+
+const base::flat_set<int>&
+ExtensionUrlPatternIndexMatcher::GetDisabledRuleIdsForTesting() const {
+  return disabled_rule_ids_;
 }
 
 }  // namespace declarative_net_request
diff --git a/extensions/browser/api/declarative_net_request/extension_url_pattern_index_matcher.h b/extensions/browser/api/declarative_net_request/extension_url_pattern_index_matcher.h
index 403c96b..008d70d 100644
--- a/extensions/browser/api/declarative_net_request/extension_url_pattern_index_matcher.h
+++ b/extensions/browser/api/declarative_net_request/extension_url_pattern_index_matcher.h
@@ -7,6 +7,7 @@
 
 #include <vector>
 
+#include "base/containers/flat_set.h"
 #include "base/memory/raw_ptr.h"
 #include "components/url_pattern_index/url_pattern_index.h"
 #include "extensions/browser/api/declarative_net_request/ruleset_matcher_base.h"
@@ -40,6 +41,11 @@
   bool IsExtraHeadersMatcher() const override;
   size_t GetRulesCount() const override;
 
+  // Sets the disabled rule ids so that the disabled rules are not matched.
+  void SetDisabledRuleIds(base::flat_set<int> disabled_rule_ids);
+
+  const base::flat_set<int>& GetDisabledRuleIdsForTesting() const;
+
  private:
   using UrlPatternIndexMatcher = url_pattern_index::UrlPatternIndexMatcher;
 
@@ -72,6 +78,10 @@
   const bool is_extra_headers_matcher_;
 
   const size_t rules_count_;
+
+  // Disabled rule ids. The ids are passed to the matching algorithm in the
+  // UrlPatternIndexMatcher so that the algorithm can skip the disabled rules.
+  base::flat_set<int> disabled_rule_ids_;
 };
 
 }  // namespace declarative_net_request
diff --git a/extensions/browser/api/declarative_net_request/ruleset_matcher.cc b/extensions/browser/api/declarative_net_request/ruleset_matcher.cc
index 1ca1950..1b85d21 100644
--- a/extensions/browser/api/declarative_net_request/ruleset_matcher.cc
+++ b/extensions/browser/api/declarative_net_request/ruleset_matcher.cc
@@ -101,5 +101,14 @@
       regex_matcher_.GetAllowlistedFrameActionForTesting(host));
 }
 
+void RulesetMatcher::SetDisabledRuleIds(base::flat_set<int> disabled_rule_ids) {
+  url_pattern_index_matcher_.SetDisabledRuleIds(std::move(disabled_rule_ids));
+}
+
+const base::flat_set<int>& RulesetMatcher::GetDisabledRuleIdsForTesting()
+    const {
+  return url_pattern_index_matcher_.GetDisabledRuleIdsForTesting();
+}
+
 }  // namespace declarative_net_request
 }  // namespace extensions
diff --git a/extensions/browser/api/declarative_net_request/ruleset_matcher.h b/extensions/browser/api/declarative_net_request/ruleset_matcher.h
index 2b163838..5d489054 100644
--- a/extensions/browser/api/declarative_net_request/ruleset_matcher.h
+++ b/extensions/browser/api/declarative_net_request/ruleset_matcher.h
@@ -9,6 +9,7 @@
 #include <memory>
 #include <string>
 
+#include "base/containers/flat_set.h"
 #include "base/memory/raw_ptr.h"
 #include "extensions/browser/api/declarative_net_request/extension_url_pattern_index_matcher.h"
 #include "extensions/browser/api/declarative_net_request/flat/extension_ruleset_generated.h"
@@ -75,6 +76,12 @@
   absl::optional<RequestAction> GetAllowlistedFrameActionForTesting(
       content::RenderFrameHost* host) const;
 
+  // Set the disabled rule ids to the ruleset matcher.
+  void SetDisabledRuleIds(base::flat_set<int> disabled_rule_ids);
+
+  // Returns the disabled rule ids for testing.
+  const base::flat_set<int>& GetDisabledRuleIdsForTesting() const;
+
  private:
   const std::string ruleset_data_;
 
diff --git a/extensions/browser/api/declarative_net_request/ruleset_matcher_unittest.cc b/extensions/browser/api/declarative_net_request/ruleset_matcher_unittest.cc
index 18bd0ef8..17c7c0a 100644
--- a/extensions/browser/api/declarative_net_request/ruleset_matcher_unittest.cc
+++ b/extensions/browser/api/declarative_net_request/ruleset_matcher_unittest.cc
@@ -1391,6 +1391,59 @@
   }
 }
 
+// Tests disable rules with simple blocking rules.
+TEST_F(RulesetMatcherTest, SetDisabledRuleIds) {
+  TestRule rule_1 = CreateGenericRule(kMinValidID);
+  rule_1.condition->url_filter = std::string("google.com");
+  GURL google_url("http://google.com");
+
+  TestRule rule_2 = CreateGenericRule(kMinValidID + 1);
+  rule_2.condition->url_filter = std::string("yahoo.com");
+  GURL yahoo_url("http://yahoo.com");
+
+  GURL example_url("http://example.com");
+
+  auto should_block_request = [](const RulesetMatcher& matcher,
+                                 const RequestParams& params) {
+    auto action = matcher.GetBeforeRequestAction(params);
+    return action.has_value() && action->IsBlockOrCollapse();
+  };
+
+  RequestParams params;
+  params.element_type = url_pattern_index::flat::ElementType_SUBDOCUMENT;
+  params.is_third_party = true;
+
+  std::unique_ptr<RulesetMatcher> matcher;
+  ASSERT_TRUE(CreateVerifiedMatcher({rule_1, rule_2}, CreateTemporarySource(),
+                                    &matcher));
+  ASSERT_TRUE(matcher);
+
+  params.url = &google_url;
+  EXPECT_TRUE(should_block_request(*matcher, params));
+
+  params.url = &yahoo_url;
+  EXPECT_TRUE(should_block_request(*matcher, params));
+
+  params.url = &example_url;
+  EXPECT_FALSE(should_block_request(*matcher, params));
+
+  EXPECT_THAT(matcher->GetDisabledRuleIdsForTesting(), testing::IsEmpty());
+
+  matcher->SetDisabledRuleIds({*rule_1.id});
+
+  EXPECT_THAT(matcher->GetDisabledRuleIdsForTesting(),
+              testing::ElementsAreArray({*rule_1.id}));
+
+  params.url = &google_url;
+  EXPECT_FALSE(should_block_request(*matcher, params));
+
+  params.url = &yahoo_url;
+  EXPECT_TRUE(should_block_request(*matcher, params));
+
+  params.url = &example_url;
+  EXPECT_FALSE(should_block_request(*matcher, params));
+}
+
 }  // namespace
 }  // namespace declarative_net_request
 }  // namespace extensions
diff --git a/gpu/command_buffer/service/shared_image/shared_image_format_utils.cc b/gpu/command_buffer/service/shared_image/shared_image_format_utils.cc
index e32e17b..7fa4970 100644
--- a/gpu/command_buffer/service/shared_image/shared_image_format_utils.cc
+++ b/gpu/command_buffer/service/shared_image/shared_image_format_utils.cc
@@ -8,6 +8,7 @@
 #include <GLES2/gl2ext.h>
 
 #include "base/check.h"
+#include "base/check_op.h"
 #include "base/logging.h"
 #include "base/notreached.h"
 #include "components/viz/common/resources/resource_format.h"
@@ -76,14 +77,9 @@
   // For multiplanar formats without external sampler, GL formats are per plane.
   // For single channel planes Y, U, V, A return GL_RED_EXT.
   // For 2 channel plane UV return GL_RG_EXT.
-  switch (format.plane_config()) {
-    case viz::SharedImageFormat::PlaneConfig::kY_V_U:
-      return GL_RED_EXT;
-    case viz::SharedImageFormat::PlaneConfig::kY_UV:
-      return plane_index == 1 ? GL_RG_EXT : GL_RED_EXT;
-    case viz::SharedImageFormat::PlaneConfig::kY_UV_A:
-      return plane_index == 1 ? GL_RG_EXT : GL_RED_EXT;
-  }
+  int num_channels = format.NumChannelsInPlane(plane_index);
+  DCHECK_GT(num_channels, 0);
+  return num_channels == 2 ? GL_RG_EXT : GL_RED_EXT;
 }
 GLenum GLInternalFormat(viz::SharedImageFormat format, int plane_index) {
   DCHECK(format.IsValidPlaneIndex(plane_index));
@@ -94,29 +90,17 @@
   // For single channel 10-bit planes Y return GL_R16_EXT.
   // For 2 channel plane 8-bit UV return GL_RG_EXT.
   // For 2 channel plane 16-bit UV return GL_RG16_EXT.
-  // TODO(hitawala): Add support for YVU/YUVA for 16 bit channels.
+  int num_channels = format.NumChannelsInPlane(plane_index);
+  DCHECK_GT(num_channels, 0);
   switch (format.channel_format()) {
     case viz::SharedImageFormat::ChannelFormat::k8:
-      switch (format.plane_config()) {
-        case viz::SharedImageFormat::PlaneConfig::kY_V_U:
-          return GL_RED_EXT;
-        case viz::SharedImageFormat::PlaneConfig::kY_UV:
-          return plane_index == 1 ? GL_RG_EXT : GL_RED_EXT;
-        case viz::SharedImageFormat::PlaneConfig::kY_UV_A:
-          return plane_index == 1 ? GL_RG_EXT : GL_RED_EXT;
-      }
+      return num_channels == 2 ? GL_RG_EXT : GL_RED_EXT;
     case viz::SharedImageFormat::ChannelFormat::k10:
-      DCHECK(format.plane_config() ==
-             viz::SharedImageFormat::PlaneConfig::kY_UV);
-      return plane_index == 1 ? GL_RG16_EXT : GL_R16_EXT;
+      return num_channels == 2 ? GL_RG16_EXT : GL_R16_EXT;
     case viz::SharedImageFormat::ChannelFormat::k16:
-      DCHECK(format.plane_config() ==
-             viz::SharedImageFormat::PlaneConfig::kY_UV);
-      return plane_index == 1 ? GL_RG16_EXT : GL_R16_EXT;
+      return num_channels == 2 ? GL_RG16_EXT : GL_R16_EXT;
     case viz::SharedImageFormat::ChannelFormat::k16F:
-      DCHECK(format.plane_config() ==
-             viz::SharedImageFormat::PlaneConfig::kY_UV);
-      return plane_index == 1 ? GL_RG16F_EXT : GL_R16F_EXT;
+      return num_channels == 2 ? GL_RG16F_EXT : GL_R16F_EXT;
   }
 }
 GLenum TextureStorageFormat(viz::SharedImageFormat format,
@@ -131,29 +115,17 @@
   // For single channel 10-bit planes Y return GL_R16_EXT.
   // For 2 channel plane 8-bit UV return GL_RG8_EXT.
   // For 2 channel plane 16-bit UV return GL_RG16_EXT.
-  // TODO(hitawala): Add support for YVU/YUVA for 16 bit channels.
+  int num_channels = format.NumChannelsInPlane(plane_index);
+  DCHECK_GT(num_channels, 0);
   switch (format.channel_format()) {
     case viz::SharedImageFormat::ChannelFormat::k8:
-      switch (format.plane_config()) {
-        case viz::SharedImageFormat::PlaneConfig::kY_V_U:
-          return GL_R8_EXT;
-        case viz::SharedImageFormat::PlaneConfig::kY_UV:
-          return plane_index == 1 ? GL_RG8_EXT : GL_R8_EXT;
-        case viz::SharedImageFormat::PlaneConfig::kY_UV_A:
-          return plane_index == 1 ? GL_RG8_EXT : GL_R8_EXT;
-      }
+      return num_channels == 2 ? GL_RG8_EXT : GL_R8_EXT;
     case viz::SharedImageFormat::ChannelFormat::k10:
-      DCHECK(format.plane_config() ==
-             viz::SharedImageFormat::PlaneConfig::kY_UV);
-      return plane_index == 1 ? GL_RG16_EXT : GL_R16_EXT;
+      return num_channels == 2 ? GL_RG16_EXT : GL_R16_EXT;
     case viz::SharedImageFormat::ChannelFormat::k16:
-      DCHECK(format.plane_config() ==
-             viz::SharedImageFormat::PlaneConfig::kY_UV);
-      return plane_index == 1 ? GL_RG16_EXT : GL_R16_EXT;
+      return num_channels == 2 ? GL_RG16_EXT : GL_R16_EXT;
     case viz::SharedImageFormat::ChannelFormat::k16F:
-      DCHECK(format.plane_config() ==
-             viz::SharedImageFormat::PlaneConfig::kY_UV);
-      return plane_index == 1 ? GL_RG16F_EXT : GL_R16F_EXT;
+      return num_channels == 2 ? GL_RG16F_EXT : GL_R16F_EXT;
   }
 }
 
diff --git a/infra/config/generated/builders/ci/Linux MSan Focal/properties.json b/infra/config/generated/builders/ci/Linux MSan Focal/properties.json
new file mode 100644
index 0000000..5fc9bed
--- /dev/null
+++ b/infra/config/generated/builders/ci/Linux MSan Focal/properties.json
@@ -0,0 +1,58 @@
+{
+  "$build/chromium_tests_builder_config": {
+    "builder_config": {
+      "builder_db": {
+        "entries": [
+          {
+            "builder_id": {
+              "bucket": "ci",
+              "builder": "Linux MSan Focal",
+              "project": "chromium"
+            },
+            "builder_spec": {
+              "builder_group": "chromium.fyi",
+              "execution_mode": "COMPILE_AND_TEST",
+              "legacy_chromium_config": {
+                "apply_configs": [
+                  "mb"
+                ],
+                "build_config": "Release",
+                "config": "chromium_msan"
+              },
+              "legacy_gclient_config": {
+                "config": "chromium"
+              }
+            }
+          }
+        ]
+      },
+      "builder_ids": [
+        {
+          "bucket": "ci",
+          "builder": "Linux MSan Focal",
+          "project": "chromium"
+        }
+      ],
+      "mirroring_builder_group_and_names": [
+        {
+          "builder": "linux_chromium_msan_focal",
+          "group": "tryserver.chromium.linux"
+        }
+      ]
+    }
+  },
+  "$build/reclient": {
+    "instance": "rbe-chromium-trusted",
+    "jobs": 500,
+    "metrics_project": "chromium-reclient-metrics"
+  },
+  "$recipe_engine/resultdb/test_presentation": {
+    "column_keys": [],
+    "grouping_keys": [
+      "status",
+      "v.test_suite"
+    ]
+  },
+  "builder_group": "chromium.fyi",
+  "recipe": "chromium"
+}
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/linux_chromium_msan_focal/properties.json b/infra/config/generated/builders/try/linux_chromium_msan_focal/properties.json
new file mode 100644
index 0000000..79e84aff
--- /dev/null
+++ b/infra/config/generated/builders/try/linux_chromium_msan_focal/properties.json
@@ -0,0 +1,52 @@
+{
+  "$build/chromium_tests_builder_config": {
+    "builder_config": {
+      "builder_db": {
+        "entries": [
+          {
+            "builder_id": {
+              "bucket": "ci",
+              "builder": "Linux MSan Focal",
+              "project": "chromium"
+            },
+            "builder_spec": {
+              "builder_group": "chromium.fyi",
+              "execution_mode": "COMPILE_AND_TEST",
+              "legacy_chromium_config": {
+                "apply_configs": [
+                  "mb"
+                ],
+                "build_config": "Release",
+                "config": "chromium_msan"
+              },
+              "legacy_gclient_config": {
+                "config": "chromium"
+              }
+            }
+          }
+        ]
+      },
+      "builder_ids": [
+        {
+          "bucket": "ci",
+          "builder": "Linux MSan Focal",
+          "project": "chromium"
+        }
+      ]
+    }
+  },
+  "$build/reclient": {
+    "instance": "rbe-chromium-untrusted",
+    "jobs": 300,
+    "metrics_project": "chromium-reclient-metrics"
+  },
+  "$recipe_engine/resultdb/test_presentation": {
+    "column_keys": [],
+    "grouping_keys": [
+      "status",
+      "v.test_suite"
+    ]
+  },
+  "builder_group": "tryserver.chromium.linux",
+  "recipe": "chromium_trybot"
+}
\ No newline at end of file
diff --git a/infra/config/generated/luci/commit-queue.cfg b/infra/config/generated/luci/commit-queue.cfg
index e123a0a..11737688 100644
--- a/infra/config/generated/luci/commit-queue.cfg
+++ b/infra/config/generated/luci/commit-queue.cfg
@@ -2970,6 +2970,10 @@
         }
       }
       builders {
+        name: "chromium/try/linux_chromium_msan_focal"
+        includable_only: true
+      }
+      builders {
         name: "chromium/try/linux_chromium_msan_rel_ng"
         includable_only: true
       }
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index 0281c56..7980a97 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -13839,7 +13839,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "free_space:standard"
-      dimensions: "os:Ubuntu-20.04"
+      dimensions: "os:Ubuntu-18.04"
       dimensions: "pool:luci.chromium.ci"
       dimensions: "ssd:1"
       exe {
@@ -13924,7 +13924,7 @@
       }
     }
     builders {
-      name: "Linux MSan Tests"
+      name: "Linux MSan Focal"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
       dimensions: "cores:8"
@@ -13950,6 +13950,95 @@
         '    }'
         '  },'
         '  "$bootstrap/properties": {'
+        '    "properties_file": "infra/config/generated/builders/ci/Linux MSan Focal/properties.json",'
+        '    "top_level_project": {'
+        '      "ref": "refs/heads/main",'
+        '      "repo": {'
+        '        "host": "chromium.googlesource.com",'
+        '        "project": "chromium/src"'
+        '      }'
+        '    }'
+        '  },'
+        '  "builder_group": "chromium.fyi",'
+        '  "led_builder_is_bootstrapped": true,'
+        '  "recipe": "chromium"'
+        '}'
+      priority: 35
+      execution_timeout_secs: 57600
+      build_numbers: YES
+      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+      experiments {
+        key: "chromium_swarming.expose_merge_script_failures"
+        value: 100
+      }
+      experiments {
+        key: "luci.buildbucket.omit_python2"
+        value: 100
+      }
+      experiments {
+        key: "luci.recipes.use_python3"
+        value: 100
+      }
+      resultdb {
+        enable: true
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "ci_test_results"
+          test_results {}
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "gpu_ci_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "ninja://chrome/test:telemetry_gpu_integration_test[^/]*/.+"
+            }
+          }
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "blink_web_tests_ci_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "(ninja://[^/]*blink_web_tests/.+)|(ninja://[^/]*blink_wpt_tests/.+)"
+            }
+          }
+        }
+        history_options {
+          use_invocation_timestamp: true
+        }
+      }
+    }
+    builders {
+      name: "Linux MSan Tests"
+      swarming_host: "chromium-swarm.appspot.com"
+      dimensions: "builderless:1"
+      dimensions: "cores:8"
+      dimensions: "cpu:x86-64"
+      dimensions: "free_space:standard"
+      dimensions: "os:Ubuntu-18.04"
+      dimensions: "pool:luci.chromium.ci"
+      dimensions: "ssd:0"
+      exe {
+        cipd_package: "infra/chromium/bootstrapper/${platform}"
+        cipd_version: "latest"
+        cmd: "bootstrapper"
+      }
+      properties:
+        '{'
+        '  "$bootstrap/exe": {'
+        '    "exe": {'
+        '      "cipd_package": "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build",'
+        '      "cipd_version": "refs/heads/main",'
+        '      "cmd": ['
+        '        "luciexe"'
+        '      ]'
+        '    }'
+        '  },'
+        '  "$bootstrap/properties": {'
         '    "properties_file": "infra/config/generated/builders/ci/Linux MSan Tests/properties.json",'
         '    "top_level_project": {'
         '      "ref": "refs/heads/main",'
@@ -54549,6 +54638,53 @@
   name: "reviver"
   swarming {
     builders {
+      name: "android-device-launcher"
+      swarming_host: "chromium-swarm.appspot.com"
+      dimensions: "builderless:1"
+      dimensions: "os:Ubuntu-18.04"
+      dimensions: "pool:luci.chromium.ci"
+      dimensions: "ssd:0"
+      exe {
+        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
+        cipd_version: "refs/heads/main"
+        cmd: "luciexe"
+      }
+      properties:
+        '{'
+        '  "$recipe_engine/resultdb/test_presentation": {'
+        '    "column_keys": [],'
+        '    "grouping_keys": ['
+        '      "status",'
+        '      "v.test_suite"'
+        '    ]'
+        '  },'
+        '  "recipe": "chromium_polymorphic/launcher",'
+        '  "runner_builder": {'
+        '    "bucket": "reviver",'
+        '    "builder": "runner",'
+        '    "project": "chromium"'
+        '  },'
+        '  "target_builders": ['
+        '    {'
+        '      "builder_id": {'
+        '        "bucket": "ci",'
+        '        "builder": "android-pie-arm64-rel",'
+        '        "project": "chromium"'
+        '      }'
+        '    }'
+        '  ]'
+        '}'
+      service_account: "reviver-builder@chops-service-accounts.iam.gserviceaccount.com"
+      experiments {
+        key: "luci.buildbucket.omit_python2"
+        value: 0
+      }
+      experiments {
+        key: "luci.recipes.use_python3"
+        value: 100
+      }
+    }
+    builders {
       name: "android-launcher"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
@@ -83370,7 +83506,7 @@
       }
     }
     builders {
-      name: "linux_chromium_msan_rel_ng"
+      name: "linux_chromium_msan_focal"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
       dimensions: "cores:8"
@@ -83395,6 +83531,116 @@
         '    }'
         '  },'
         '  "$bootstrap/properties": {'
+        '    "properties_file": "infra/config/generated/builders/try/linux_chromium_msan_focal/properties.json",'
+        '    "top_level_project": {'
+        '      "ref": "refs/heads/main",'
+        '      "repo": {'
+        '        "host": "chromium.googlesource.com",'
+        '        "project": "chromium/src"'
+        '      }'
+        '    }'
+        '  },'
+        '  "builder_group": "tryserver.chromium.linux",'
+        '  "led_builder_is_bootstrapped": true,'
+        '  "recipe": "chromium_trybot"'
+        '}'
+      execution_timeout_secs: 57600
+      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_swarming.expose_merge_script_failures"
+        value: 100
+      }
+      experiments {
+        key: "enable_weetbix_queries"
+        value: 100
+      }
+      experiments {
+        key: "luci.buildbucket.omit_python2"
+        value: 100
+      }
+      experiments {
+        key: "luci.recipes.use_python3"
+        value: 100
+      }
+      experiments {
+        key: "weetbix.enable_weetbix_exonerations"
+        value: 100
+      }
+      experiments {
+        key: "weetbix.retry_weak_exonerations"
+        value: 100
+      }
+      resultdb {
+        enable: true
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "try_test_results"
+          test_results {}
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "gpu_try_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "ninja://chrome/test:telemetry_gpu_integration_test[^/]*/.+"
+            }
+          }
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "blink_web_tests_try_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "(ninja://[^/]*blink_web_tests/.+)|(ninja://[^/]*blink_wpt_tests/.+)"
+            }
+          }
+        }
+        history_options {
+          use_invocation_timestamp: true
+        }
+      }
+    }
+    builders {
+      name: "linux_chromium_msan_rel_ng"
+      swarming_host: "chromium-swarm.appspot.com"
+      dimensions: "builderless:1"
+      dimensions: "cores:8"
+      dimensions: "cpu:x86-64"
+      dimensions: "os:Ubuntu-18.04"
+      dimensions: "pool:luci.chromium.try"
+      dimensions: "ssd:0"
+      exe {
+        cipd_package: "infra/chromium/bootstrapper/${platform}"
+        cipd_version: "latest"
+        cmd: "bootstrapper"
+      }
+      properties:
+        '{'
+        '  "$bootstrap/exe": {'
+        '    "exe": {'
+        '      "cipd_package": "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build",'
+        '      "cipd_version": "refs/heads/main",'
+        '      "cmd": ['
+        '        "luciexe"'
+        '      ]'
+        '    }'
+        '  },'
+        '  "$bootstrap/properties": {'
         '    "properties_file": "infra/config/generated/builders/try/linux_chromium_msan_rel_ng/properties.json",'
         '    "top_level_project": {'
         '      "ref": "refs/heads/main",'
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg
index 334dd62..43d6e4d0 100644
--- a/infra/config/generated/luci/luci-milo.cfg
+++ b/infra/config/generated/luci/luci-milo.cfg
@@ -8751,6 +8751,11 @@
     short_name: "crs"
   }
   builders {
+    name: "buildbucket/luci.chromium.ci/Linux MSan Focal"
+    category: "msan"
+    short_name: "lin"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/linux-upload-perfetto"
     category: "perfetto"
     short_name: "lnx"
@@ -16955,6 +16960,9 @@
     name: "buildbucket/luci.chromium.try/linux_chromium_dbg_ng"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/linux_chromium_msan_focal"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/linux_chromium_msan_rel_ng"
   }
   builders {
@@ -17243,6 +17251,9 @@
   id: "reviver"
   name: "reviver"
   builders {
+    name: "buildbucket/luci.chromium.reviver/android-device-launcher"
+  }
+  builders {
     name: "buildbucket/luci.chromium.reviver/android-launcher"
   }
   builders {
@@ -17971,6 +17982,9 @@
     name: "buildbucket/luci.chromium.try/linux_chromium_dbg_ng"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/linux_chromium_msan_focal"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/linux_chromium_msan_rel_ng"
   }
   builders {
diff --git a/infra/config/generated/luci/luci-scheduler.cfg b/infra/config/generated/luci/luci-scheduler.cfg
index 769dd14..c9d31cf 100644
--- a/infra/config/generated/luci/luci-scheduler.cfg
+++ b/infra/config/generated/luci/luci-scheduler.cfg
@@ -1739,6 +1739,15 @@
   }
 }
 job {
+  id: "Linux MSan Focal"
+  realm: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "ci"
+    builder: "Linux MSan Focal"
+  }
+}
+job {
   id: "Linux MSan Tests"
   realm: "ci"
   buildbucket {
@@ -3685,6 +3694,16 @@
   }
 }
 job {
+  id: "android-device-launcher"
+  realm: "reviver"
+  schedule: "0 5,8,11 * * *"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "reviver"
+    builder: "android-device-launcher"
+  }
+}
+job {
   id: "android-fieldtrial-rel"
   realm: "ci"
   buildbucket {
@@ -3696,7 +3715,7 @@
 job {
   id: "android-launcher"
   realm: "reviver"
-  schedule: "0 1,4,7,10,13 * * *"
+  schedule: "0 2,5,8,11,14 * * *"
   buildbucket {
     server: "cr-buildbucket.appspot.com"
     bucket: "reviver"
@@ -4070,7 +4089,7 @@
 job {
   id: "fuchsia-coordinator"
   realm: "reviver"
-  schedule: "0 1,3,5,7,9,11,13 * * *"
+  schedule: "0 2,4,6,8,10,12,14 * * *"
   buildbucket {
     server: "cr-buildbucket.appspot.com"
     bucket: "reviver"
@@ -5919,6 +5938,7 @@
   triggers: "Linux ChromiumOS MSan Focal"
   triggers: "Linux FYI GPU TSAN Release"
   triggers: "Linux MSan Builder"
+  triggers: "Linux MSan Focal"
   triggers: "Linux TSan Builder"
   triggers: "Linux Viz"
   triggers: "MSAN Release (chained origins)"
diff --git a/infra/config/subprojects/chromium/ci/chromium.fyi.star b/infra/config/subprojects/chromium/ci/chromium.fyi.star
index c519380..38a976ea 100644
--- a/infra/config/subprojects/chromium/ci/chromium.fyi.star
+++ b/infra/config/subprojects/chromium/ci/chromium.fyi.star
@@ -1927,6 +1927,32 @@
 
 ci.builder(
     # An FYI version of the following builders that runs on Focal:
+    # https://ci.chromium.org/p/chromium/builders/ci/Linux%20MSan%20Builder
+    # https://ci.chromium.org/p/chromium/builders/ci/Linux%20MSan%20Tests
+    # TODO(crbug.com/1260217): Remove this builder when the main MSAN builder
+    # has migrated to focal.
+    name = "Linux MSan Focal",
+    builder_spec = builder_config.builder_spec(
+        gclient_config = builder_config.gclient_config(
+            config = "chromium",
+        ),
+        chromium_config = builder_config.chromium_config(
+            config = "chromium_msan",
+            apply_configs = ["mb"],
+            build_config = builder_config.build_config.RELEASE,
+        ),
+    ),
+    console_view_entry = consoles.console_view_entry(
+        category = "msan",
+        short_name = "lin",
+    ),
+    reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CI,
+    os = os.LINUX_FOCAL,
+    execution_timeout = 16 * time.hour,
+)
+
+ci.builder(
+    # An FYI version of the following builders that runs on Focal:
     # https://ci.chromium.org/p/chromium/builders/ci/Linux%20ChromiumOS%20MSan%20Builder
     # https://ci.chromium.org/p/chromium/builders/ci/Linux%20ChromiumOS%20MSan%20Tests
     # TODO(crbug.com/1260217): Remove this builder when the main MSAN builder
diff --git a/infra/config/subprojects/chromium/ci/chromium.memory.star b/infra/config/subprojects/chromium/ci/chromium.memory.star
index 5b7ad835..950bfdba 100644
--- a/infra/config/subprojects/chromium/ci/chromium.memory.star
+++ b/infra/config/subprojects/chromium/ci/chromium.memory.star
@@ -321,7 +321,6 @@
         short_name = "bld",
     ),
     ssd = True,
-    os = os.LINUX_FOCAL,
 )
 
 linux_memory_builder(
@@ -349,7 +348,6 @@
     ),
     reclient_jobs = reclient.jobs.LOW_JOBS_FOR_CI,
     triggered_by = ["Linux MSan Builder"],
-    os = os.LINUX_FOCAL,
 )
 
 linux_memory_builder(
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star b/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
index f0762a5..16d0759 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
@@ -522,6 +522,17 @@
 )
 
 try_.builder(
+    name = "linux_chromium_msan_focal",
+    mirrors = [
+        "ci/Linux MSan Focal",
+    ],
+    execution_timeout = 16 * time.hour,
+    goma_backend = None,
+    os = os.LINUX_FOCAL,
+    reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CQ,
+)
+
+try_.builder(
     name = "linux_chromium_msan_rel_ng",
     mirrors = [
         "ci/Linux MSan Builder",
@@ -529,7 +540,6 @@
     ],
     execution_timeout = 6 * time.hour,
     goma_backend = None,
-    os = os.LINUX_FOCAL,
     reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CQ,
 )
 
diff --git a/infra/config/subprojects/reviver/reviver.star b/infra/config/subprojects/reviver/reviver.star
index 0b53afc..33a4d1e 100644
--- a/infra/config/subprojects/reviver/reviver.star
+++ b/infra/config/subprojects/reviver/reviver.star
@@ -53,8 +53,20 @@
     ],
     os = os.LINUX_DEFAULT,
     pool = ci.DEFAULT_POOL,
-    # To avoid peak hours, we run it at 1 AM, 4 AM, 7 AM, 10AM, 1 PM UTC.
-    schedule = "0 1,4,7,10,13 * * *",
+    # To avoid peak hours, we run it at 2 AM, 5 AM, 8 AM, 11AM, 2 PM UTC.
+    schedule = "0 2,5,8,11,14 * * *",
+)
+
+polymorphic.launcher(
+    name = "android-device-launcher",
+    runner = "reviver/runner",
+    target_builders = [
+        "ci/android-pie-arm64-rel",
+    ],
+    os = os.LINUX_DEFAULT,
+    pool = ci.DEFAULT_POOL,
+    # To avoid peak hours, we run it at 5 AM, 8 AM, 11AM UTC.
+    schedule = "0 5,8,11 * * *",
 )
 
 # A coordinator of slightly aggressive scheduling with effectively unlimited
@@ -70,7 +82,7 @@
     os = os.LINUX_DEFAULT,
     pool = ci.DEFAULT_POOL,
     # Avoid peak hours.
-    schedule = "0 1,3,5,7,9,11,13 * * *",
+    schedule = "0 2,4,6,8,10,12,14 * * *",
 )
 
 # A coordinator for lacros.
diff --git a/ios/chrome/browser/metrics/demographics_egtest.mm b/ios/chrome/browser/metrics/demographics_egtest.mm
index b074f45..53f91c7 100644
--- a/ios/chrome/browser/metrics/demographics_egtest.mm
+++ b/ios/chrome/browser/metrics/demographics_egtest.mm
@@ -127,8 +127,9 @@
   // Chrome and Turn on sync. This matches the main user flow that enables
   // UKM.
   [SigninEarlGreyUI signinWithFakeIdentity:[FakeSystemIdentity fakeIdentity1]];
-  [ChromeEarlGrey waitForSyncInitialized:YES
-                             syncTimeout:syncher::kSyncUKMOperationsTimeout];
+  [ChromeEarlGrey
+      waitForSyncEngineInitialized:YES
+                       syncTimeout:syncher::kSyncUKMOperationsTimeout];
 }
 
 // Adds a dummy UKM source to the UKM service's recordings. The presence of this
diff --git a/ios/chrome/browser/metrics/ukm_egtest.mm b/ios/chrome/browser/metrics/ukm_egtest.mm
index 7c5284a..50bf04b 100644
--- a/ios/chrome/browser/metrics/ukm_egtest.mm
+++ b/ios/chrome/browser/metrics/ukm_egtest.mm
@@ -43,8 +43,9 @@
 - (void)setUp {
   [super setUp];
 
-  [ChromeEarlGrey waitForSyncInitialized:NO
-                             syncTimeout:syncher::kSyncUKMOperationsTimeout];
+  [ChromeEarlGrey
+      waitForSyncEngineInitialized:NO
+                       syncTimeout:syncher::kSyncUKMOperationsTimeout];
   GREYAssert([MetricsAppInterface checkUKMRecordingEnabled:NO],
              @"Failed to assert that UKM was not enabled.");
   // Sign in to Chrome and turn sync on.
@@ -53,8 +54,9 @@
   // flow to Sign in to Chrome and Turn sync on. This matches the main user
   // flow that enables UKM.
   [SigninEarlGreyUI signinWithFakeIdentity:[FakeSystemIdentity fakeIdentity1]];
-  [ChromeEarlGrey waitForSyncInitialized:YES
-                             syncTimeout:syncher::kSyncUKMOperationsTimeout];
+  [ChromeEarlGrey
+      waitForSyncEngineInitialized:YES
+                       syncTimeout:syncher::kSyncUKMOperationsTimeout];
 
   // Grant metrics consent and update MetricsServicesManager.
   [MetricsAppInterface overrideMetricsAndCrashReportingForTesting];
@@ -65,8 +67,9 @@
 }
 
 - (void)tearDown {
-  [ChromeEarlGrey waitForSyncInitialized:YES
-                             syncTimeout:syncher::kSyncUKMOperationsTimeout];
+  [ChromeEarlGrey
+      waitForSyncEngineInitialized:YES
+                       syncTimeout:syncher::kSyncUKMOperationsTimeout];
   GREYAssert([MetricsAppInterface checkUKMRecordingEnabled:YES],
              @"Failed to assert that UKM was enabled.");
 
@@ -84,8 +87,9 @@
   // flow that disables UKM.
   [SigninEarlGrey signOut];
 
-  [ChromeEarlGrey waitForSyncInitialized:NO
-                             syncTimeout:syncher::kSyncUKMOperationsTimeout];
+  [ChromeEarlGrey
+      waitForSyncEngineInitialized:NO
+                       syncTimeout:syncher::kSyncUKMOperationsTimeout];
   [ChromeEarlGrey clearSyncServerData];
 
   [super tearDown];
diff --git a/ios/chrome/browser/passwords/password_controller_egtest.mm b/ios/chrome/browser/passwords/password_controller_egtest.mm
index 8fa8b01..97eaba2 100644
--- a/ios/chrome/browser/passwords/password_controller_egtest.mm
+++ b/ios/chrome/browser/passwords/password_controller_egtest.mm
@@ -189,7 +189,8 @@
   }
 #endif
   [SigninEarlGreyUI signinWithFakeIdentity:[FakeSystemIdentity fakeIdentity1]];
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:base::Seconds(10)];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:base::Seconds(10)];
 
   [ChromeEarlGrey loadURL:self.testServer->GetURL("/simple_signup_form.html")];
   [ChromeEarlGrey waitForWebStateContainingText:"Signup form."];
diff --git a/ios/chrome/browser/policy/user_policy_egtest.mm b/ios/chrome/browser/policy/user_policy_egtest.mm
index c31fb5d..bc9ed56 100644
--- a/ios/chrome/browser/policy/user_policy_egtest.mm
+++ b/ios/chrome/browser/policy/user_policy_egtest.mm
@@ -263,7 +263,8 @@
       [FakeSystemIdentity encodeIdentitiesToBase64:@[ fakeManagedIdentity ]]);
   [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config];
 
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:base::Seconds(5)];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:base::Seconds(5)];
 
   // Wait until the user policies are loaded from disk.
   WaitOnUserPolicy(kWaitOnScheduledUserPolicyFetchInterval);
diff --git a/ios/chrome/browser/ui/authentication/signin/advanced_settings_signin/advanced_settings_signin_egtest.mm b/ios/chrome/browser/ui/authentication/signin/advanced_settings_signin/advanced_settings_signin_egtest.mm
index 1759904..4a1e11b 100644
--- a/ios/chrome/browser/ui/authentication/signin/advanced_settings_signin/advanced_settings_signin_egtest.mm
+++ b/ios/chrome/browser/ui/authentication/signin/advanced_settings_signin/advanced_settings_signin_egtest.mm
@@ -118,7 +118,8 @@
   [SigninEarlGrey verifySignedInWithFakeIdentity:fakeIdentity];
 
   // Add a bookmark after sync is initialized.
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
   [ChromeEarlGrey waitForBookmarksToFinishLoading];
   [BookmarkEarlGrey setupStandardBookmarks];
 
@@ -165,7 +166,8 @@
   [SigninEarlGrey verifySignedInWithFakeIdentity:fakeIdentity];
 
   // Add a bookmark after sync is initialized.
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
   [ChromeEarlGrey waitForBookmarksToFinishLoading];
   [BookmarkEarlGrey setupStandardBookmarks];
 
diff --git a/ios/chrome/browser/ui/authentication/signin/forced_signin/forced_signin_egtest.mm b/ios/chrome/browser/ui/authentication/signin/forced_signin/forced_signin_egtest.mm
index 7e064aa..ba6c18c 100644
--- a/ios/chrome/browser/ui/authentication/signin/forced_signin/forced_signin_egtest.mm
+++ b/ios/chrome/browser/ui/authentication/signin/forced_signin/forced_signin_egtest.mm
@@ -408,7 +408,8 @@
 
   // Enable sync.
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity1];
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
 
   OpenAccountSettingsAndSignOut(YES);
 
@@ -454,7 +455,8 @@
 
   // Enable sync.
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity1];
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
 
   [ChromeEarlGreyUI openSettingsMenu];
   [ChromeEarlGreyUI tapSettingsMenuButton:GoogleSyncSettingsButton()];
@@ -718,7 +720,8 @@
 
   // Sync utilities require sync to be initialized in order to perform
   // operations on the Sync server.
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:base::Seconds(10)];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:base::Seconds(10)];
 
   // Make sure the forced sign-in screen isn't shown because sign-in was
   // already done.
@@ -857,7 +860,8 @@
 
   // Sync utilities require sync to be initialized in order to perform
   // operations on the Sync server.
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:base::Seconds(10)];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:base::Seconds(10)];
 
   // Make sure the forced sign-in screen isn't shown because the browser is
   // already signed in.
diff --git a/ios/chrome/browser/ui/authentication/signin/signin_coordinator_egtest.mm b/ios/chrome/browser/ui/authentication/signin/signin_coordinator_egtest.mm
index 9dad64d..a5352d38 100644
--- a/ios/chrome/browser/ui/authentication/signin/signin_coordinator_egtest.mm
+++ b/ios/chrome/browser/ui/authentication/signin/signin_coordinator_egtest.mm
@@ -242,7 +242,8 @@
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity];
 
   // Add a bookmark after sync is initialized.
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
   [ChromeEarlGrey waitForBookmarksToFinishLoading];
   [BookmarkEarlGrey setupStandardBookmarks];
 
@@ -278,7 +279,8 @@
   [SigninEarlGreyUI signinWithFakeIdentity:fakeSupervisedIdentity];
 
   // Add a bookmark after sync is initialized.
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
   [ChromeEarlGrey waitForBookmarksToFinishLoading];
   [BookmarkEarlGrey setupStandardBookmarks];
 
@@ -302,7 +304,8 @@
   [SigninEarlGreyUI signinWithFakeIdentity:fakeSupervisedIdentity];
 
   // Add a bookmark after sync is initialized.
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
   [ChromeEarlGrey waitForBookmarksToFinishLoading];
   [BookmarkEarlGrey setupStandardBookmarks];
 
diff --git a/ios/chrome/browser/ui/authentication/signin_earl_grey_ui_test_util.mm b/ios/chrome/browser/ui/authentication/signin_earl_grey_ui_test_util.mm
index 79f0b53..7317c2c 100644
--- a/ios/chrome/browser/ui/authentication/signin_earl_grey_ui_test_util.mm
+++ b/ios/chrome/browser/ui/authentication/signin_earl_grey_ui_test_util.mm
@@ -108,7 +108,8 @@
 
   // Sync utilities require sync to be initialized in order to perform
   // operations on the Sync server.
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:base::Seconds(10)];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:base::Seconds(10)];
 }
 
 + (void)signOutWithConfirmationChoice:(SignOutConfirmationChoice)confirmation {
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm b/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm
index a44b149..da17ec0 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm
@@ -551,7 +551,8 @@
     EARL_GREY_TEST_DISABLED(@"Test disabled on iOS 15.3.");
   }
   [SigninEarlGreyUI signinWithFakeIdentity:[FakeSystemIdentity fakeIdentity1]];
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:base::Seconds(10)];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:base::Seconds(10)];
 
   const GURL URL = self.testServer->GetURL(kFormHTMLFile);
   [ChromeEarlGrey loadURL:URL];
diff --git a/ios/chrome/browser/ui/history/history_ui_egtest.mm b/ios/chrome/browser/ui/history/history_ui_egtest.mm
index 05c03e4..71d221e127 100644
--- a/ios/chrome/browser/ui/history/history_ui_egtest.mm
+++ b/ios/chrome/browser/ui/history/history_ui_egtest.mm
@@ -295,7 +295,8 @@
   [SigninEarlGrey addFakeIdentity:fakeIdentity];
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity];
 
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
   [ChromeEarlGrey triggerSyncCycleForType:syncer::TYPED_URLS];
 
   [ChromeEarlGrey waitForSyncServerEntitiesWithType:syncer::TYPED_URLS
diff --git a/ios/chrome/browser/ui/ntp/feed_control_delegate.h b/ios/chrome/browser/ui/ntp/feed_control_delegate.h
index f4c6dae9..d03dd1b0 100644
--- a/ios/chrome/browser/ui/ntp/feed_control_delegate.h
+++ b/ios/chrome/browser/ui/ntp/feed_control_delegate.h
@@ -30,6 +30,9 @@
 // for certain circumstances like restricted accounts.
 - (BOOL)isFollowingFeedAvailable;
 
+// Returns the index of the last visible feed card.
+- (NSUInteger)lastVisibleFeedCardIndex;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_NTP_FEED_CONTROL_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/ntp/feed_header_view_controller.mm b/ios/chrome/browser/ui/ntp/feed_header_view_controller.mm
index 728e11a..eeb932c 100644
--- a/ios/chrome/browser/ui/ntp/feed_header_view_controller.mm
+++ b/ios/chrome/browser/ui/ntp/feed_header_view_controller.mm
@@ -763,7 +763,10 @@
 - (void)onSegmentSelected:(UISegmentedControl*)segmentedControl {
   switch (segmentedControl.selectedSegmentIndex) {
     case static_cast<NSInteger>(FeedTypeDiscover): {
-      [self.feedMetricsRecorder recordFeedSelected:FeedTypeDiscover];
+      [self.feedMetricsRecorder
+                recordFeedSelected:FeedTypeDiscover
+          fromPreviousFeedPosition:[self.feedControlDelegate
+                                           lastVisibleFeedCardIndex]];
       [self.feedControlDelegate handleFeedSelected:FeedTypeDiscover];
       [UIView animateWithDuration:kSegmentAnimationDuration
                        animations:^{
@@ -772,7 +775,10 @@
       break;
     }
     case static_cast<NSInteger>(FeedTypeFollowing): {
-      [self.feedMetricsRecorder recordFeedSelected:FeedTypeFollowing];
+      [self.feedMetricsRecorder
+                recordFeedSelected:FeedTypeFollowing
+          fromPreviousFeedPosition:[self.feedControlDelegate
+                                           lastVisibleFeedCardIndex]];
       [self.feedControlDelegate handleFeedSelected:FeedTypeFollowing];
       // Only show sorting button for Following feed.
       [UIView animateWithDuration:kSegmentAnimationDuration
diff --git a/ios/chrome/browser/ui/ntp/feed_wrapper_view_controller.h b/ios/chrome/browser/ui/ntp/feed_wrapper_view_controller.h
index 56baa751..83356d4 100644
--- a/ios/chrome/browser/ui/ntp/feed_wrapper_view_controller.h
+++ b/ios/chrome/browser/ui/ntp/feed_wrapper_view_controller.h
@@ -38,6 +38,9 @@
                          bundle:(NSBundle*)nibBundleOrNil NS_UNAVAILABLE;
 - (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE;
 
+// Returns the index of the last visible feed card.
+- (NSUInteger)lastVisibleFeedCardIndex;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_NTP_FEED_WRAPPER_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/ntp/feed_wrapper_view_controller.mm b/ios/chrome/browser/ui/ntp/feed_wrapper_view_controller.mm
index 5b6a14b..20c5842 100644
--- a/ios/chrome/browser/ui/ntp/feed_wrapper_view_controller.mm
+++ b/ios/chrome/browser/ui/ntp/feed_wrapper_view_controller.mm
@@ -54,6 +54,19 @@
   }
 }
 
+#pragma mark - Public
+
+- (NSUInteger)lastVisibleFeedCardIndex {
+  DCHECK(self.contentCollectionView);
+  NSArray<NSIndexPath*>* visibleCardIndices =
+      [self.contentCollectionView indexPathsForVisibleItems];
+  NSInteger lastVisibleIndex;
+  for (NSIndexPath* cardIndex in visibleCardIndices) {
+    lastVisibleIndex = MAX(lastVisibleIndex, cardIndex.item);
+  }
+  return lastVisibleIndex;
+}
+
 #pragma mark - Private
 
 // If the feed is visible, we configure the feed's collection view and view
diff --git a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.h b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.h
index 4706108b..2a43952 100644
--- a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.h
+++ b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.h
@@ -268,6 +268,13 @@
 // Histogram for an action taken on the start surface.
 extern const char kActionOnStartSurface[];
 
+// Histogram name for last visible card when switching from Discover to
+// Following feed.
+extern const char kDiscoverIndexWhenSwitchingFeed[];
+// Histogram name for last visible card when switching from Following to
+// Discover feed.
+extern const char kFollowingIndexWhenSwitchingFeed[];
+
 #pragma mark - User Actions
 
 // User action names for the device orientation having changed.
diff --git a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.mm b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.mm
index ac8f21f..e7031c92 100644
--- a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.mm
+++ b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.mm
@@ -78,6 +78,10 @@
 const char kActionOnNTP[] = "IOS.ContentSuggestions.ActionOnNTP";
 const char kActionOnStartSurface[] =
     "IOS.ContentSuggestions.ActionOnStartSurface";
+const char kDiscoverIndexWhenSwitchingFeed[] =
+    "ContentSuggestions.Feed.CardIndexOnSwitch";
+const char kFollowingIndexWhenSwitchingFeed[] =
+    "ContentSuggestions.Feed.WebFeed.CardIndexOnSwitch";
 
 #pragma mark - User Actions
 
diff --git a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.h b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.h
index 05c286ec..50d6074 100644
--- a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.h
+++ b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.h
@@ -122,10 +122,10 @@
 - (void)recordCommandID:(int)commandID;
 
 // Records that a card was shown at `index`.
-- (void)recordCardShownAtIndex:(int)index;
+- (void)recordCardShownAtIndex:(NSUInteger)index;
 
 // Records that a card was opened at `index`.
-- (void)recordCardTappedAtIndex:(int)index;
+- (void)recordCardTappedAtIndex:(NSUInteger)index;
 
 // Records if a notice card was presented at the time the feed was initially
 // loaded. e.g. Launch time, user refreshes, and account switches.
@@ -187,8 +187,10 @@
 // Records that the feed is about to be refreshed.
 - (void)recordFeedWillRefresh;
 
-// Records that a given `feedType` was selected.
-- (void)recordFeedSelected:(FeedType)feedType;
+// Records that a given `feedType` was explicitly selected. Logs position in
+// previous feed as `index`.
+- (void)recordFeedSelected:(FeedType)feedType
+    fromPreviousFeedPosition:(NSUInteger)index;
 
 // Records the user's current follow count after a given event `logReason`.
 - (void)recordFollowCount:(NSUInteger)followCount
diff --git a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.mm b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.mm
index a26736d..5e4eb4e0 100644
--- a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.mm
+++ b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.mm
@@ -330,7 +330,7 @@
   base::UmaHistogramSparse(kDiscoverFeedUserActionCommandHistogram, commandID);
 }
 
-- (void)recordCardShownAtIndex:(int)index {
+- (void)recordCardShownAtIndex:(NSUInteger)index {
   switch ([self.feedControlDelegate selectedFeed]) {
     case FeedTypeDiscover:
       UMA_HISTOGRAM_EXACT_LINEAR(kDiscoverFeedCardShownAtIndex, index,
@@ -342,7 +342,7 @@
   }
 }
 
-- (void)recordCardTappedAtIndex:(int)index {
+- (void)recordCardTappedAtIndex:(NSUInteger)index {
   switch ([self.feedControlDelegate selectedFeed]) {
     case FeedTypeDiscover:
       UMA_HISTOGRAM_EXACT_LINEAR(kDiscoverFeedCardOpenedAtIndex, index,
@@ -461,7 +461,8 @@
   base::RecordAction(base::UserMetricsAction(kFeedWillRefresh));
 }
 
-- (void)recordFeedSelected:(FeedType)feedType {
+- (void)recordFeedSelected:(FeedType)feedType
+    fromPreviousFeedPosition:(NSUInteger)index {
   DCHECK(self.followDelegate);
   switch (feedType) {
     case FeedTypeDiscover:
@@ -469,12 +470,16 @@
                                                       kDiscoverFeedSelected
                                     asInteraction:NO];
       base::RecordAction(base::UserMetricsAction(kDiscoverFeedSelected));
+      UMA_HISTOGRAM_EXACT_LINEAR(kFollowingIndexWhenSwitchingFeed, index,
+                                 kMaxCardsInFeed);
       break;
     case FeedTypeFollowing:
       [self recordDiscoverFeedUserActionHistogram:FeedUserActionType::
                                                       kFollowingFeedSelected
                                     asInteraction:NO];
       base::RecordAction(base::UserMetricsAction(kFollowingFeedSelected));
+      UMA_HISTOGRAM_EXACT_LINEAR(kDiscoverIndexWhenSwitchingFeed, index,
+                                 kMaxCardsInFeed);
       NSUInteger followCount = [self.followDelegate followedPublisherCount];
       if (followCount > 0 &&
           [self.followDelegate doesFollowingFeedHaveContent]) {
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
index 96761dd..463de66c 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
@@ -915,6 +915,10 @@
          self.authService->HasPrimaryIdentity(signin::ConsentLevel::kSignin);
 }
 
+- (NSUInteger)lastVisibleFeedCardIndex {
+  return [self.feedWrapperViewController lastVisibleFeedCardIndex];
+}
+
 #pragma mark - FeedDelegate
 
 - (void)contentSuggestionsWasUpdated {
@@ -1442,6 +1446,7 @@
            followingSegmentDotVisible:followingSegmentDotVisible];
     _feedHeaderViewController.feedControlDelegate = self;
     _feedHeaderViewController.ntpDelegate = self;
+    _feedHeaderViewController.feedMetricsRecorder = self.feedMetricsRecorder;
     [_feedHeaderViewController.menuButton
                addTarget:self
                   action:@selector(openFeedMenu)
diff --git a/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm b/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm
index 7a9a191..c134c98a 100644
--- a/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm
+++ b/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm
@@ -221,7 +221,8 @@
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity];
 
   // Add a bookmark after sync is initialized.
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
   [ChromeEarlGrey waitForBookmarksToFinishLoading];
   [BookmarkEarlGrey setupStandardBookmarks];
 
@@ -248,7 +249,8 @@
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity];
 
   // Add a bookmark after sync is initialized.
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
   [ChromeEarlGrey waitForBookmarksToFinishLoading];
   [BookmarkEarlGrey setupStandardBookmarks];
 
@@ -273,7 +275,8 @@
       signinWithFakeIdentity:[FakeSystemIdentity fakeManagedIdentity]];
 
   // Add a bookmark after sync is initialized.
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
   [ChromeEarlGrey waitForBookmarksToFinishLoading];
   [BookmarkEarlGrey setupStandardBookmarks];
 
@@ -344,7 +347,8 @@
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity];
 
   // Add a bookmark after sync is initialized.
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
   [ChromeEarlGrey waitForBookmarksToFinishLoading];
   [BookmarkEarlGrey setupStandardBookmarks];
 
diff --git a/ios/chrome/browser/ui/settings/google_services/google_services_settings_egtest.mm b/ios/chrome/browser/ui/settings/google_services/google_services_settings_egtest.mm
index 82cd7cb..49bc6ca 100644
--- a/ios/chrome/browser/ui/settings/google_services/google_services_settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/google_services/google_services_settings_egtest.mm
@@ -380,7 +380,8 @@
   [SigninEarlGrey verifySignedInWithFakeIdentity:fakeIdentity];
 
   // Add a bookmark after sync is initialized.
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kWaitForActionTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kWaitForActionTimeout];
   [ChromeEarlGrey waitForBookmarksToFinishLoading];
   [BookmarkEarlGrey setupStandardBookmarks];
 
@@ -448,7 +449,8 @@
   [SigninEarlGrey verifySignedInWithFakeIdentity:fakeIdentity];
 
   // Add a bookmark after sync is initialized.
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kWaitForActionTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kWaitForActionTimeout];
   [ChromeEarlGrey waitForBookmarksToFinishLoading];
   [BookmarkEarlGrey setupStandardBookmarks];
 
diff --git a/ios/chrome/browser/ui/settings/password/BUILD.gn b/ios/chrome/browser/ui/settings/password/BUILD.gn
index c4f2d9ed..ebd2ae1 100644
--- a/ios/chrome/browser/ui/settings/password/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/password/BUILD.gn
@@ -250,6 +250,7 @@
     "//components/strings",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/passwords",
+    "//ios/chrome/browser/sync",
     "//ios/chrome/common/ui/reauthentication",
     "//ios/chrome/test/app:test_support",
     "//ios/testing/earl_grey:eg_app_support+eg2",
diff --git a/ios/chrome/browser/ui/settings/password/legacy_password_settings_egtest.mm b/ios/chrome/browser/ui/settings/password/legacy_password_settings_egtest.mm
index 9e99013..2cd9447 100644
--- a/ios/chrome/browser/ui/settings/password/legacy_password_settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/password/legacy_password_settings_egtest.mm
@@ -2130,7 +2130,8 @@
   // Sign-in and synced user.
   FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1];
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity];
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:base::Seconds(5)];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:base::Seconds(5)];
 
   // Add passwords for the user.
   SaveExamplePasswordForms();
diff --git a/ios/chrome/browser/ui/settings/password/password_manager_egtest.mm b/ios/chrome/browser/ui/settings/password/password_manager_egtest.mm
index c0880f4..f8847de9 100644
--- a/ios/chrome/browser/ui/settings/password/password_manager_egtest.mm
+++ b/ios/chrome/browser/ui/settings/password/password_manager_egtest.mm
@@ -2321,7 +2321,8 @@
   // Sign-in and synced user.
   FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1];
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity];
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:base::Seconds(5)];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:base::Seconds(5)];
 
   // Add passwords for the user.
   SaveExamplePasswordForms();
diff --git a/ios/chrome/browser/ui/settings/password/password_settings_app_interface.h b/ios/chrome/browser/ui/settings/password/password_settings_app_interface.h
index ede7597..c27ec72 100644
--- a/ios/chrome/browser/ui/settings/password/password_settings_app_interface.h
+++ b/ios/chrome/browser/ui/settings/password/password_settings_app_interface.h
@@ -60,6 +60,9 @@
 // Returns YES if credential service is enabled.
 + (BOOL)isCredentialsServiceEnabled;
 
+// See password_manager::features_util::IsOptedInForAccountStorage().
++ (BOOL)isOptedInForAccountStorage;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_PASSWORD_SETTINGS_APP_INTERFACE_H_
diff --git a/ios/chrome/browser/ui/settings/password/password_settings_app_interface.mm b/ios/chrome/browser/ui/settings/password/password_settings_app_interface.mm
index 62ecde6c..3ee7a954 100644
--- a/ios/chrome/browser/ui/settings/password/password_settings_app_interface.mm
+++ b/ios/chrome/browser/ui/settings/password/password_settings_app_interface.mm
@@ -14,12 +14,14 @@
 #import "base/time/time.h"
 #import "components/keyed_service/core/service_access_type.h"
 #import "components/password_manager/core/browser/password_form.h"
+#import "components/password_manager/core/browser/password_manager_features_util.h"
 #import "components/password_manager/core/browser/password_store_consumer.h"
 #import "components/password_manager/core/browser/password_store_interface.h"
 #import "components/password_manager/core/common/password_manager_pref_names.h"
 #import "components/prefs/pref_service.h"
 #import "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h"
+#import "ios/chrome/browser/sync/sync_service_factory.h"
 #import "ios/chrome/test/app/chrome_test_util.h"
 #import "ios/chrome/test/app/password_test_util.h"
 #import "url/gurl.h"
@@ -264,4 +266,13 @@
       password_manager::prefs::kCredentialsEnableService);
 }
 
++ (BOOL)isOptedInForAccountStorage {
+  ChromeBrowserState* browserState =
+      chrome_test_util::GetOriginalBrowserState();
+  syncer::SyncService* syncService =
+      SyncServiceFactory::GetForBrowserState(browserState);
+  return password_manager::features_util::IsOptedInForAccountStorage(
+      browserState->GetPrefs(), syncService);
+}
+
 @end
diff --git a/ios/chrome/browser/ui/settings/sync/utils/sync_fake_server_egtest.mm b/ios/chrome/browser/ui/settings/sync/utils/sync_fake_server_egtest.mm
index 51c6d19..825f443 100644
--- a/ios/chrome/browser/ui/settings/sync/utils/sync_fake_server_egtest.mm
+++ b/ios/chrome/browser/ui/settings/sync/utils/sync_fake_server_egtest.mm
@@ -87,7 +87,8 @@
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity];
 
   // Assert that the correct number of bookmarks have been synced.
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
   WaitForNumberOfEntities(1, syncer::BOOKMARKS);
 }
 
@@ -98,7 +99,8 @@
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity];
 
   // Add a bookmark after sync is initialized.
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
   [BookmarkEarlGrey addBookmarkWithTitle:@"goo" URL:@"https://www.goo.com"];
   WaitForNumberOfEntities(1, syncer::BOOKMARKS);
 }
@@ -115,7 +117,8 @@
   [SigninEarlGrey addFakeIdentity:fakeIdentity];
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity];
 
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
   WaitForNumberOfEntities(1, syncer::BOOKMARKS);
   [BookmarkEarlGrey verifyBookmarksWithTitle:@"hoo" expectedCount:1];
 }
@@ -127,16 +130,19 @@
   FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1];
   [SigninEarlGrey addFakeIdentity:fakeIdentity];
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity];
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
 
   // Store the original guid, then restart sync.
   std::string original_guid = [ChromeEarlGrey syncCacheGUID];
   [ChromeEarlGrey stopSync];
-  [ChromeEarlGrey waitForSyncInitialized:NO syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:NO
+                                   syncTimeout:kSyncOperationTimeout];
   [ChromeEarlGrey startSync];
 
   // Verify the guid did not change.
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
   GREYAssertEqual([ChromeEarlGrey syncCacheGUID], original_guid,
                   @"Stored guid doesn't match current value");
 }
@@ -148,16 +154,19 @@
   FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1];
   [SigninEarlGrey addFakeIdentity:fakeIdentity];
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity];
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
   std::string original_guid = [ChromeEarlGrey syncCacheGUID];
 
   [SigninEarlGrey verifySignedInWithFakeIdentity:fakeIdentity];
   [SigninEarlGrey signOut];
-  [ChromeEarlGrey waitForSyncInitialized:NO syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:NO
+                                   syncTimeout:kSyncOperationTimeout];
 
   // Sign the user back in, and verify the guid has changed.
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity];
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
   GREYAssertTrue(
       [ChromeEarlGrey syncCacheGUID] != original_guid,
       @"guid didn't change after user signed out and signed back in");
@@ -172,24 +181,29 @@
   FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1];
   [SigninEarlGrey addFakeIdentity:fakeIdentity];
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity];
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
 
   [SigninEarlGrey verifySignedInWithFakeIdentity:fakeIdentity];
   [SigninEarlGrey signOut];
-  [ChromeEarlGrey waitForSyncInitialized:NO syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:NO
+                                   syncTimeout:kSyncOperationTimeout];
 
   // Sign the user back in.
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity];
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
 
   // Record the initial guid, before restarting sync.
   std::string original_guid = [ChromeEarlGrey syncCacheGUID];
   [ChromeEarlGrey stopSync];
-  [ChromeEarlGrey waitForSyncInitialized:NO syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:NO
+                                   syncTimeout:kSyncOperationTimeout];
   [ChromeEarlGrey startSync];
 
   // Verify the guid did not change after restarting sync.
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
   GREYAssertEqual([ChromeEarlGrey syncCacheGUID], original_guid,
                   @"Stored guid doesn't match current value");
 }
@@ -213,7 +227,8 @@
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity];
 
   // Verify that the autofill profile has been downloaded.
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
   WaitForNumberOfEntities(1, syncer::AUTOFILL_PROFILE);
   GREYAssertTrue([ChromeEarlGrey isAutofillProfilePresentWithGUID:kGuid
                                               autofillProfileName:kFullName],
@@ -242,7 +257,8 @@
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity];
 
   // Verify that the autofill profile has been downloaded.
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
   WaitForNumberOfEntities(1, syncer::AUTOFILL_PROFILE);
   GREYAssertTrue([ChromeEarlGrey isAutofillProfilePresentWithGUID:kGuid
                                               autofillProfileName:kFullName],
@@ -289,7 +305,8 @@
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity];
 
   // Verify that the autofill profile has been downloaded
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
   WaitForNumberOfEntities(1, syncer::AUTOFILL_PROFILE);
   GREYAssertTrue([ChromeEarlGrey isAutofillProfilePresentWithGUID:kGuid
                                               autofillProfileName:kFullName],
@@ -330,7 +347,8 @@
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity];
 
   // Verify the sessions on the sync server.
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
   WaitForNumberOfEntities(3, syncer::SESSIONS);
 
   NSArray<NSString*>* specs = @[
@@ -356,7 +374,8 @@
   [SigninEarlGrey addFakeIdentity:fakeIdentity];
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity];
 
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
 
   // Trigger sync and verify the typed URL is on the fake sync server.
   [ChromeEarlGrey triggerSyncCycleForType:syncer::TYPED_URLS];
@@ -383,7 +402,8 @@
   [SigninEarlGrey addFakeIdentity:fakeIdentity];
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity];
 
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
 
   // Wait for typed url to appear on client.
   [ChromeEarlGrey waitForTypedURL:mockURL
@@ -409,7 +429,8 @@
   [SigninEarlGrey addFakeIdentity:fakeIdentity];
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity];
 
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
 
   // Wait for typed url to appear on client.
   [ChromeEarlGrey waitForTypedURL:mockURL
@@ -443,7 +464,8 @@
   [SigninEarlGrey addFakeIdentity:fakeIdentity];
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity];
 
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
   [ChromeEarlGrey triggerSyncCycleForType:syncer::TYPED_URLS];
 
   [ChromeEarlGrey waitForSyncServerEntitiesWithType:syncer::TYPED_URLS
@@ -485,7 +507,8 @@
   [SigninEarlGrey addFakeIdentity:fakeIdentity];
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity];
 
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
   WaitForNumberOfEntities(2, syncer::BOOKMARKS);
 
   [BookmarkEarlGrey verifyBookmarksWithTitle:title1 expectedCount:1];
@@ -498,7 +521,8 @@
   [SigninEarlGrey addFakeIdentity:fakeIdentity];
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity];
 
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout];
+  [ChromeEarlGrey waitForSyncEngineInitialized:YES
+                                   syncTimeout:kSyncOperationTimeout];
   WaitForNumberOfEntities(1, syncer::DEVICE_INFO);
   [ChromeEarlGrey waitForSyncInvalidationFields];
 }
diff --git a/ios/chrome/test/app/sync_test_util.h b/ios/chrome/test/app/sync_test_util.h
index 4a3fe75..1ca149b 100644
--- a/ios/chrome/test/app/sync_test_util.h
+++ b/ios/chrome/test/app/sync_test_util.h
@@ -80,8 +80,8 @@
 // nothing.
 void ClearSyncServerData();
 
-// Returns true if the sync backend server is intialized.
-bool IsSyncInitialized();
+// See SyncService::IsEngineInitialized().
+bool IsSyncEngineInitialized();
 
 // Returns the current sync cache guid. The sync server must be running when
 // calling this.
diff --git a/ios/chrome/test/app/sync_test_util.mm b/ios/chrome/test/app/sync_test_util.mm
index 2b8524f..65b23285 100644
--- a/ios/chrome/test/app/sync_test_util.mm
+++ b/ios/chrome/test/app/sync_test_util.mm
@@ -103,7 +103,7 @@
 }
 
 void StartSync() {
-  DCHECK(!IsSyncInitialized());
+  DCHECK(!IsSyncEngineInitialized());
   ChromeBrowserState* browser_state =
       chrome_test_util::GetOriginalBrowserState();
   SyncSetupService* sync_setup_service =
@@ -112,7 +112,7 @@
 }
 
 void StopSync() {
-  DCHECK(IsSyncInitialized());
+  DCHECK(IsSyncEngineInitialized());
   ChromeBrowserState* browser_state =
       chrome_test_util::GetOriginalBrowserState();
   SyncSetupService* sync_setup_service =
@@ -186,7 +186,7 @@
           .BuildBookmark(GURL(url)));
 }
 
-bool IsSyncInitialized() {
+bool IsSyncEngineInitialized() {
   ChromeBrowserState* browser_state =
       chrome_test_util::GetOriginalBrowserState();
   DCHECK(browser_state);
@@ -196,7 +196,7 @@
 }
 
 std::string GetSyncCacheGuid() {
-  DCHECK(IsSyncInitialized());
+  DCHECK(IsSyncEngineInitialized());
   ChromeBrowserState* browser_state =
       chrome_test_util::GetOriginalBrowserState();
   syncer::DeviceInfoSyncService* service =
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey.h b/ios/chrome/test/earl_grey/chrome_earl_grey.h
index 913d1a1..3aa30ac 100644
--- a/ios/chrome/test/earl_grey/chrome_earl_grey.h
+++ b/ios/chrome/test/earl_grey/chrome_earl_grey.h
@@ -469,8 +469,8 @@
 // that data types are configured and ready to use. See
 // SyncService::IsEngineInitialized() for details. If not succeeded a GREYAssert
 // is induced.
-- (void)waitForSyncInitialized:(BOOL)isInitialized
-                   syncTimeout:(base::TimeDelta)timeout;
+- (void)waitForSyncEngineInitialized:(BOOL)isInitialized
+                         syncTimeout:(base::TimeDelta)timeout;
 
 // Returns the current sync cache GUID. The sync server must be running when
 // calling this.
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey.mm b/ios/chrome/test/earl_grey/chrome_earl_grey.mm
index 042212c..32d7a1f6 100644
--- a/ios/chrome/test/earl_grey/chrome_earl_grey.mm
+++ b/ios/chrome/test/earl_grey/chrome_earl_grey.mm
@@ -885,11 +885,11 @@
       deleteAutofillProfileFromFakeSyncServerWithGUID:GUID];
 }
 
-- (void)waitForSyncInitialized:(BOOL)isInitialized
-                   syncTimeout:(base::TimeDelta)timeout {
+- (void)waitForSyncEngineInitialized:(BOOL)isInitialized
+                         syncTimeout:(base::TimeDelta)timeout {
   EG_TEST_HELPER_ASSERT_NO_ERROR([ChromeEarlGreyAppInterface
-      waitForSyncInitialized:isInitialized
-                 syncTimeout:timeout]);
+      waitForSyncEngineInitialized:isInitialized
+                       syncTimeout:timeout]);
 }
 
 - (const std::string)syncCacheGUID {
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.h b/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.h
index 83d6a712..f39ebc1 100644
--- a/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.h
+++ b/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.h
@@ -358,11 +358,12 @@
 // Stops the sync server. The server should be running when calling this.
 + (void)stopSync;
 
-// Waits for sync to be initialized or not.
-// Returns nil on success, or else an NSError indicating why the
-// operation failed.
-+ (NSError*)waitForSyncInitialized:(BOOL)isInitialized
-                       syncTimeout:(base::TimeDelta)timeout;
+// Waits for sync engine to be initialized or not. It doesn't necessarily mean
+// that data types are configured and ready to use. See
+// SyncService::IsEngineInitialized() for details. If not succeeded a GREYAssert
+// is induced.
++ (NSError*)waitForSyncEngineInitialized:(BOOL)isInitialized
+                             syncTimeout:(base::TimeDelta)timeout;
 
 // Returns the current sync cache GUID. The sync server must be running when
 // calling this.
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.mm b/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.mm
index 8e2cf08..de3fd30 100644
--- a/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.mm
+++ b/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.mm
@@ -872,10 +872,10 @@
   chrome_test_util::StopSync();
 }
 
-+ (NSError*)waitForSyncInitialized:(BOOL)isInitialized
-                       syncTimeout:(base::TimeDelta)timeout {
++ (NSError*)waitForSyncEngineInitialized:(BOOL)isInitialized
+                             syncTimeout:(base::TimeDelta)timeout {
   bool success = WaitUntilConditionOrTimeout(timeout, ^{
-    return chrome_test_util::IsSyncInitialized() == isInitialized;
+    return chrome_test_util::IsSyncEngineInitialized() == isInitialized;
   });
   if (!success) {
     NSString* errorDescription =
diff --git a/ios/chrome/test/earl_grey2/smoke_egtest.mm b/ios/chrome/test/earl_grey2/smoke_egtest.mm
index cf0fdd16..c31b7bcb 100644
--- a/ios/chrome/test/earl_grey2/smoke_egtest.mm
+++ b/ios/chrome/test/earl_grey2/smoke_egtest.mm
@@ -155,7 +155,8 @@
 // Tests sync server converted helpers in chrome_earl_grey.h.
 - (void)testSyncServerHelpers {
   [ChromeEarlGrey startSync];
-  [ChromeEarlGrey waitForSyncInitialized:NO syncTimeout:base::Seconds(10)];
+  [ChromeEarlGrey waitForSyncEngineInitialized:NO
+                                   syncTimeout:base::Seconds(10)];
   [ChromeEarlGrey clearSyncServerData];
 }
 
diff --git a/ios/web_view/internal/cwv_lookalike_url_handler_unittest.mm b/ios/web_view/internal/cwv_lookalike_url_handler_unittest.mm
index 03ec87a..eaead10 100644
--- a/ios/web_view/internal/cwv_lookalike_url_handler_unittest.mm
+++ b/ios/web_view/internal/cwv_lookalike_url_handler_unittest.mm
@@ -42,7 +42,8 @@
       const GURL& request_url,
       base::OnceCallback<void(NSString*)> callback) {
     auto url_info = std::make_unique<LookalikeUrlContainer::LookalikeUrlInfo>(
-        safe_url, request_url, LookalikeUrlMatchType::kSiteEngagement);
+        safe_url, request_url,
+        LookalikeUrlMatchType::kSkeletonMatchSiteEngagement);
     return
         [[CWVLookalikeURLHandler alloc] initWithWebState:&web_state_
                                         lookalikeURLInfo:std::move(url_info)
diff --git a/media/base/decoder_status.h b/media/base/decoder_status.h
index c87582a..354ff87 100644
--- a/media/base/decoder_status.h
+++ b/media/base/decoder_status.h
@@ -43,7 +43,6 @@
     kMediaFoundationNotAvailable = 207,
   };
   static constexpr StatusGroupType Group() { return "DecoderStatus"; }
-  static constexpr Codes DefaultEnumValue() { return Codes::kOk; }
 };
 
 using DecoderStatus = TypedStatus<DecoderStatusTraits>;
diff --git a/media/base/encoder_status.h b/media/base/encoder_status.h
index 342e181..56170ea4 100644
--- a/media/base/encoder_status.h
+++ b/media/base/encoder_status.h
@@ -26,7 +26,6 @@
     kFormatConversionError = 12,
   };
   static constexpr StatusGroupType Group() { return "EncoderStatus"; }
-  static constexpr Codes DefaultEnumValue() { return Codes::kOk; }
 };
 
 using EncoderStatus = TypedStatus<EncoderStatusTraits>;
diff --git a/media/base/media_serializers.h b/media/base/media_serializers.h
index 018fc61b..623bd08 100644
--- a/media/base/media_serializers.h
+++ b/media/base/media_serializers.h
@@ -263,7 +263,7 @@
 template <>
 struct MediaSerializer<VideoColorSpace> {
   static inline base::Value Serialize(const VideoColorSpace& value) {
-    base::Value result(base::Value::Type::DICTIONARY);
+    base::Value result(base::Value::Type::DICT);
     FIELD_SERIALIZE("primaries", value.primaries);
     FIELD_SERIALIZE("transfer", value.transfer);
     FIELD_SERIALIZE("matrix", value.matrix);
@@ -277,7 +277,7 @@
 struct MediaSerializer<gfx::HDRMetadata> {
   static base::Value Serialize(const gfx::HDRMetadata& value) {
     // TODO(tmathmeyer) serialize more fields here potentially.
-    base::Value result(base::Value::Type::DICTIONARY);
+    base::Value result(base::Value::Type::DICT);
     FIELD_SERIALIZE(
         "luminance range",
         base::StringPrintf("%.2f => %.2f",
@@ -298,7 +298,7 @@
 template <>
 struct MediaSerializer<AudioDecoderConfig> {
   static base::Value Serialize(const AudioDecoderConfig& value) {
-    base::Value result(base::Value::Type::DICTIONARY);
+    base::Value result(base::Value::Type::DICT);
     FIELD_SERIALIZE("codec", value.codec());
     FIELD_SERIALIZE("profile", value.profile());
     FIELD_SERIALIZE("bytes per channel", value.bytes_per_channel());
@@ -338,7 +338,7 @@
 template <>
 struct MediaSerializer<VideoDecoderConfig> {
   static base::Value Serialize(const VideoDecoderConfig& value) {
-    base::Value result(base::Value::Type::DICTIONARY);
+    base::Value result(base::Value::Type::DICT);
     FIELD_SERIALIZE("codec", value.codec());
     FIELD_SERIALIZE("profile", value.profile());
     FIELD_SERIALIZE("alpha mode", value.alpha_mode());
@@ -358,7 +358,7 @@
 template <>
 struct MediaSerializer<TextTrackConfig> {
   static base::Value Serialize(const TextTrackConfig& value) {
-    base::Value result(base::Value::Type::DICTIONARY);
+    base::Value result(base::Value::Type::DICT);
     FIELD_SERIALIZE("kind", value.kind());
     FIELD_SERIALIZE("language", value.language());
     if (value.label().length()) {
@@ -420,7 +420,7 @@
 template <SerializableBufferingStateType T>
 struct MediaSerializer<SerializableBufferingState<T>> {
   static base::Value Serialize(const SerializableBufferingState<T>& value) {
-    base::Value result(base::Value::Type::DICTIONARY);
+    base::Value result(base::Value::Type::DICT);
     FIELD_SERIALIZE("state", value.state);
 
     switch (value.reason) {
@@ -458,7 +458,7 @@
 template <>
 struct MediaSerializer<StatusData> {
   static base::Value Serialize(const StatusData& status) {
-    base::Value result(base::Value::Type::DICTIONARY);
+    base::Value result(base::Value::Type::DICT);
     // TODO: replace code with a stringified version, since
     // this representation will only go to medialog anyway.
     FIELD_SERIALIZE(StatusConstants::kCodeKey, status.code);
@@ -476,7 +476,7 @@
 template <>
 struct MediaSerializer<base::Location> {
   static base::Value Serialize(const base::Location& value) {
-    base::Value result(base::Value::Type::DICTIONARY);
+    base::Value result(base::Value::Type::DICT);
     FIELD_SERIALIZE(StatusConstants::kFileKey,
                     value.file_name() ? value.file_name() : "unknown");
     FIELD_SERIALIZE(StatusConstants::kLineKey, value.line_number());
diff --git a/media/base/pipeline_status.h b/media/base/pipeline_status.h
index ba619694..b9858492 100644
--- a/media/base/pipeline_status.h
+++ b/media/base/pipeline_status.h
@@ -74,7 +74,7 @@
   using Codes = PipelineStatusCodes;
 
   static constexpr StatusGroupType Group() { return "PipelineStatus"; }
-  static constexpr Codes DefaultEnumValue() { return PIPELINE_OK; }
+  static constexpr Codes OkEnumValue() { return PIPELINE_OK; }
 };
 
 using PipelineStatus = TypedStatus<PipelineStatusTraits>;
diff --git a/media/base/status.cc b/media/base/status.cc
index 792c38e..6b84ad79 100644
--- a/media/base/status.cc
+++ b/media/base/status.cc
@@ -25,7 +25,7 @@
     : group(group),
       code(code),
       message(std::move(message)),
-      data(base::Value(base::Value::Type::DICTIONARY)),
+      data(base::Value(base::Value::Type::DICT)),
       packed_root_cause(root_cause) {}
 
 std::unique_ptr<StatusData> StatusData::copy() const {
diff --git a/media/base/status.h b/media/base/status.h
index 00d80bf..4a26fcf 100644
--- a/media/base/status.h
+++ b/media/base/status.h
@@ -106,80 +106,70 @@
   UKMPackedType packed_root_cause = 0;
 };
 
+#define NAME_DETECTOR(detector_name, field)                            \
+  template <typename T>                                                \
+  struct detector_name {                                               \
+    template <typename, typename>                                      \
+    struct field##is_enum {                                            \
+      constexpr static bool value = false;                             \
+    };                                                                 \
+    template <typename V>                                              \
+    struct field##is_enum<V, decltype(V::field)> {                     \
+      constexpr static bool value = true;                              \
+    };                                                                 \
+    template <typename, typename>                                      \
+    struct field##_is_member {                                         \
+      constexpr static bool value = false;                             \
+    };                                                                 \
+    template <typename V>                                              \
+    struct field##_is_member<                                          \
+        V,                                                             \
+        std::enable_if_t<std::is_pointer_v<decltype(&V::field)>, V>> { \
+      constexpr static bool value = true;                              \
+    };                                                                 \
+    constexpr static bool as_enum_value = field##is_enum<T, T>::value; \
+    constexpr static bool as_method = field##_is_member<T, T>::value;  \
+  }
+
+NAME_DETECTOR(HasOkCode, kOk);
+NAME_DETECTOR(HasPackExtraData, PackExtraData);
+NAME_DETECTOR(HasSetDefaultOk, OkEnumValue);
+
+#undef NAME_DETECTOR
+
 // Helper class to allow traits with no default enum.
 template <typename T>
 struct StatusTraitsHelper {
-  // If T defines DefaultEnumValue(), then return it. Otherwise, return an
-  // empty optional.
-  static constexpr absl::optional<typename T::Codes> DefaultEnumValue() {
-    return DefaultEnumValueImpl(0);
+  static constexpr bool has_ok = HasOkCode<typename T::Codes>::as_enum_value;
+  static constexpr bool has_default = HasSetDefaultOk<T>::as_method;
+  static constexpr bool has_pack = HasPackExtraData<T>::as_method;
+
+  // If T defines OkEnumValue(), then return it. Otherwise, return an
+  // T::Codes::kOk if that's defined, or absl::nullopt if its not.
+  static constexpr absl::optional<typename T::Codes> OkEnumValue() {
+    if constexpr (has_default) {
+      return T::OkEnumValue();
+    } else if constexpr (has_ok) {
+      return T::Codes::kOk;
+    } else {
+      return absl::nullopt;
+    }
   }
 
   // If T defined PackExtraData(), then evaluate it. Otherwise, return a default
   // value. |PackExtraData| is an optional method that can operate on the
   // internal status data in order to pack it into a 32-bit entry for UKM.
   static constexpr uint32_t PackExtraData(const StatusData& info) {
-    return DefaultPackExtraData(info, 0);
-  }
-
- private:
-  // Call with an (ignored) int, which will choose the first one if it isn't
-  // removed by SFINAE, else will use the varargs one below.
-  template <typename X = T>
-  static constexpr typename std::enable_if_t<
-      std::is_pointer_v<decltype(&X::DefaultEnumValue)>,
-      absl::optional<typename T::Codes>>
-  DefaultEnumValueImpl(int) {
-    // Make sure the signature is correct, just for sanity.
-    static_assert(
-        std::is_same<decltype(T::DefaultEnumValue), typename T::Codes()>::value,
-        "TypedStatus::Traits::DefaultEnumValue() must return Traits::Codes.");
-    return T::DefaultEnumValue();
-  }
-
-  static constexpr absl::optional<typename T::Codes> DefaultEnumValueImpl(...) {
-    return {};
-  }
-
-  template <typename X = T>
-  static constexpr
-      typename std::enable_if_t<std::is_pointer_v<decltype(&X::PackExtraData)>,
-                                uint32_t>
-      DefaultPackExtraData(const StatusData& info, int) {
-    static_assert(
-        std::is_same_v<decltype(T::PackExtraData(info)), uint32_t>,
-        "Traits::PackExtraData(const StatusData&) must return uint32_t");
-    return T::PackExtraData(info);
-  }
-
-  static constexpr int DefaultPackExtraData(const StatusData&, ...) {
-    return 0;
+    if constexpr (has_pack) {
+      return T::PackExtraData(info);
+    } else {
+      return 0;
+    }
   }
 };
 
-template <typename, typename>
-struct OkStatusDetectorHelper {
-  constexpr static bool has_ok = false;
-};
-
-// Matches <T,T> if T::kOk exists.
-template <typename T>
-struct OkStatusDetectorHelper<T, decltype(T::kOk)> {
-  constexpr static bool has_ok = true;
-};
-
-// Does T have a T::kOk?
-template <typename T>
-constexpr bool DoesHaveOkCode = OkStatusDetectorHelper<T, T>::has_ok;
-
-// Implicitly converts to `kOk` TypedStatus, for any traits.  Also converts to
-// the enum code 'kOk', for any enum that has a 'kOk'.
-struct OkStatusImplicitConstructionHelper {
-  template <typename T>
-  operator T() const {
-    return T::kOk;
-  }
-};
+// Implicitly converts to an ok value for any implementation of TypedStatus.
+struct OkStatusImplicitConstructionHelper {};
 
 // For gtest, so it can print this.  Otherwise, it tries to convert to an
 // integer for printing.  That'd be okay, except our implicit cast matches the
@@ -217,12 +207,12 @@
     // compile-time, so the later clauses don't have to be compilable if the
     // the earlier ones match.  Specifically, it's okay to reference `kOk` even
     // if `T::Codes` doesn't have `kOk`, since we check for it first.
-    if constexpr (!internal::DoesHaveOkCode<typename T::Codes>)
+    if constexpr (!internal::StatusTraitsHelper<T>::has_ok)
       return true;
-    else if constexpr (!internal::StatusTraitsHelper<T>::DefaultEnumValue())
+    else if constexpr (!internal::StatusTraitsHelper<T>::has_default)
       return true;
     else
-      return T::DefaultEnumValue() == T::Codes::kOk;
+      return T::OkEnumValue() == T::Codes::kOk;
   }
   static_assert(verify_default_okayness(),
                 "If kOk is defined, then either no default, or default==kOk");
@@ -244,7 +234,7 @@
   // Special constructor use by OkStatus() to implicitly be cast to any required
   // status type.
   TypedStatus(const internal::OkStatusImplicitConstructionHelper&)
-      : TypedStatus(Codes::kOk) {}
+      : TypedStatus() {}
 
   // Used to implicitly create a TypedStatus from a TypedStatus::Codes value.
   TypedStatus(Codes code,
@@ -321,7 +311,7 @@
               const base::Location& location = base::Location::Current()) {
     // Note that |message| would be dropped when code is the default value,
     // so DCHECK that it is not set.
-    if (code == internal::StatusTraitsHelper<Traits>::DefaultEnumValue()) {
+    if (code == internal::StatusTraitsHelper<Traits>::OkEnumValue()) {
       DCHECK(!!message.empty());
       return;
     }
@@ -340,19 +330,11 @@
     return *this;
   }
 
-  // If `Codes` has a `kOk` value, then check return true if we're `kOk`.  If
-  // there is no `kOk`, or if we're some other value, then return false.
-  bool is_ok() const {
-    if constexpr (internal::DoesHaveOkCode<Codes>) {
-      return code() == Codes::kOk;
-    } else {
-      return false;
-    }
-  }
+  bool is_ok() const { return !data_; }
 
   Codes code() const {
     if (!data_)
-      return *internal::StatusTraitsHelper<Traits>::DefaultEnumValue();
+      return *internal::StatusTraitsHelper<Traits>::OkEnumValue();
     return static_cast<Codes>(data_->code);
   }
 
@@ -464,7 +446,7 @@
 
     // Create an Or type implicitly from a TypedStatus
     Or(TypedStatus<T>&& error) : error_(std::move(error)) {
-      // `error_` must not be `kOk`, if there is such a value.
+      // `error_` must not be ok.
       DCHECK(!error_->is_ok());
     }
 
@@ -502,15 +484,12 @@
 
     bool has_value() const { return value_.has_value(); }
 
-    // If we have an error, verify that `code` matches.  If we have a value,
-    // then this should match if an only if `code` is `kOk`.  If there is no
-    // `kOk`, then it does not match even if we have a value.
     inline bool operator==(typename T::Codes code) const {
-      if constexpr (internal::DoesHaveOkCode<typename T::Codes>) {
-        return code == this->code();
-      } else {
-        return error_ ? code == error_->code() : false;
-      }
+      // We can't use Or<T>::code() directly, since it might not be allowed
+      // due to not having an OK or default code.
+      if (error_)
+        return error_->code() == code;
+      return internal::StatusTraitsHelper<Traits>::OkEnumValue() == code;
     }
 
     inline bool operator!=(typename T::Codes code) const {
@@ -549,15 +528,11 @@
 
     typename T::Codes code() const {
       DCHECK(error_ || value_);
-      // It is invalid to call |code()| on an |Or| with a value that
-      // is specialized in a TypedStatus with no `kOk`.  Instead, you should
-      // explicitly call has_value() / error().code().
-      static_assert(internal::DoesHaveOkCode<typename T::Codes>,
-                    "Cannot call Or::code() if there is no kOk code.");
-      // TODO: should this DCHECK(error_) if we don't have kOk?  It's not as
-      // strong as the static_assert, but maybe we want to allow this for types
-      // that don't have `kOk`.
-      return error_ ? error_->code() : T::Codes::kOk;
+      using helper = internal::StatusTraitsHelper<Traits>;
+      static_assert(
+          helper::OkEnumValue().has_value(),
+          "Cannot call Or::code() without OkEnumValue or kOk defined");
+      return error_ ? error_->code() : *helper::OkEnumValue();
     }
 
     template <typename FnType,
diff --git a/media/base/status.md b/media/base/status.md
index 191ac51..8a3da94f 100644
--- a/media/base/status.md
+++ b/media/base/status.md
@@ -23,7 +23,7 @@
   // then the function OkStatus() can be used to return a status with this
   // code. Statuses created with this default code can not have any data,
   // causes, or a message attached.
-  static constexpr Codes DefaultEnumValue() { return Codes::kSomething; }
+  static constexpr Codes OkEnumValue() { return Codes::kSomething; }
 
   // [OPTIONAL] If |OnCreateFrom| is declared, then TypedStatus<T> can be
   // created with {T::Codes, SomeOtherType} or {T::Codes, string, SomeOtherType}
@@ -100,7 +100,7 @@
 struct MyExampleStatusTraits {
   using Codes = MyExampleEnum;
   static constexpr StatusGroupType Group() { return "MyExampleStatus"; }
-  static constexpr Codes DefaultEnumValue() { return Codes::kDefaultValue; }
+  static constexpr Codes OkEnumValue() { return Codes::kDefaultValue; }
 }
 ```
 
@@ -132,7 +132,7 @@
 ```
 // To create an status with the default OK type, there's a helper function that
 // creates any type you want, so long as it actually has a kOk value or
-|DefaultEnumValue| implementation.
+|OkEnumValue| implementation.
 TypedStatus<MyType> ok = OkStatus();
 
 // A status can be implicitly created from a code
@@ -180,7 +180,7 @@
 OtherType value() &&;
 
 // It is invalid to call `code()` on an `Or<D>` type when
-// has_value() is true and TypedStatusTraits<T>::DefaultEnumValue is nullopt.
+// has_value() is true and TypedStatusTraits<T>::OkEnumValue is nullopt.
 T::Codes code();
 ```
 
@@ -258,7 +258,7 @@
   // here, instead of `using`.
   using Codes = MyExampleEnum;
   static constexpr StatusGroupType Group() { return "MyExampleStatus"; }
-  static constexpr Codes DefaultEnumValue() { return Codes::kDefaultValue; }
+  static constexpr Codes OkEnumValue() { return Codes::kDefaultValue; }
   static uint32_t PackExtraData(const StatusData& info) {
     absl::optional<int> hresult = info.data.GetIntValue("HRESULT");
     return static_cast<uint32_t>(hresult.has_value() ? *hresult : 0);
diff --git a/media/base/status_unittest.cc b/media/base/status_unittest.cc
index 60c21b8..e514047d 100644
--- a/media/base/status_unittest.cc
+++ b/media/base/status_unittest.cc
@@ -38,6 +38,12 @@
   static constexpr StatusGroupType Group() { return "NoDefaultNoOkType"; }
 };
 
+struct CustomDefaultValue {
+  enum class Codes : StatusCodeType { kFoo = 0, kBar = 1, kBaz = 2 };
+  static constexpr StatusGroupType Group() { return "CustomOkCode"; }
+  static constexpr Codes OkEnumValue() { return Codes::kFoo; }
+};
+
 struct ZeroValueOkTypeTraits {
   enum class Codes : StatusCodeType { kOk = 0, kFoo = 1, kBar = 2, kBaz = 3 };
   static constexpr StatusGroupType Group() { return "ZeroValueOkTypeTraits"; }
@@ -495,10 +501,20 @@
                   .is_ok());
 }
 
-TEST_F(StatusTest, CanConvertOkToCode) {
-  // OkStatus() should also be convertible to the enum directly.
-  ZeroValueOkTypeTraits::Codes code = OkStatus();
-  EXPECT_EQ(code, ZeroValueOkTypeTraits::Codes::kOk);
+TEST_F(StatusTest, MustHaveOkOrHelperMethod) {
+  static_assert(internal::StatusTraitsHelper<CustomDefaultValue>::has_default,
+                "WOW");
+
+  auto nook = internal::StatusTraitsHelper<NoOkStatusTypeTraits>::OkEnumValue();
+  ASSERT_FALSE(nook.has_value());
+
+  auto kok = internal::StatusTraitsHelper<ZeroValueOkTypeTraits>::OkEnumValue();
+  ASSERT_TRUE(kok.has_value());
+  ASSERT_EQ(*kok, ZeroValueOkTypeTraits::Codes::kOk);
+
+  auto custom = internal::StatusTraitsHelper<CustomDefaultValue>::OkEnumValue();
+  ASSERT_TRUE(custom.has_value());
+  ASSERT_EQ(*custom, CustomDefaultValue::Codes::kFoo);
 }
 
 TEST_F(StatusTest, OkStatusInitializesToOk) {
diff --git a/media/base/video_frame_metadata.h b/media/base/video_frame_metadata.h
index dc64006c..a67c06916 100644
--- a/media/base/video_frame_metadata.h
+++ b/media/base/video_frame_metadata.h
@@ -195,7 +195,7 @@
   absl::optional<base::TimeDelta> processing_time;
 
   // The RTP timestamp associated with this video frame. Stored as a double
-  // since base::DictionaryValue doesn't have a uint32_t type.
+  // since base::Value::Dict doesn't have a uint32_t type.
   //
   // https://w3c.github.io/webrtc-pc/#dom-rtcrtpcontributingsource-rtptimestamp
   absl::optional<double> rtp_timestamp;
diff --git a/media/cast/encoding/fake_software_video_encoder.cc b/media/cast/encoding/fake_software_video_encoder.cc
index 1b7de3c..dd6bb2d4 100644
--- a/media/cast/encoding/fake_software_video_encoder.cc
+++ b/media/cast/encoding/fake_software_video_encoder.cc
@@ -59,7 +59,7 @@
       ToRtpTimeTicks(video_frame->timestamp(), kVideoFrequency);
   encoded_frame->reference_time = reference_time;
 
-  base::Value values(base::Value::Type::DICTIONARY);
+  base::Value values(base::Value::Type::DICT);
   values.SetBoolKey("key", encoded_frame->dependency == Dependency::kKeyFrame);
   values.SetIntKey("ref", encoded_frame->referenced_frame_id.lower_32_bits());
   values.SetIntKey("id", encoded_frame->frame_id.lower_32_bits());
diff --git a/media/cast/test/simulator.cc b/media/cast/test/simulator.cc
index 24bbb5d5..41f341d 100644
--- a/media/cast/test/simulator.cc
+++ b/media/cast/test/simulator.cc
@@ -178,8 +178,7 @@
 class EncodedVideoFrameTracker final : public RawEventSubscriber {
  public:
   EncodedVideoFrameTracker(FakeMediaSource* media_source)
-      : media_source_(media_source),
-        last_frame_event_type_(UNKNOWN) {}
+      : media_source_(media_source), last_frame_event_type_(UNKNOWN) {}
 
   EncodedVideoFrameTracker(const EncodedVideoFrameTracker&) = delete;
   EncodedVideoFrameTracker& operator=(const EncodedVideoFrameTracker&) = delete;
@@ -231,10 +230,8 @@
                      scoped_refptr<media::VideoFrame> frame) {
   // Write YUV420 format to file.
   std::string header;
-  base::StringAppendF(
-      &header, "FRAME W%d H%d\n",
-      frame->coded_size().width(),
-      frame->coded_size().height());
+  base::StringAppendF(&header, "FRAME W%d H%d\n", frame->coded_size().width(),
+                      frame->coded_size().height());
   AppendToFile(path, header);
   AppendToFile(path,
                base::make_span(frame->data(media::VideoFrame::kYPlane),
@@ -323,10 +320,8 @@
       &receiver_clock, task_runner, task_runner, task_runner);
 
   // Event subscriber. Store at most 1 hour of events.
-  EncodingEventSubscriber audio_event_subscriber(AUDIO_EVENT,
-                                                 100 * 60 * 60);
-  EncodingEventSubscriber video_event_subscriber(VIDEO_EVENT,
-                                                 30 * 60 * 60);
+  EncodingEventSubscriber audio_event_subscriber(AUDIO_EVENT, 100 * 60 * 60);
+  EncodingEventSubscriber video_event_subscriber(VIDEO_EVENT, 30 * 60 * 60);
   sender_env->logger()->Subscribe(&audio_event_subscriber);
   sender_env->logger()->Subscribe(&video_event_subscriber);
 
@@ -337,8 +332,7 @@
           base::Milliseconds(GetIntegerSwitchValue(kTargetDelay, 400));
 
   // Audio receiver config.
-  FrameReceiverConfig audio_receiver_config =
-      GetDefaultAudioReceiverConfig();
+  FrameReceiverConfig audio_receiver_config = GetDefaultAudioReceiverConfig();
   audio_receiver_config.rtp_max_delay_ms =
       audio_sender_config.max_playout_delay.InMilliseconds();
 
@@ -353,8 +347,7 @@
   video_sender_config.max_frame_rate = GetIntegerSwitchValue(kMaxFrameRate, 30);
 
   // Video receiver config.
-  FrameReceiverConfig video_receiver_config =
-      GetDefaultVideoReceiverConfig();
+  FrameReceiverConfig video_receiver_config = GetDefaultVideoReceiverConfig();
   video_receiver_config.rtp_max_delay_ms =
       video_sender_config.max_playout_delay.InMilliseconds();
 
@@ -415,11 +408,8 @@
 
   // Initialize a fake media source and a tracker to encoded video frames.
   const bool quality_test = !metrics_output_path.empty();
-  FakeMediaSource media_source(task_runner,
-                               &testing_clock,
-                               audio_sender_config,
-                               video_sender_config,
-                               quality_test);
+  FakeMediaSource media_source(task_runner, &testing_clock, audio_sender_config,
+                               video_sender_config, quality_test);
   std::unique_ptr<EncodedVideoFrameTracker> video_frame_tracker;
   if (quality_test) {
     video_frame_tracker =
@@ -493,10 +483,10 @@
   media::cast::PacketEventList audio_packet_events, video_packet_events;
   audio_metadata.set_extra_data(extra_data);
   video_metadata.set_extra_data(extra_data);
-  audio_event_subscriber.GetEventsAndReset(
-      &audio_metadata, &audio_frame_events, &audio_packet_events);
-  video_event_subscriber.GetEventsAndReset(
-      &video_metadata, &video_frame_events, &video_packet_events);
+  audio_event_subscriber.GetEventsAndReset(&audio_metadata, &audio_frame_events,
+                                           &audio_packet_events);
+  video_event_subscriber.GetEventsAndReset(&video_metadata, &video_frame_events,
+                                           &video_packet_events);
 
   // Print simulation results.
 
@@ -555,10 +545,10 @@
   LOG(INFO) << "Dropped video frames: " << dropped_video_frames;
   LOG(INFO) << "Late video frames: " << late_video_frames
             << " (average lateness: "
-            << (late_video_frames > 0 ?
-                    static_cast<double>(total_delay_of_late_frames_ms) /
-                        late_video_frames :
-                    0)
+            << (late_video_frames > 0
+                    ? static_cast<double>(total_delay_of_late_frames_ms) /
+                          late_video_frames
+                    : 0)
             << " ms)";
   LOG(INFO) << "Average encoded bitrate (kbps): " << avg_encoded_bitrate;
   LOG(INFO) << "Average target bitrate (kbps): " << avg_target_bitrate;
@@ -577,8 +567,9 @@
   if (quality_test) {
     LOG(INFO) << "Writing quality metrics: " << metrics_output_path.value();
     std::string line;
-    for (size_t i = 0; i < metrics_output.psnr.size() &&
-             i < metrics_output.ssim.size(); ++i) {
+    for (size_t i = 0;
+         i < metrics_output.psnr.size() && i < metrics_output.ssim.size();
+         ++i) {
       base::StringAppendF(&line, "%f %f\n", metrics_output.psnr[i],
                           metrics_output.ssim[i]);
     }
@@ -683,24 +674,24 @@
 
   media::InitializeMediaLibrary();
 
-  base::FilePath source_path = cmd->GetSwitchValuePath(
-      media::cast::kSourcePath);
-  base::FilePath log_output_path = cmd->GetSwitchValuePath(
-      media::cast::kOutputPath);
+  base::FilePath source_path =
+      cmd->GetSwitchValuePath(media::cast::kSourcePath);
+  base::FilePath log_output_path =
+      cmd->GetSwitchValuePath(media::cast::kOutputPath);
   if (log_output_path.empty()) {
     base::GetTempDir(&log_output_path);
     log_output_path = log_output_path.AppendASCII("sim-events.gz");
   }
-  base::FilePath metrics_output_path = cmd->GetSwitchValuePath(
-      media::cast::kMetricsOutputPath);
-  base::FilePath yuv_output_path = cmd->GetSwitchValuePath(
-      media::cast::kYuvOutputPath);
+  base::FilePath metrics_output_path =
+      cmd->GetSwitchValuePath(media::cast::kMetricsOutputPath);
+  base::FilePath yuv_output_path =
+      cmd->GetSwitchValuePath(media::cast::kYuvOutputPath);
   std::string sim_id = cmd->GetSwitchValueASCII(media::cast::kSimulationId);
 
-  NetworkSimulationModel model = media::cast::LoadModel(
-      cmd->GetSwitchValuePath(media::cast::kModelPath));
+  NetworkSimulationModel model =
+      media::cast::LoadModel(cmd->GetSwitchValuePath(media::cast::kModelPath));
 
-  base::Value values(base::Value::Type::DICTIONARY);
+  base::Value values(base::Value::Type::DICT);
   values.SetBoolKey("sim", true);
   values.SetStringKey("sim-id", sim_id);
 
diff --git a/media/cdm/aes_decryptor_unittest.cc b/media/cdm/aes_decryptor_unittest.cc
index 15d48d3..b5db765 100644
--- a/media/cdm/aes_decryptor_unittest.cc
+++ b/media/cdm/aes_decryptor_unittest.cc
@@ -62,7 +62,7 @@
 MATCHER(IsJSONDictionary, "") {
   std::string result(arg.begin(), arg.end());
   absl::optional<base::Value> root = base::JSONReader::Read(result);
-  return (root && root->type() == base::Value::Type::DICTIONARY);
+  return (root && root->type() == base::Value::Type::DICT);
 }
 MATCHER(IsNullTime, "") {
   return arg.is_null();
diff --git a/media/cdm/json_web_key.cc b/media/cdm/json_web_key.cc
index 6a9e76b6..cd5a045 100644
--- a/media/cdm/json_web_key.cc
+++ b/media/cdm/json_web_key.cc
@@ -114,29 +114,30 @@
 
 // Processes a JSON Web Key to extract the key id and key value. Sets |jwk_key|
 // to the id/value pair and returns true on success.
-static bool ConvertJwkToKeyPair(const base::DictionaryValue& jwk,
+static bool ConvertJwkToKeyPair(const base::Value::Dict& jwk,
                                 KeyIdAndKeyPair* jwk_key) {
-  std::string type;
-  if (!jwk.GetString(kKeyTypeTag, &type) || type != kKeyTypeOct) {
-    DVLOG(1) << "Missing or invalid '" << kKeyTypeTag << "': " << type;
+  const base::Value* type = jwk.Find(kKeyTypeTag);
+  if (!type || *type != kKeyTypeOct) {
+    DVLOG(1) << "Missing or invalid '" << kKeyTypeTag
+             << "': " << (type ? type->DebugString() : "");
     return false;
   }
 
   // Get the key id and actual key parameters.
-  std::string encoded_key_id;
-  std::string encoded_key;
-  if (!jwk.GetString(kKeyIdTag, &encoded_key_id)) {
+  const base::Value* encoded_key_id = jwk.Find(kKeyIdTag);
+  const base::Value* encoded_key = jwk.Find(kKeyTag);
+  if (!encoded_key_id) {
     DVLOG(1) << "Missing '" << kKeyIdTag << "' parameter";
     return false;
   }
-  if (!jwk.GetString(kKeyTag, &encoded_key)) {
+  if (!encoded_key) {
     DVLOG(1) << "Missing '" << kKeyTag << "' parameter";
     return false;
   }
 
   // Key ID and key are base64url-encoded strings, so decode them.
   std::string raw_key_id;
-  if (!base::Base64UrlDecode(encoded_key_id,
+  if (!base::Base64UrlDecode(encoded_key_id->GetString(),
                              base::Base64UrlDecodePolicy::DISALLOW_PADDING,
                              &raw_key_id) ||
       raw_key_id.empty()) {
@@ -145,7 +146,7 @@
   }
 
   std::string raw_key;
-  if (!base::Base64UrlDecode(encoded_key,
+  if (!base::Base64UrlDecode(encoded_key->GetString(),
                              base::Base64UrlDecodePolicy::DISALLOW_PADDING,
                              &raw_key) ||
       raw_key.empty()) {
@@ -167,16 +168,15 @@
   }
 
   absl::optional<base::Value> root = base::JSONReader::Read(jwk_set);
-  if (!root || root->type() != base::Value::Type::DICTIONARY) {
+  if (!root || root->type() != base::Value::Type::DICT) {
     DVLOG(1) << "Not valid JSON: " << jwk_set;
     return false;
   }
 
   // Locate the set from the dictionary.
-  base::DictionaryValue* dictionary =
-      static_cast<base::DictionaryValue*>(&root.value());
-  base::ListValue* list_val = NULL;
-  if (!dictionary->GetList(kKeysTag, &list_val)) {
+  base::Value::Dict* dictionary = root.value().GetIfDict();
+  base::Value::List* list_val = dictionary->FindList(kKeysTag);
+  if (!list_val) {
     DVLOG(1) << "Missing '" << kKeysTag
              << "' parameter or not a list in JWK Set";
     return false;
@@ -185,15 +185,15 @@
   // Create a local list of keys, so that |jwk_keys| only gets updated on
   // success.
   KeyIdAndKeyPairs local_keys;
-  for (size_t i = 0; i < list_val->GetListDeprecated().size(); ++i) {
-    base::Value& jwk = list_val->GetListDeprecated()[i];
+  for (size_t i = 0; i < list_val->size(); ++i) {
+    base::Value& jwk = (*list_val)[i];
     if (!jwk.is_dict()) {
       DVLOG(1) << "Unable to access '" << kKeysTag << "'[" << i
                << "] in JWK Set";
       return false;
     }
     KeyIdAndKeyPair key_pair;
-    if (!ConvertJwkToKeyPair(base::Value::AsDictionaryValue(jwk), &key_pair)) {
+    if (!ConvertJwkToKeyPair(jwk.GetDict(), &key_pair)) {
       DVLOG(1) << "Error from '" << kKeysTag << "'[" << i << "]";
       return false;
     }
@@ -202,8 +202,8 @@
 
   // Successfully processed all JWKs in the set. Now check if "type" is
   // specified.
-  base::Value* value = NULL;
-  if (!dictionary->Get(kTypeTag, &value)) {
+  base::Value* value = dictionary->Find(kTypeTag);
+  if (!value) {
     // Not specified, so use the default type.
     *session_type = CdmSessionType::kTemporary;
   } else {
@@ -237,7 +237,7 @@
   }
 
   absl::optional<base::Value> root = base::JSONReader::Read(input);
-  if (!root || root->type() != base::Value::Type::DICTIONARY) {
+  if (!root || root->type() != base::Value::Type::DICT) {
     error_message->assign("Not valid JSON: ");
     error_message->append(ShortenTo64Characters(input));
     return false;
@@ -297,7 +297,7 @@
                           CdmSessionType session_type,
                           std::vector<uint8_t>* license) {
   // Create the license request.
-  base::Value request(base::Value::Type::DICTIONARY);
+  base::Value request(base::Value::Type::DICT);
   base::Value list(base::Value::Type::LIST);
   for (const auto& key_id : key_ids) {
     std::string key_id_string;
@@ -330,7 +330,7 @@
 }
 
 base::Value MakeKeyIdsDictionary(const KeyIdList& key_ids) {
-  base::Value dictionary(base::Value::Type::DICTIONARY);
+  base::Value dictionary(base::Value::Type::DICT);
   base::Value list(base::Value::Type::LIST);
   for (const auto& key_id : key_ids) {
     std::string key_id_string;
@@ -387,7 +387,7 @@
   }
 
   absl::optional<base::Value> root = base::JSONReader::Read(license_as_str);
-  if (!root || root->type() != base::Value::Type::DICTIONARY) {
+  if (!root || root->type() != base::Value::Type::DICT) {
     DVLOG(1) << "Not valid JSON: " << license_as_str;
     return false;
   }
diff --git a/media/filters/mac/audio_toolbox_audio_decoder.cc b/media/filters/mac/audio_toolbox_audio_decoder.cc
index dcafead..57cbef2b 100644
--- a/media/filters/mac/audio_toolbox_audio_decoder.cc
+++ b/media/filters/mac/audio_toolbox_audio_decoder.cc
@@ -163,7 +163,7 @@
   output_cb_ = output_cb;
   BindToCurrentLoop(std::move(init_cb))
       .Run(CreateAACDecoder(config)
-               ? OkStatus()
+               ? DecoderStatus::Codes::kOk
                : DecoderStatus::Codes::kFailedToCreateDecoder);
 }
 
diff --git a/media/formats/mp4/mp4_status.h b/media/formats/mp4/mp4_status.h
index 3d9a8e4..d4d7102 100644
--- a/media/formats/mp4/mp4_status.h
+++ b/media/formats/mp4/mp4_status.h
@@ -31,7 +31,6 @@
     kFailedToLookupVPS = 10,
   };
   static constexpr StatusGroupType Group() { return "MP4Status"; }
-  static constexpr Codes DefaultEnumValue() { return Codes::kOk; }
 };
 
 using MP4Status = TypedStatus<MP4StatusTraits>;
diff --git a/media/gpu/chromeos/chromeos_status.h b/media/gpu/chromeos/chromeos_status.h
index 015c502..5d32a72 100644
--- a/media/gpu/chromeos/chromeos_status.h
+++ b/media/gpu/chromeos/chromeos_status.h
@@ -25,7 +25,6 @@
 struct CroStatusTraits {
   using Codes = ChromeosStatusCode;
   static constexpr StatusGroupType Group() { return "ChromeosStatusCode"; }
-  static constexpr ChromeosStatusCode DefaultEnumValue() { return Codes::kOk; }
 };
 using CroStatus = TypedStatus<CroStatusTraits>;
 
diff --git a/media/gpu/v4l2/v4l2_status.h b/media/gpu/v4l2/v4l2_status.h
index ed625bc0..f8d25b5 100644
--- a/media/gpu/v4l2/v4l2_status.h
+++ b/media/gpu/v4l2/v4l2_status.h
@@ -26,7 +26,6 @@
 struct V4L2StatusTraits {
   using Codes = V4L2StatusCodes;
   static constexpr StatusGroupType Group() { return "V4L2StatusCode"; }
-  static constexpr V4L2StatusCodes DefaultEnumValue() { return Codes::kOk; }
 };
 using V4L2Status = TypedStatus<V4L2StatusTraits>;
 
diff --git a/media/gpu/vaapi/vaapi_status.h b/media/gpu/vaapi/vaapi_status.h
index 2bc7abe..a2ab195 100644
--- a/media/gpu/vaapi/vaapi_status.h
+++ b/media/gpu/vaapi/vaapi_status.h
@@ -30,10 +30,9 @@
 struct VaapiStatusTraits {
   using Codes = VaapiStatusCode;
   static constexpr StatusGroupType Group() { return "VaapiStatusCode"; }
-  static constexpr VaapiStatusCode DefaultEnumValue() { return Codes::kOk; }
 };
 using VaapiStatus = TypedStatus<VaapiStatusTraits>;
 
 }  // namespace media
 
-#endif  // MEDIA_GPU_VAAPI_VAAPI_STATUS_H_
\ No newline at end of file
+#endif  // MEDIA_GPU_VAAPI_VAAPI_STATUS_H_
diff --git a/media/gpu/video_decode_accelerator_perf_tests.cc b/media/gpu/video_decode_accelerator_perf_tests.cc
index d0fcbd9..7db5a6c 100644
--- a/media/gpu/video_decode_accelerator_perf_tests.cc
+++ b/media/gpu/video_decode_accelerator_perf_tests.cc
@@ -258,7 +258,7 @@
   output_folder_path = base::MakeAbsoluteFilePath(output_folder_path);
 
   // Write performance metrics to json.
-  base::Value metrics(base::Value::Type::DICTIONARY);
+  base::Value metrics(base::Value::Type::DICT);
   metrics.SetKey(
       "FramesDecoded",
       base::Value(base::checked_cast<int>(perf_metrics_.frames_decoded_)));
diff --git a/media/gpu/video_encode_accelerator_perf_tests.cc b/media/gpu/video_encode_accelerator_perf_tests.cc
index 2ed2028c..6ed27e1 100644
--- a/media/gpu/video_encode_accelerator_perf_tests.cc
+++ b/media/gpu/video_encode_accelerator_perf_tests.cc
@@ -264,7 +264,7 @@
   output_folder_path = base::MakeAbsoluteFilePath(output_folder_path);
 
   // Write performance metrics to json.
-  base::Value metrics(base::Value::Type::DICTIONARY);
+  base::Value metrics(base::Value::Type::DICT);
   metrics.SetKey("BitstreamsEncoded",
                  base::Value(base::checked_cast<int>(bitstreams_encoded_)));
   metrics.SetKey("TotalDurationMs",
@@ -457,7 +457,7 @@
     base::CreateDirectory(output_folder_path);
   output_folder_path = base::MakeAbsoluteFilePath(output_folder_path);
   // Write quality metrics to json.
-  base::Value metrics(base::Value::Type::DICTIONARY);
+  base::Value metrics(base::Value::Type::DICT);
   if (!svc_text.empty())
     metrics.SetKey("SVC", base::Value(svc_text));
   metrics.SetKey("Bitrate",
diff --git a/media/gpu/windows/d3d11_status.h b/media/gpu/windows/d3d11_status.h
index f2c76496..8e11a5c 100644
--- a/media/gpu/windows/d3d11_status.h
+++ b/media/gpu/windows/d3d11_status.h
@@ -66,9 +66,6 @@
 struct D3D11StatusTraits {
   using Codes = D3D11StatusCode;
   static constexpr StatusGroupType Group() { return "D3D11Status"; }
-  static constexpr D3D11StatusCode DefaultEnumValue() {
-    return D3D11StatusCode::kOk;
-  }
 
   static void OnCreateFrom(TypedStatus<D3D11StatusTraits>* s, HRESULT hresult) {
     // Store it as a string for easy human consumption.
diff --git a/media/midi/midi_manager_alsa.cc b/media/midi/midi_manager_alsa.cc
index 725d5d6..a5fc2c9 100644
--- a/media/midi/midi_manager_alsa.cc
+++ b/media/midi/midi_manager_alsa.cc
@@ -150,11 +150,11 @@
   return vendor;
 }
 
-void SetStringIfNonEmpty(base::DictionaryValue* value,
+void SetStringIfNonEmpty(base::Value::Dict* value,
                          const std::string& path,
                          const std::string& in_value) {
   if (!in_value.empty())
-    value->SetString(path, in_value);
+    value->Set(path, in_value);
 }
 
 }  // namespace
@@ -309,8 +309,7 @@
       vendor_id_(vendor_id),
       model_id_(model_id),
       usb_interface_num_(usb_interface_num),
-      serial_(serial) {
-}
+      serial_(serial) {}
 
 MidiManagerAlsa::MidiPort::Id::Id(const Id&) = default;
 
@@ -347,14 +346,13 @@
       client_name_(client_name),
       port_name_(port_name),
       manufacturer_(manufacturer),
-      version_(version) {
-}
+      version_(version) {}
 
 MidiManagerAlsa::MidiPort::~MidiPort() = default;
 
 // Note: keep synchronized with the MidiPort::Match* methods.
-std::unique_ptr<base::Value> MidiManagerAlsa::MidiPort::Value() const {
-  std::unique_ptr<base::DictionaryValue> value(new base::DictionaryValue);
+std::unique_ptr<base::Value::Dict> MidiManagerAlsa::MidiPort::Value() const {
+  std::unique_ptr<base::Value::Dict> value(new base::Value::Dict);
 
   std::string type;
   switch (type_) {
@@ -365,13 +363,13 @@
       type = "output";
       break;
   }
-  value->SetString("type", type);
+  value->Set("type", type);
   SetStringIfNonEmpty(value.get(), "path", path_);
   SetStringIfNonEmpty(value.get(), "clientName", client_name_);
   SetStringIfNonEmpty(value.get(), "portName", port_name_);
-  value->SetInteger("clientId", client_id_);
-  value->SetInteger("portId", port_id_);
-  value->SetInteger("midiDevice", midi_device_);
+  value->Set("clientId", client_id_);
+  value->Set("portId", port_id_);
+  value->Set("midiDevice", midi_device_);
 
   // Flatten id fields.
   SetStringIfNonEmpty(value.get(), "bus", id_.bus());
@@ -380,7 +378,7 @@
   SetStringIfNonEmpty(value.get(), "usbInterfaceNum", id_.usb_interface_num());
   SetStringIfNonEmpty(value.get(), "serial", id_.serial());
 
-  return std::move(value);
+  return value;
 }
 
 std::string MidiManagerAlsa::MidiPort::JSONValue() const {
@@ -707,15 +705,13 @@
     const std::string& name,
     MidiManagerAlsa::AlsaSeqState::PortDirection direction,
     bool midi)
-    : name_(name), direction_(direction), midi_(midi) {
-}
+    : name_(name), direction_(direction), midi_(midi) {}
 
 MidiManagerAlsa::AlsaSeqState::Port::~Port() = default;
 
 MidiManagerAlsa::AlsaSeqState::Client::Client(const std::string& name,
                                               snd_seq_client_type_t type)
-    : name_(name), type_(type) {
-}
+    : name_(name), type_(type) {}
 
 MidiManagerAlsa::AlsaSeqState::Client::~Client() = default;
 
@@ -764,8 +760,7 @@
           vendor_id_,
           device::UdevDeviceGetPropertyValue(dev, kUdevIdVendorFromDatabase),
           name,
-          longname)) {
-}
+          longname)) {}
 
 MidiManagerAlsa::AlsaCard::~AlsaCard() = default;
 
diff --git a/media/midi/midi_manager_alsa.h b/media/midi/midi_manager_alsa.h
index 5606300..8ccb595f 100644
--- a/media/midi/midi_manager_alsa.h
+++ b/media/midi/midi_manager_alsa.h
@@ -102,7 +102,7 @@
     ~MidiPort();
 
     // Gets a Value representation of this object, suitable for serialization.
-    std::unique_ptr<base::Value> Value() const;
+    std::unique_ptr<base::Value::Dict> Value() const;
 
     // Gets a string version of Value in JSON format.
     std::string JSONValue() const;
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index b3209b2..1b57e52 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -3670,6 +3670,1949 @@
       }
     ]
   },
+  "Linux MSan Focal": {
+    "gtest_tests": [
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "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/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "accessibility_unittests",
+        "test_id_prefix": "ninja://ui/accessibility:accessibility_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "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
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "app_shell_unittests",
+        "test_id_prefix": "ninja://extensions/shell:app_shell_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "aura_unittests",
+        "test_id_prefix": "ninja://ui/aura:aura_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "base_unittests",
+        "test_id_prefix": "ninja://base:base_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "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/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "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/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "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/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "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/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "webkit_unit_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "blink_unittests",
+        "test_id_prefix": "ninja://third_party/blink/renderer/controller:blink_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "boringssl_crypto_tests",
+        "test_id_prefix": "ninja://third_party/boringssl:boringssl_crypto_tests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "boringssl_ssl_tests",
+        "test_id_prefix": "ninja://third_party/boringssl:boringssl_ssl_tests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "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*",
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "capture_unittests",
+        "test_id_prefix": "ninja://media/capture:capture_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "cast_unittests",
+        "test_id_prefix": "ninja://media/cast:cast_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "cc_unittests",
+        "test_id_prefix": "ninja://cc:cc_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "chrome_app_unittests",
+        "test_id_prefix": "ninja://chrome/test:chrome_app_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "chromedriver_unittests",
+        "test_id_prefix": "ninja://chrome/test/chromedriver:chromedriver_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "color_unittests",
+        "test_id_prefix": "ninja://ui/color:color_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "components_browsertests",
+        "test_id_prefix": "ninja://components:components_browsertests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "components_unittests",
+        "test_id_prefix": "ninja://components:components_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "compositor_unittests",
+        "test_id_prefix": "ninja://ui/compositor:compositor_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 8
+        },
+        "test": "content_browsertests",
+        "test_id_prefix": "ninja://content/test:content_browsertests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "content_unittests",
+        "test_id_prefix": "ninja://content/test:content_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "crashpad_tests",
+        "test_id_prefix": "ninja://third_party/crashpad/crashpad:crashpad_tests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "cronet_tests",
+        "test_id_prefix": "ninja://components/cronet:cronet_tests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "cronet_unittests",
+        "test_id_prefix": "ninja://components/cronet:cronet_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "crypto_unittests",
+        "test_id_prefix": "ninja://crypto:crypto_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "dbus_unittests",
+        "test_id_prefix": "ninja://dbus:dbus_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "device_unittests",
+        "test_id_prefix": "ninja://device:device_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "display_unittests",
+        "test_id_prefix": "ninja://ui/display:display_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "events_unittests",
+        "test_id_prefix": "ninja://ui/events:events_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "extensions_browsertests",
+        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "extensions_unittests",
+        "test_id_prefix": "ninja://extensions:extensions_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "filesystem_service_unittests",
+        "test_id_prefix": "ninja://components/services/filesystem:filesystem_service_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "gcm_unit_tests",
+        "test_id_prefix": "ninja://google_apis/gcm:gcm_unit_tests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "gfx_unittests",
+        "test_id_prefix": "ninja://ui/gfx:gfx_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "gin_unittests",
+        "test_id_prefix": "ninja://gin:gin_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "google_apis_unittests",
+        "test_id_prefix": "ninja://google_apis:google_apis_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "gpu_unittests",
+        "test_id_prefix": "ninja://gpu:gpu_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "gwp_asan_unittests",
+        "test_id_prefix": "ninja://components/gwp_asan:gwp_asan_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "headless_browsertests",
+        "test_id_prefix": "ninja://headless:headless_browsertests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "headless_unittests",
+        "test_id_prefix": "ninja://headless:headless_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "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/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "ipc_tests",
+        "test_id_prefix": "ninja://ipc:ipc_tests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "latency_unittests",
+        "test_id_prefix": "ninja://ui/latency:latency_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "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/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "liburlpattern_unittests",
+        "test_id_prefix": "ninja://third_party/liburlpattern:liburlpattern_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "media_unittests",
+        "test_id_prefix": "ninja://media:media_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "message_center_unittests",
+        "test_id_prefix": "ninja://ui/message_center:message_center_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "midi_unittests",
+        "test_id_prefix": "ninja://media/midi:midi_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "mojo_core_unittests",
+        "test_id_prefix": "ninja://mojo/core:mojo_core_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "mojo_unittests",
+        "test_id_prefix": "ninja://mojo:mojo_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "nacl_loader_unittests",
+        "test_id_prefix": "ninja://components/nacl/loader:nacl_loader_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "native_theme_unittests",
+        "test_id_prefix": "ninja://ui/native_theme:native_theme_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "net_unittests",
+        "test_id_prefix": "ninja://net:net_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "openscreen_unittests",
+        "test_id_prefix": "ninja://chrome/browser/media/router:openscreen_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "ozone_x11_unittests",
+        "test_id_prefix": "ninja://ui/ozone:ozone_x11_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "pdf_unittests",
+        "test_id_prefix": "ninja://pdf:pdf_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "perfetto_unittests",
+        "test_id_prefix": "ninja://third_party/perfetto:perfetto_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "ppapi_unittests",
+        "test_id_prefix": "ninja://ppapi:ppapi_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "printing_unittests",
+        "test_id_prefix": "ninja://printing:printing_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "remoting_unittests",
+        "test_id_prefix": "ninja://remoting:remoting_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "sandbox_linux_unittests",
+        "test_id_prefix": "ninja://sandbox/linux:sandbox_linux_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "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/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "shell_dialogs_unittests",
+        "test_id_prefix": "ninja://ui/shell_dialogs:shell_dialogs_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "skia_unittests",
+        "test_id_prefix": "ninja://skia:skia_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "snapshot_unittests",
+        "test_id_prefix": "ninja://ui/snapshot:snapshot_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "sql_unittests",
+        "test_id_prefix": "ninja://sql:sql_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "storage_unittests",
+        "test_id_prefix": "ninja://storage:storage_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "sync_integration_tests",
+        "test_id_prefix": "ninja://chrome/test:sync_integration_tests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "ui_base_unittests",
+        "test_id_prefix": "ninja://ui/base:ui_base_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "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/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "unit_tests",
+        "test_id_prefix": "ninja://chrome/test:unit_tests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "url_unittests",
+        "test_id_prefix": "ninja://url:url_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "views_unittests",
+        "test_id_prefix": "ninja://ui/views:views_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "viz_unittests",
+        "test_id_prefix": "ninja://components/viz:viz_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "vr_common_unittests",
+        "test_id_prefix": "ninja://chrome/browser/vr:vr_common_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "vr_pixeltests",
+        "test_id_prefix": "ninja://chrome/browser/vr:vr_pixeltests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "wm_unittests",
+        "test_id_prefix": "ninja://ui/wm:wm_unittests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "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/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "xr_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "xr_browser_tests",
+        "test_id_prefix": "ninja://chrome/test:xr_browser_tests/"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-20.04"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 7200,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "zlib_unittests",
+        "test_id_prefix": "ninja://third_party/zlib:zlib_unittests/"
+      }
+    ]
+  },
   "Linux Viz": {
     "additional_compile_targets": [
       "all"
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index eec7875..b107ea4 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -7123,7 +7123,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7144,7 +7144,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7165,7 +7165,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7187,7 +7187,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7208,7 +7208,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7229,7 +7229,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7250,7 +7250,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7271,7 +7271,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7292,7 +7292,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7313,7 +7313,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7335,7 +7335,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7356,7 +7356,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7377,7 +7377,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7398,7 +7398,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -7421,7 +7421,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7442,7 +7442,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7463,7 +7463,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7484,7 +7484,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7505,7 +7505,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7526,7 +7526,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7547,7 +7547,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7568,7 +7568,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7589,7 +7589,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7610,7 +7610,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -7632,7 +7632,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7653,7 +7653,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7674,7 +7674,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7695,7 +7695,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7716,7 +7716,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7737,7 +7737,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7758,7 +7758,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7779,7 +7779,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7800,7 +7800,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7821,7 +7821,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7842,7 +7842,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7863,7 +7863,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7884,7 +7884,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7905,7 +7905,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7926,7 +7926,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7947,7 +7947,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7968,7 +7968,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7989,7 +7989,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8010,7 +8010,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8031,7 +8031,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8052,7 +8052,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -8095,7 +8095,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8116,7 +8116,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8137,7 +8137,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8158,7 +8158,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8179,7 +8179,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8200,7 +8200,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8221,7 +8221,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8242,7 +8242,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8263,7 +8263,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8284,7 +8284,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8305,7 +8305,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8326,7 +8326,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8347,7 +8347,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8368,7 +8368,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8389,7 +8389,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8410,7 +8410,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8431,7 +8431,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8452,7 +8452,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8473,7 +8473,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8494,7 +8494,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8515,7 +8515,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8536,7 +8536,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8557,7 +8557,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8578,7 +8578,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8599,7 +8599,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8620,7 +8620,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8641,7 +8641,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8662,7 +8662,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8683,7 +8683,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8704,7 +8704,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8725,7 +8725,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8746,7 +8746,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8767,7 +8767,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8788,7 +8788,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8809,7 +8809,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8830,7 +8830,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8852,7 +8852,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8873,7 +8873,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-20.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index c240bee..ba22f3f 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -2126,6 +2126,7 @@
       # Can't run on MSAN because gl_tests uses the hardware driver,
       # which isn't instrumented.
       'Linux MSan Tests',
+      'Linux MSan Focal',
     ],
     'modifications': {
       # TODO(kbr): figure out a better way to specify blocks of
@@ -2251,6 +2252,7 @@
       # Can't run on MSAN because gl_unittests uses the hardware driver,
       # which isn't instrumented.
       'Linux MSan Tests',
+      'Linux MSan Focal',
     ],
     'modifications': {
       'Win10 FYI x64 Exp Release (Intel HD 630)': {
@@ -3190,6 +3192,7 @@
       'Linux ChromiumOS MSan Tests',  # https://crbug.com/831676
       'Linux ChromiumOS MSan Focal',
       'Linux MSan Tests',  # https://crbug.com/831676
+      'Linux MSan Focal',  # https://crbug.com/831676
     ],
     'replacements': {
       # TODO(crbug.com/1078982): Remove once the test is fixed on 10.15.4.
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index a6c216de..834a8c2 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -2724,6 +2724,22 @@
           '--test-launcher-print-test-stdio=always',
         ],
       },
+      'Linux MSan Focal': {
+        'mixins': [
+          'linux-focal',
+          'x86-64',
+        ],
+        'swarming': {
+          'expiration': 10800,
+          'hard_timeout': 7200,
+        },
+        'test_suites': {
+          'gtest_tests': 'chromium_linux_and_gl_gtests',
+        },
+        'args': [
+          '--test-launcher-print-test-stdio=always',
+        ],
+      },
       'Linux Viz': {
         'mixins': [
           'linux-bionic',
@@ -5024,7 +5040,7 @@
       },
       'Linux MSan Tests': {
         'mixins': [
-          'linux-focal',
+          'linux-xenial',
           'x86-64',
         ],
         'test_suites': {
diff --git a/third_party/blink/renderer/core/frame/history_user_activation_state.h b/third_party/blink/renderer/core/frame/history_user_activation_state.h
index 414e4cd..4d357ad 100644
--- a/third_party/blink/renderer/core/frame/history_user_activation_state.h
+++ b/third_party/blink/renderer/core/frame/history_user_activation_state.h
@@ -8,21 +8,21 @@
 namespace blink {
 
 // Used to decide whether to allow web pages to prevent history traversal, and
-// to ensure they do not doing so twice in a row without an intervening user
+// to ensure they are not doing so twice in a row without an intervening user
 // activation.
 // This is used for a similar purpose to the history manipulation intervention
 // (src/docs/history_manipulation_intervention.md), but at a different
 // point in time. The intervention is used to make history entries skippable
-// when they are created, while HistoryUserActivationState is used to determine
-// whether the web page is allowed to block when traversing to an already
-// created history entry.
+// when they are navigated away from e.g. by creating a new entry, while
+// HistoryUserActivationState is used to determine whether the web page is
+// allowed to block when traversing to an already created history entry.
 // HistoryUserActivationState records activation at the same time as
 // UserActivationState, but consume behaves differently.
-// ConsumeHistoryUserActivation() only affects the target window, not
-// descendants, and HistoryUserActivationState consume is only triggered by
-// specific APIs that block history traversals. Therefore there will be cases
-// where HasHistoryUserActivation() is true but UserActivationState::IsActive()
-// is false, and vice versa.
+// `HistoryUserActivationState::Consume()` is only called on the target window,
+// not descendants, and is only triggered by specific APIs that block history
+// traversals. Therefore there will be cases where
+// `HistoryUserActivationState::IsActive()` is true but
+// `UserActivationState::IsActive()` is false, and vice versa.
 class HistoryUserActivationState {
  public:
   HistoryUserActivationState() = default;
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 a2b401d..873db356 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.cc
+++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -1081,7 +1081,9 @@
     int64_t display_id =
         frame ? frame->GetChromeClient().GetScreenInfo(*frame).display_id
               : Screen::kInvalidDisplayId;
-    screen_ = MakeGarbageCollected<Screen>(this, display_id);
+    screen_ = MakeGarbageCollected<Screen>(
+        this, display_id, /*use_size_override=*/
+        !RuntimeEnabledFeatures::FullscreenScreenSizeMatchesDisplayEnabled());
   }
   return screen_.Get();
 }
diff --git a/third_party/blink/renderer/core/frame/screen.cc b/third_party/blink/renderer/core/frame/screen.cc
index 1288aa5..4d2a750 100644
--- a/third_party/blink/renderer/core/frame/screen.cc
+++ b/third_party/blink/renderer/core/frame/screen.cc
@@ -44,28 +44,50 @@
 
 }  // namespace
 
-Screen::Screen(LocalDOMWindow* window, int64_t display_id)
-    : ExecutionContextClient(window), display_id_(display_id) {}
+Screen::Screen(LocalDOMWindow* window,
+               int64_t display_id,
+               bool use_size_override)
+    : ExecutionContextClient(window),
+      display_id_(display_id),
+      use_size_override_(use_size_override) {}
 
 // static
 bool Screen::AreWebExposedScreenPropertiesEqual(
     const display::ScreenInfo& prev,
-    const display::ScreenInfo& current) {
-  // height() / width() use rect / device_scale_factor
-  if (prev.rect.size() != current.rect.size())
+    const display::ScreenInfo& current,
+    bool use_size_override) {
+  // height() and width() use rect.size() or size_override
+  gfx::Size prev_size = prev.rect.size();
+  if (prev.size_override && use_size_override)
+    prev_size = *prev.size_override;
+  gfx::Size current_size = current.rect.size();
+  if (current.size_override && use_size_override)
+    current_size = *current.size_override;
+  if (prev_size != current_size)
     return false;
 
+  // height() and width() use device_scale_factor
   // Note: comparing device_scale_factor is a bit of a lie as Screen only uses
   // this with the PhysicalPixelsQuirk (see width() / height() below).  However,
   // this value likely changes rarely and should not throw many false positives.
   if (prev.device_scale_factor != current.device_scale_factor)
     return false;
 
-  // availLeft() / availTop() / availHeight() / availWidth() use available_rect
-  if (prev.available_rect != current.available_rect)
+  // availLeft() and availTop() use available_rect.origin()
+  if (prev.available_rect.origin() != current.available_rect.origin())
     return false;
 
-  // colorDepth() / pixelDepth() use depth
+  // availHeight() and availWidth() use available_rect.size() or size_override
+  gfx::Size prev_avail_size = prev.available_rect.size();
+  if (prev.size_override && use_size_override)
+    prev_avail_size = *prev.size_override;
+  gfx::Size current_avail_size = current.available_rect.size();
+  if (current.size_override && use_size_override)
+    current_avail_size = *current.size_override;
+  if (prev_avail_size != current_avail_size)
+    return false;
+
+  // colorDepth() and pixelDepth() use depth
   if (prev.depth != current.depth)
     return false;
 
@@ -93,25 +115,13 @@
 int Screen::height() const {
   if (!DomWindow())
     return 0;
-  LocalFrame* frame = DomWindow()->GetFrame();
-  const display::ScreenInfo& screen_info = GetScreenInfo();
-  if (frame->GetSettings()->GetReportScreenSizeInPhysicalPixelsQuirk()) {
-    return base::ClampRound(screen_info.rect.height() *
-                            screen_info.device_scale_factor);
-  }
-  return screen_info.rect.height();
+  return GetRect(/*available=*/false).height();
 }
 
 int Screen::width() const {
   if (!DomWindow())
     return 0;
-  LocalFrame* frame = DomWindow()->GetFrame();
-  const display::ScreenInfo& screen_info = GetScreenInfo();
-  if (frame->GetSettings()->GetReportScreenSizeInPhysicalPixelsQuirk()) {
-    return base::ClampRound(screen_info.rect.width() *
-                            screen_info.device_scale_factor);
-  }
-  return screen_info.rect.width();
+  return GetRect(/*available=*/false).width();
 }
 
 unsigned Screen::colorDepth() const {
@@ -127,49 +137,25 @@
 int Screen::availLeft() const {
   if (!DomWindow())
     return 0;
-  LocalFrame* frame = DomWindow()->GetFrame();
-  const display::ScreenInfo& screen_info = GetScreenInfo();
-  if (frame->GetSettings()->GetReportScreenSizeInPhysicalPixelsQuirk()) {
-    return base::ClampRound(screen_info.available_rect.x() *
-                            screen_info.device_scale_factor);
-  }
-  return screen_info.available_rect.x();
+  return GetRect(/*available=*/true).x();
 }
 
 int Screen::availTop() const {
   if (!DomWindow())
     return 0;
-  LocalFrame* frame = DomWindow()->GetFrame();
-  const display::ScreenInfo& screen_info = GetScreenInfo();
-  if (frame->GetSettings()->GetReportScreenSizeInPhysicalPixelsQuirk()) {
-    return base::ClampRound(screen_info.available_rect.y() *
-                            screen_info.device_scale_factor);
-  }
-  return screen_info.available_rect.y();
+  return GetRect(/*available=*/true).y();
 }
 
 int Screen::availHeight() const {
   if (!DomWindow())
     return 0;
-  LocalFrame* frame = DomWindow()->GetFrame();
-  const display::ScreenInfo& screen_info = GetScreenInfo();
-  if (frame->GetSettings()->GetReportScreenSizeInPhysicalPixelsQuirk()) {
-    return base::ClampRound(screen_info.available_rect.height() *
-                            screen_info.device_scale_factor);
-  }
-  return screen_info.available_rect.height();
+  return GetRect(/*available=*/true).height();
 }
 
 int Screen::availWidth() const {
   if (!DomWindow())
     return 0;
-  LocalFrame* frame = DomWindow()->GetFrame();
-  const display::ScreenInfo& screen_info = GetScreenInfo();
-  if (frame->GetSettings()->GetReportScreenSizeInPhysicalPixelsQuirk()) {
-    return base::ClampRound(screen_info.available_rect.width() *
-                            screen_info.device_scale_factor);
-  }
-  return screen_info.available_rect.width();
+  return GetRect(/*available=*/true).width();
 }
 
 void Screen::Trace(Visitor* visitor) const {
@@ -198,6 +184,19 @@
   return GetScreenInfo().is_extended;
 }
 
+gfx::Rect Screen::GetRect(bool available) const {
+  if (!DomWindow())
+    return gfx::Rect();
+  LocalFrame* frame = DomWindow()->GetFrame();
+  const display::ScreenInfo& screen_info = GetScreenInfo();
+  gfx::Rect rect = available ? screen_info.available_rect : screen_info.rect;
+  if (screen_info.size_override && use_size_override_)
+    rect.set_size(*screen_info.size_override);
+  if (frame->GetSettings()->GetReportScreenSizeInPhysicalPixelsQuirk())
+    return gfx::ScaleToRoundedRect(rect, screen_info.device_scale_factor);
+  return rect;
+}
+
 const display::ScreenInfo& Screen::GetScreenInfo() const {
   DCHECK(DomWindow());
   LocalFrame* frame = DomWindow()->GetFrame();
diff --git a/third_party/blink/renderer/core/frame/screen.h b/third_party/blink/renderer/core/frame/screen.h
index a4cd610..260483f 100644
--- a/third_party/blink/renderer/core/frame/screen.h
+++ b/third_party/blink/renderer/core/frame/screen.h
@@ -35,6 +35,7 @@
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/supplementable.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
+#include "ui/gfx/geometry/rect.h"
 
 namespace display {
 struct ScreenInfo;
@@ -50,11 +51,12 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  explicit Screen(LocalDOMWindow*, int64_t display_id);
+  Screen(LocalDOMWindow*, int64_t display_id, bool use_size_override);
 
   static bool AreWebExposedScreenPropertiesEqual(
       const display::ScreenInfo& prev,
-      const display::ScreenInfo& current);
+      const display::ScreenInfo& current,
+      bool use_size_override);
 
   int height() const;
   int width() const;
@@ -84,8 +86,19 @@
   void UpdateDisplayId(int64_t display_id) { display_id_ = display_id; }
 
  protected:
+  // Helpers to access screen information.
+  gfx::Rect GetRect(bool available) const;
   const display::ScreenInfo& GetScreenInfo() const;
+
+  // The internal id of the underlying display, to support multi-screen devices.
   int64_t display_id_;
+
+  // A flag controlling whether to respect ScreenInfo's size override, which is
+  // set to viewport dimensions while the frame is fullscreen, as a speculative
+  // site compatibility measure, because web authors may assume that screen
+  // dimensions match window.innerWidth/innerHeight while a page is fullscreen,
+  // but that is not always true. crbug.com/1367416
+  const bool use_size_override_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
index 24817c6..fa798b2 100644
--- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
@@ -4158,7 +4158,8 @@
   const bool window_screen_has_changed =
       !Screen::AreWebExposedScreenPropertiesEqual(
           previous_original_screen_infos.current(),
-          original_screen_infos.current());
+          original_screen_infos.current(),
+          !RuntimeEnabledFeatures::FullscreenScreenSizeMatchesDisplayEnabled());
 
   // Update Screens interface data before firing any events. The API is designed
   // to offer synchronous access to the most up-to-date cached screen
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc
index 7a7d250..3357e07 100644
--- a/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -2720,8 +2720,10 @@
     PaintingLayer()->SetNeedsCompositingInputsUpdate();
   }
 
-  if (diff.NeedsVisualRectUpdate())
-    SetShouldCheckForPaintInvalidation();
+  if (!IsLayoutNGObject() && old_style &&
+      old_style->Visibility() != style_->Visibility()) {
+    SetShouldDoFullPaintInvalidation();
+  }
 
   // Text nodes share style with their parents but the paint properties don't
   // apply to them, hence the !isText() check. If property nodes are added or
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
index 48dd4aa..0b39331e 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
@@ -45,16 +45,6 @@
 
 namespace blink {
 
-namespace {
-
-inline void ClearNeedsLayoutIfNeeded(LayoutObject* layout_object) {
-  DCHECK(layout_object);
-  if (layout_object->NeedsLayout())
-    layout_object->ClearNeedsLayout();
-}
-
-}  // namespace
-
 NGInlineLayoutAlgorithm::NGInlineLayoutAlgorithm(
     NGInlineNode inline_node,
     const NGConstraintSpace& space,
@@ -585,7 +575,8 @@
 
   DCHECK(item.GetLayoutObject());
   DCHECK(item.GetLayoutObject()->IsText());
-  ClearNeedsLayoutIfNeeded(item.GetLayoutObject());
+  if (!NGDisableSideEffectsScope::IsDisabled())
+    item.GetLayoutObject()->ClearNeedsLayoutWithFullPaintInvalidation();
 
   if (UNLIKELY(quirks_mode_ && !box->HasMetrics()))
     box->EnsureTextMetrics(*item.Style(), *box->font, baseline_type_);
diff --git a/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc b/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
index ee694953..1c822f40 100644
--- a/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
@@ -1031,6 +1031,36 @@
   GetDocument().View()->SetTracksRasterInvalidations(false);
 }
 
+TEST_P(PaintAndRasterInvalidationTest, VisibilityChange) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      #target { width: 100px; height: 100px; background: blue; }
+    </style>
+    <div id="target"></div>
+  )HTML");
+
+  auto* target = GetDocument().getElementById("target");
+  const DisplayItemClient* client = target->GetLayoutObject();
+
+  GetDocument().View()->SetTracksRasterInvalidations(true);
+  target->setAttribute(html_names::kStyleAttr, "visibility: hidden");
+  UpdateAllLifecyclePhasesForTest();
+  EXPECT_THAT(GetRasterInvalidationTracking()->Invalidations(),
+              UnorderedElementsAre(RasterInvalidationInfo{
+                  client->Id(), client->DebugName(), gfx::Rect(8, 8, 100, 100),
+                  PaintInvalidationReason::kDisappeared}));
+  GetDocument().View()->SetTracksRasterInvalidations(false);
+
+  GetDocument().View()->SetTracksRasterInvalidations(true);
+  target->setAttribute(html_names::kStyleAttr, "visibility: visible");
+  UpdateAllLifecyclePhasesForTest();
+  EXPECT_THAT(GetRasterInvalidationTracking()->Invalidations(),
+              UnorderedElementsAre(RasterInvalidationInfo{
+                  client->Id(), client->DebugName(), gfx::Rect(8, 8, 100, 100),
+                  PaintInvalidationReason::kAppeared}));
+  GetDocument().View()->SetTracksRasterInvalidations(false);
+}
+
 class PaintInvalidatorTestClient : public RenderingTestChromeClient {
  public:
   void InvalidateContainer() override { invalidation_recorded_ = true; }
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc
index 7424063f..1c7929d 100644
--- a/third_party/blink/renderer/core/style/computed_style.cc
+++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -729,9 +729,6 @@
 
   AdjustDiffForNeedsPaintInvalidation(other, diff, document);
 
-  if (DiffNeedsVisualRectUpdate(other))
-    diff.SetNeedsVisualRectUpdate();
-
   UpdatePropertySpecificDifferences(other, diff);
 
   // The following condition needs to be at last, because it may depend on
@@ -1015,15 +1012,6 @@
   return true;
 }
 
-// This doesn't include conditions needing layout or overflow recomputation
-// which implies visual rect update.
-bool ComputedStyle::DiffNeedsVisualRectUpdate(
-    const ComputedStyle& other) const {
-  // Visual rect is empty if visibility is hidden. Also need to update visual
-  // rect of the resizer.
-  return ComputedStyleBase::DiffNeedsVisualRectUpdate(*this, other);
-}
-
 bool ComputedStyle::PotentialCompositingReasonsFor3DTransformChanged(
     const ComputedStyle& other) const {
   // Compositing reasons for 3D transforms depend on the LayoutObject type (see:
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h
index 2554e5b..3072a31f 100644
--- a/third_party/blink/renderer/core/style/computed_style.h
+++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -2436,7 +2436,6 @@
   bool DiffNeedsPaintInvalidationForPaintImage(const StyleImage&,
                                                const ComputedStyle& other,
                                                const Document&) const;
-  bool DiffNeedsVisualRectUpdate(const ComputedStyle& other) const;
   CORE_EXPORT void UpdatePropertySpecificDifferences(const ComputedStyle& other,
                                                      StyleDifference&) const;
   bool PotentialCompositingReasonsFor3DTransformChanged(
diff --git a/third_party/blink/renderer/core/style/computed_style_diff_functions.json5 b/third_party/blink/renderer/core/style/computed_style_diff_functions.json5
index 072d0ab..2448648 100644
--- a/third_party/blink/renderer/core/style/computed_style_diff_functions.json5
+++ b/third_party/blink/renderer/core/style/computed_style_diff_functions.json5
@@ -335,25 +335,6 @@
         ]
     },
     {
-        name: "DiffNeedsVisualRectUpdate",
-        methods_to_diff: [
-          {
-            method: "Visibility()",
-            field_dependencies: ["visibility"]
-          },
-          {
-            method: "Resize()",
-            field_dependencies: ["resize"]
-          },
-        ],
-        predicates_to_test: [
-          {
-            predicate: "a.ClipPathDataEquivalent(b)",
-            field_dependencies: ["clip-path"]
-          }
-        ]
-    },
-    {
         name: "UpdatePropertySpecificDifferencesZIndex",
         fields_to_diff: ["z-index"],
         methods_to_diff: [
diff --git a/third_party/blink/renderer/core/style/style_difference.cc b/third_party/blink/renderer/core/style/style_difference.cc
index 8cfe294..62d4220 100644
--- a/third_party/blink/renderer/core/style/style_difference.cc
+++ b/third_party/blink/renderer/core/style/style_difference.cc
@@ -29,7 +29,6 @@
   out << ", reshape=" << diff.needs_reshape_;
   out << ", paintInvalidation=" << diff.needs_paint_invalidation_;
   out << ", recomputeVisualOverflow=" << diff.recompute_visual_overflow_;
-  out << ", visualRectUpdate=" << diff.visual_rect_update_;
 
   out << ", propertySpecificDifferences=";
   int diff_count = 0;
diff --git a/third_party/blink/renderer/core/style/style_difference.h b/third_party/blink/renderer/core/style/style_difference.h
index 08510d2..4558afe 100644
--- a/third_party/blink/renderer/core/style/style_difference.h
+++ b/third_party/blink/renderer/core/style/style_difference.h
@@ -43,7 +43,6 @@
         layout_type_(kNoLayout),
         needs_reshape_(false),
         recompute_visual_overflow_(false),
-        visual_rect_update_(false),
         property_specific_differences_(0),
         scroll_anchor_disabling_property_changed_(false),
         compositing_reasons_changed_(false),
@@ -54,7 +53,6 @@
     layout_type_ = std::max(layout_type_, other.layout_type_);
     needs_reshape_ |= other.needs_reshape_;
     recompute_visual_overflow_ |= other.recompute_visual_overflow_;
-    visual_rect_update_ |= other.visual_rect_update_;
     property_specific_differences_ |= other.property_specific_differences_;
     scroll_anchor_disabling_property_changed_ |=
         other.scroll_anchor_disabling_property_changed_;
@@ -66,7 +64,7 @@
   bool HasDifference() const {
     return needs_paint_invalidation_ || layout_type_ || needs_reshape_ ||
            property_specific_differences_ || recompute_visual_overflow_ ||
-           visual_rect_update_ || scroll_anchor_disabling_property_changed_ ||
+           scroll_anchor_disabling_property_changed_ ||
            compositing_reasons_changed_ || compositable_paint_effect_changed_;
   }
 
@@ -103,9 +101,6 @@
   }
   void SetNeedsRecomputeVisualOverflow() { recompute_visual_overflow_ = true; }
 
-  bool NeedsVisualRectUpdate() const { return visual_rect_update_; }
-  void SetNeedsVisualRectUpdate() { visual_rect_update_ = true; }
-
   // True if the transform property itself changed, or properties related to
   // transform changed (e.g., individual transform properties, motion path,
   // etc.). See: |ComputedStyle::HasTransform|.
@@ -209,7 +204,6 @@
   unsigned layout_type_ : 2;
   unsigned needs_reshape_ : 1;
   unsigned recompute_visual_overflow_ : 1;
-  unsigned visual_rect_update_ : 1;
   unsigned property_specific_differences_ : kPropertyDifferenceCount;
   unsigned scroll_anchor_disabling_property_changed_ : 1;
   unsigned compositing_reasons_changed_ : 1;
@@ -223,7 +217,7 @@
   // data back again with a large read can cause store-to-load forward
   // stalls). Feel free to take bits from here if you need them
   // for something else.
-  unsigned padding_ [[maybe_unused]] : 12;
+  unsigned padding_ [[maybe_unused]] : 13;
 };
 static_assert(sizeof(StyleDifference) == 4, "Remove some padding bits!");
 
diff --git a/third_party/blink/renderer/core/style/style_difference_test.cc b/third_party/blink/renderer/core/style/style_difference_test.cc
index 1408fc7..3183f22 100644
--- a/third_party/blink/renderer/core/style/style_difference_test.cc
+++ b/third_party/blink/renderer/core/style/style_difference_test.cc
@@ -15,9 +15,8 @@
   string_stream << diff;
   EXPECT_EQ(
       "StyleDifference{layoutType=NoLayout, "
-      "reshape=0, "
-      "paintInvalidation=0, recomputeVisualOverflow=0, "
-      "visualRectUpdate=0, propertySpecificDifferences=, "
+      "reshape=0, paintInvalidation=0, recomputeVisualOverflow=0, "
+      "propertySpecificDifferences=, "
       "scrollAnchorDisablingPropertyChanged=0}",
       string_stream.str());
 }
@@ -29,15 +28,13 @@
   diff.SetNeedsPositionedMovementLayout();
   diff.SetNeedsReshape();
   diff.SetNeedsRecomputeVisualOverflow();
-  diff.SetNeedsVisualRectUpdate();
   diff.SetTransformPropertyChanged();
   diff.SetOtherTransformPropertyChanged();
   diff.SetScrollAnchorDisablingPropertyChanged();
   string_stream << diff;
   EXPECT_EQ(
       "StyleDifference{layoutType=PositionedMovement, "
-      "reshape=1, paintInvalidation=1, "
-      "recomputeVisualOverflow=1, visualRectUpdate=1, "
+      "reshape=1, paintInvalidation=1, recomputeVisualOverflow=1, "
       "propertySpecificDifferences="
       "TransformPropertyChanged|OtherTransformPropertyChanged, "
       "scrollAnchorDisablingPropertyChanged=1}",
@@ -58,8 +55,7 @@
   string_stream << diff;
   EXPECT_EQ(
       "StyleDifference{layoutType=NoLayout, "
-      "reshape=0, paintInvalidation=0, "
-      "recomputeVisualOverflow=0, visualRectUpdate=0, "
+      "reshape=0, paintInvalidation=0, recomputeVisualOverflow=0, "
       "propertySpecificDifferences=TransformPropertyChanged|"
       "OtherTransformPropertyChanged|OpacityChanged|"
       "ZIndexChanged|FilterChanged|CSSClipChanged|"
diff --git a/third_party/blink/renderer/modules/screen_enumeration/screen_detailed.cc b/third_party/blink/renderer/modules/screen_enumeration/screen_detailed.cc
index 5cec26d..9cbd3caa 100644
--- a/third_party/blink/renderer/modules/screen_enumeration/screen_detailed.cc
+++ b/third_party/blink/renderer/modules/screen_enumeration/screen_detailed.cc
@@ -21,7 +21,7 @@
                                int64_t display_id,
                                bool label_is_internal,
                                uint32_t label_idx)
-    : Screen(window, display_id),
+    : Screen(window, display_id, /*use_size_override=*/false),
       label_idx_(label_idx),
       label_is_internal_(label_is_internal) {}
 
@@ -29,8 +29,10 @@
 bool ScreenDetailed::AreWebExposedScreenDetailedPropertiesEqual(
     const display::ScreenInfo& prev,
     const display::ScreenInfo& current) {
-  if (!Screen::AreWebExposedScreenPropertiesEqual(prev, current))
+  if (!Screen::AreWebExposedScreenPropertiesEqual(
+          prev, current, /*use_size_override=*/false)) {
     return false;
+  }
 
   // left() / top()
   if (prev.rect.origin() != current.rect.origin())
@@ -99,25 +101,13 @@
 int ScreenDetailed::left() const {
   if (!DomWindow())
     return 0;
-  LocalFrame* frame = DomWindow()->GetFrame();
-  const display::ScreenInfo& screen_info = GetScreenInfo();
-  if (frame->GetSettings()->GetReportScreenSizeInPhysicalPixelsQuirk()) {
-    return base::ClampRound(screen_info.rect.x() *
-                            screen_info.device_scale_factor);
-  }
-  return screen_info.rect.x();
+  return GetRect(/*available=*/false).x();
 }
 
 int ScreenDetailed::top() const {
   if (!DomWindow())
     return 0;
-  LocalFrame* frame = DomWindow()->GetFrame();
-  const display::ScreenInfo& screen_info = GetScreenInfo();
-  if (frame->GetSettings()->GetReportScreenSizeInPhysicalPixelsQuirk()) {
-    return base::ClampRound(screen_info.rect.y() *
-                            screen_info.device_scale_factor);
-  }
-  return screen_info.rect.y();
+  return GetRect(/*available=*/false).y();
 }
 
 bool ScreenDetailed::isPrimary() const {
diff --git a/third_party/blink/renderer/modules/webcodecs/codec_logger.h b/third_party/blink/renderer/modules/webcodecs/codec_logger.h
index 8a0891f..5810218 100644
--- a/third_party/blink/renderer/modules/webcodecs/codec_logger.h
+++ b/third_party/blink/renderer/modules/webcodecs/codec_logger.h
@@ -133,7 +133,7 @@
 
   // Records the first media::Status passed to MakeException.
   typename StatusImpl::Codes status_code() const {
-    return status_code_.value_or(StatusImpl::Traits::DefaultEnumValue());
+    return status_code_.value_or(StatusImpl::Codes::kOk);
   }
 
  private:
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
index 11c92c8..69e84822 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
@@ -835,6 +835,12 @@
 
   previous_update_for_testing_ = PreviousUpdateType::kRepaint;
   needs_update_ = false;
+
+  DVLOG(3) << "PaintArtifactCompositor::UpdateRepaintedLayers() done\n"
+           << "Composited layers:\n"
+           << GetLayersAsJSON(VLOG_IS_ON(3) ? 0xffffffff : 0)
+                  ->ToPrettyJSONString()
+                  .Utf8();
 }
 
 bool PaintArtifactCompositor::CanDirectlyUpdateProperties() const {
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 1f705433..e2aaa0fe 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1368,6 +1368,16 @@
       status: "experimental",
     },
     {
+      // If enabled, `window.screen` always provides display dimensions.
+      // Otherwise, `window.screen` provides viewport dimensions in fullscreen
+      // as a speculative site compatibility measure, because web authors may
+      // assume that screen dimensions match window.innerWidth/innerHeight while
+      // a page is fullscreen, but that is not always true. crbug.com/1367416
+      name: "FullscreenScreenSizeMatchesDisplay",
+      status: "experimental",
+      base_feature: "FullscreenScreenSizeMatchesDisplay",
+    },
+    {
       name: "GamepadButtonAxisEvents",
       status: "experimental",
     },
diff --git a/third_party/blink/tools/blinkpy/common/checkout/baseline_optimizer_unittest.py b/third_party/blink/tools/blinkpy/common/checkout/baseline_optimizer_unittest.py
index 00eec06b..33112d8f 100644
--- a/third_party/blink/tools/blinkpy/common/checkout/baseline_optimizer_unittest.py
+++ b/third_party/blink/tools/blinkpy/common/checkout/baseline_optimizer_unittest.py
@@ -123,7 +123,7 @@
             self.fs.join(web_tests_dir, 'VirtualTestSuites'),
             '[{"prefix": "gpu", "platforms": ["Linux", "Mac", "Win"], '
             '"bases": ["fast/canvas", "slow/canvas/mock-test.html"], '
-            '"args": ["--foo"]}]')
+            '"args": ["--foo"], "expires": "never"}]')
         self.fs.write_text_file(
             self.fs.join(web_tests_dir, 'FlagSpecificConfig'),
             '[{"name": "highdpi", "args": ["--force-device-scale-factor=1.5"]}]'
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 5b61a611..fd92bbb 100644
--- a/third_party/blink/tools/blinkpy/w3c/import_notifier_unittest.py
+++ b/third_party/blink/tools/blinkpy/w3c/import_notifier_unittest.py
@@ -26,7 +26,8 @@
         self.host.filesystem = MockFileSystem({
             MOCK_WEB_TESTS + 'VirtualTestSuites':
             b'[{"prefix": "gpu", "platforms": ["Linux", "Mac", "Win"], '
-            b'"bases": ["external/wpt/foo"], "args": ["--foo"]}]'
+            b'"bases": ["external/wpt/foo"], "args": ["--foo"], '
+            b'"expires": "never"}]'
         })
         self.git = self.host.git()
         self.local_wpt = MockLocalWPT()
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 682a36b6..e8f3623 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/base.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/base.py
@@ -41,6 +41,7 @@
 import tempfile
 from collections import defaultdict
 from copy import deepcopy
+from datetime import datetime
 
 import six
 from six.moves import zip_longest
@@ -2238,10 +2239,16 @@
                     self._filesystem.read_text_file(
                         path_to_virtual_test_suites))
                 self._virtual_test_suites = []
+                current_time = datetime.now()
                 for json_config in test_suite_json:
                     # Strings are treated as comments.
                     if isinstance(json_config, str):
                         continue
+                    expires = json_config.get("expires")
+                    if (expires.lower() != 'never' and datetime.strptime(
+                            expires, '%b %d, %Y') <= current_time):
+                        # do not load expired virtual suites
+                        continue
                     vts = VirtualTestSuite(**json_config)
                     if any(vts.full_prefix == s.full_prefix
                            for s in self._virtual_test_suites):
@@ -2576,7 +2583,8 @@
                  platforms=None,
                  bases=None,
                  exclusive_tests=None,
-                 args=None):
+                 args=None,
+                 expires=None):
         assert VALID_FILE_NAME_REGEX.match(prefix), \
             "Virtual test suite prefix '{}' contains invalid characters".format(prefix)
         assert isinstance(platforms, list)
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/base_unittest.py b/third_party/blink/tools/blinkpy/web_tests/port/base_unittest.py
index c88d5603..b2636fe 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/base_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/base_unittest.py
@@ -229,7 +229,7 @@
         port.host.filesystem.write_text_file(
             MOCK_WEB_TESTS + 'VirtualTestSuites',
             '[{ "prefix": "bar", "platforms": ["Linux", "Mac", "Win"],'
-            ' "bases": ["fast"], "args": ["--bar"]}]')
+            ' "bases": ["fast"], "args": ["--bar"], "expires": "never"}]')
         port.host.filesystem.write_text_file(
             MOCK_WEB_TESTS + 'FlagSpecificConfig',
             '[{"name": "special-flag", "args": ["--special"]}]')
@@ -316,7 +316,7 @@
         port.host.filesystem.write_text_file(
             MOCK_WEB_TESTS + 'VirtualTestSuites',
             '[{ "prefix": "flag", "platforms": ["Linux", "Mac", "Win"],'
-            ' "bases": ["fast"], "args": ["--flag"]}]')
+            ' "bases": ["fast"], "args": ["--flag"], "expires": "never"}]')
 
         # The default baseline for base test
         self.assertEqual(
@@ -1465,7 +1465,7 @@
             port.host.filesystem.join(port.web_tests_dir(),
                                       'VirtualTestSuites'),
             '[{"prefix": "bar", "platforms": ["Linux", "Mac", "Win"], '
-            '"bases": ["fast/bar"], "args": ["--bar"]}]')
+            '"bases": ["fast/bar"], "args": ["--bar"], "expires": "never"}]')
 
         # If this call returns successfully, we found and loaded the web_tests/VirtualTestSuites.
         _ = port.virtual_test_suites()
@@ -1475,8 +1475,10 @@
         port.host.filesystem.write_text_file(
             port.host.filesystem.join(port.web_tests_dir(),
                                       'VirtualTestSuites'), '['
-            '{"prefix": "bar", "platforms": ["Linux"], "bases": ["fast/bar"], "args": ["--bar"]},'
-            '{"prefix": "bar", "platforms": ["Linux"], "bases": ["fast/foo"], "args": ["--bar"]}'
+            '{"prefix": "bar", "platforms": ["Linux"], "bases": ["fast/bar"], '
+            '"args": ["--bar"], "expires": "never"},'
+            '{"prefix": "bar", "platforms": ["Linux"], "bases": ["fast/foo"], '
+            '"args": ["--bar"], "expires": "never"}'
             ']')
 
         self.assertRaises(ValueError, port.virtual_test_suites)
@@ -1581,6 +1583,24 @@
         port = self.make_port()
         self.assertRaises(AssertionError, port.virtual_test_suites)
 
+    def test_virtual_test_expires(self):
+        port = self.make_port()
+        fs = port.host.filesystem
+        web_tests_dir = port.web_tests_dir()
+        fs.write_text_file(
+            fs.join(web_tests_dir, 'VirtualTestSuites'), '['
+            '{"prefix": "v1", "platforms": ["Linux"], "bases": ["test"],'
+            ' "args": ["-a"], "expires": "Jul 1, 2022"},'
+            '{"prefix": "v2", "platforms": ["Linux"], "bases": ["test"],'
+            ' "args": ["-b"], "expires": "Jul 1, 2222"},'
+            '{"prefix": "v3", "platforms": ["Linux"], "bases": ["test"],'
+            ' "args": ["-c"], "expires": "never"}'
+            ']')
+        fs.write_text_file(fs.join(web_tests_dir, 'test', 'test.html'), '')
+        self.assertTrue("virtual/v1/test/test.html" not in port.tests())
+        self.assertTrue("virtual/v2/test/test.html" in port.tests())
+        self.assertTrue("virtual/v3/test/test.html" in port.tests())
+
     def test_virtual_exclusive_tests(self):
         port = self.make_port()
         fs = port.host.filesystem
@@ -1588,11 +1608,13 @@
         fs.write_text_file(
             fs.join(web_tests_dir, 'VirtualTestSuites'), '['
             '{"prefix": "v1", "platforms": ["Linux"], "bases": ["b1", "b2"],'
-            ' "exclusive_tests": "ALL", "args": ["-a"]},'
+            ' "exclusive_tests": "ALL", '
+            '"args": ["-a"], "expires": "never"},'
             '{"prefix": "v2", "platforms": ["Linux"], "bases": ["b2"],'
-            ' "exclusive_tests": ["b2/test.html"], "args": ["-b"]},'
+            ' "exclusive_tests": ["b2/test.html"], '
+            '"args": ["-b"], "expires": "never"},'
             '{"prefix": "v3", "platforms": ["Linux"], "bases": ["b3"],'
-            ' "args": ["-c"]}'
+            ' "args": ["-c"], "expires": "never"}'
             ']')
         fs.write_text_file(fs.join(web_tests_dir, 'b1', 'test.html'), '')
         fs.write_text_file(fs.join(web_tests_dir, 'b1', 'test2.html'), '')
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 9460f63..90cfd6e 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -3131,9 +3131,9 @@
 crbug.com/626703 external/wpt/geolocation-API/enabled-by-feature-policy-attribute.https.sub.html [ Timeout ]
 crbug.com/626703 external/wpt/geolocation-API/enabled-by-feature-policy.https.sub.html [ Timeout ]
 crbug.com/626703 external/wpt/geolocation-API/enabled-on-self-origin-by-feature-policy.https.sub.html [ Timeout ]
-crbug.com/626703 external/wpt/resource-timing/object-not-found-adds-entry.html [ Timeout Failure Pass ]
-crbug.com/1385265 virtual/plz-dedicated-worker/external/wpt/resource-timing/object-not-found-adds-entry.html [ Skip Failure Pass ]
-crbug.com/1385278 external/wpt/resource-timing/iframe-failed-commit.html [ Skip Failure Pass Timeout ]
+crbug.com/626703 external/wpt/resource-timing/object-not-found-adds-entry.html [ Failure Pass Timeout ]
+crbug.com/1385265 virtual/plz-dedicated-worker/external/wpt/resource-timing/object-not-found-adds-entry.html [ Failure Pass Skip ]
+crbug.com/1385278 external/wpt/resource-timing/iframe-failed-commit.html [ Failure Pass Skip Timeout ]
 crbug.com/626703 external/wpt/webrtc/RTCConfiguration-iceTransportPolicy.html [ Skip Timeout ]
 crbug.com/626703 [ Mac12 ] external/wpt/mediacapture-record/MediaRecorder-mimetype.html [ Failure Timeout ]
 crbug.com/626703 [ Mac10.14 ] virtual/portals/external/wpt/portals/no-portal-in-sandboxed-popup.html [ Timeout ]
@@ -6366,19 +6366,20 @@
 crbug.com/1378078 [ Debug Linux ] media/controls/slow-doubletap.html [ Failure ]
 crbug.com/1384671 [ Win ] virtual/prerender/external/wpt/speculation-rules/prerender/opt-out.html [ Failure Timeout ]
 crbug.com/1384671 [ Linux ] external/wpt/speculation-rules/prerender/opt-out.html [ Failure Timeout ]
-crbug.com/1385491 [ Win ] external/wpt/selection/user-select-on-input-and-contenteditable.html [ Crash Failure Pass Timeout ]
+crbug.com/1385491 [ Win ] external/wpt/selection/user-select-on-input-and-contenteditable.html [ Skip Timeout ]
 crbug.com/1385538 [ Win ] http/tests/serviceworker/postmessage-cross-process.html [ Failure ]
 crbug.com/1377056 [ Debug Linux ] payments/payment-request-interface.html [ Failure ]
 crbug.com/1377056 [ Mac ] payments/payment-request-interface.html [ Failure ]
-crbug.com/1385919 [ Win ] external/wpt/css/selectors/focus-visible-018-2.html [ Crash Failure Pass Timeout ]
-crbug.com/1385919 [ Win ] external/wpt/css/selectors/focus-visible-002.html [ Crash Failure Pass Timeout ]
-crbug.com/1385905 [ Win ] external/wpt/editing/run/caret-navigation-around-line-break.html [ Crash Failure Pass Timeout ]
+crbug.com/1385919 [ Win ] external/wpt/css/selectors/focus-visible-018-2.html [ Skip Timeout ]
+crbug.com/1385919 [ Win ] external/wpt/css/selectors/focus-visible-002.html [ Skip Timeout ]
+crbug.com/1385905 [ Win ] external/wpt/editing/run/caret-navigation-around-line-break.html [ Skip Timeout ]
 crbug.com/1385881 [ Win ] external/wpt/fetch/metadata/generated/audioworklet.https.sub.html [ Timeout ]
-crbug.com/1385870 [ Win ] external/wpt/screen-capture/getdisplaymedia.https.html [ Crash Failure Pass Timeout ]
-crbug.com/1385870 [ Win ] external/wpt/screen-capture/getdisplaymedia-capture-controller.https.window.html [ Crash Failure Pass Timeout ]
-crbug.com/1385858 [ Win ] virtual/web-bluetooth-new-permissions-backend/wpt_internal/bluetooth/requestDevice/filter-does-not-match.https.html [ Crash Failure Pass Timeout ]
+crbug.com/1385870 [ Win ] external/wpt/screen-capture/getdisplaymedia.https.html [ Skip Timeout ]
+crbug.com/1385870 [ Win ] external/wpt/screen-capture/getdisplaymedia-capture-controller.https.window.html [ Skip Timeout ]
+crbug.com/1385858 [ Win ] virtual/web-bluetooth-new-permissions-backend/wpt_internal/bluetooth/requestDevice/filter-does-not-match.https.html [ Skip Timeout ]
 crbug.com/1385929 [ Win ] editing/selection/mouse/mouse-selection-vertical-lr.html [ Timeout ]
 crbug.com/1385929 [ Win ] editing/selection/mouse/mouse-selection-horizontal.html [ Timeout ]
+crbug.com/1392480 [ Win ] wpt_internal/hid/hidDevice_reports.https.window.html [ Timeout ]
 
 # Sheriff 2022-10-07
 crbug.com/1372556 [ Linux ] external/wpt/css/css-text/text-transform/text-transform-capitalize-* [ Failure Pass ]
diff --git a/third_party/blink/web_tests/VIRTUAL_OWNERS b/third_party/blink/web_tests/VIRTUAL_OWNERS
index 949a323..5c21dc0 100644
--- a/third_party/blink/web_tests/VIRTUAL_OWNERS
+++ b/third_party/blink/web_tests/VIRTUAL_OWNERS
@@ -24,6 +24,11 @@
 #   will be part of the path should a baseline be needed, and will cause
 #   trouble at that time.
 #
+# - The expiration date of the virtual test suite usually should be 6 month
+#   from the creatation of the test suite. The expiration date can be set to
+#   'never' when it is not expected to expire. In this case an explanation is
+#   required.
+#
 # [1] https://chromium.googlesource.com/chromium/src/+/main/docs/testing/web_tests.md#testing-runtime-flags
 
 dom@chromium.org
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index cced3405..c71e3b5 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -15,6 +15,8 @@
   "     in their `exclusive_tests` list will be skipped, too.                 ",
   " args: A list of command line switches that will be passed to the test     ",
   "     driver for the tests under this virtual suite.                        ",
+  " expires: An expiration date or 'never' if the test suite is not expected  ",
+  "     to expire. Tests will not be run starting from the expiration date.   ",
 
   {
     "prefix": "anonymous-iframe-origin-trial",
@@ -24,13 +26,15 @@
       "--disable-blink-features=AnonymousIframe",
       "--disable-features=PartitionedCookies,ThirdPartyStoragePartitioning",
       "--enable-features=AnonymousIframeOriginTrial"
-    ]
+    ],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "pna-permission",
     "platforms": ["Linux", "Mac", "Win", "Fuchsia"],
     "bases": ["external/wpt/fetch/private-network-access"],
-    "args": ["--enable-features=PrivateNetworkAccessPermissionPrompt"]
+    "args": ["--enable-features=PrivateNetworkAccessPermissionPrompt"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "reduce-accept-language",
@@ -41,19 +45,22 @@
               "navigator_language/reduce_accept_language"],
     "exclusive_tests": ["http/tests/serviceworker/reduce-accept-language/fetch-event-headers.html",
                         "navigator_language/reduce_accept_language"],
-    "args": ["--enable-features=ReduceAcceptLanguage"]
+    "args": ["--enable-features=ReduceAcceptLanguage"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "gpu",
     "platforms": ["Linux", "Mac", "Win", "Fuchsia"],
     "bases": ["fast/canvas"],
-    "args": ["--enable-accelerated-2d-canvas"]
+    "args": ["--enable-accelerated-2d-canvas"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "unsafe_webgpu",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["regress/regress-1104580.html"],
-    "args": ["--enable-unsafe-webgpu"]
+    "args": ["--enable-unsafe-webgpu"],
+    "expires": "Jul 1, 2023"
   },
 
   "The skipped base tests require a compositor, e.g. some uses requestIdleCallback",
@@ -92,7 +99,8 @@
                         "external/wpt/pointerevents/pointerevent_predicted_events_attributes-manual.html",
                         "external/wpt/requestidlecallback",
                         "http/tests/devtools/isolated-code-cache"],
-    "args": ["--enable-threaded-compositing"]
+    "args": ["--enable-threaded-compositing"],
+    "expires": "Jul 1, 2023"
   },
 
   {
@@ -101,7 +109,8 @@
     "bases": ["wpt_internal/attribution-reporting"],
     "exclusive_tests": "ALL",
     "args": ["--attribution-reporting-debug-mode",
-             "--enable-features=AttributionReportingCrossAppWeb"]
+             "--enable-features=AttributionReportingCrossAppWeb"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "off-main-thread-css-paint",
@@ -112,7 +121,8 @@
              "--enable-blink-features=OffMainThreadCSSPaint",
              "--enable-gpu-rasterization",
              "--enable-accelerated-2d-canvas",
-             "--disable-features=CanvasOopRasterization"]
+             "--disable-features=CanvasOopRasterization"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "prefer_compositing_to_lcd_text",
@@ -120,14 +130,16 @@
     "bases": ["compositing/overflow",
               "compositing/squashing/keep-lcd-text.html",
               "scrollbars"],
-    "args": ["--enable-prefer-compositing-to-lcd-text"]
+    "args": ["--enable-prefer-compositing-to-lcd-text"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "threaded-no-composited-antialiasing",
     "platforms": ["Linux", "Mac", "Win", "Fuchsia"],
     "bases": ["animations"],
     "args": ["--enable-threaded-compositing",
-             "--disable-composited-antialiasing"]
+             "--disable-composited-antialiasing"],
+    "expires": "Jul 1, 2023"
   },
 
   "The skipped base test requires a compositor to pass as root scrollbar scrolling",
@@ -141,14 +153,16 @@
               "external/wpt/css/cssom-view"],
     "exclusive_tests": ["fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar-thumb-scaled.html"],
     "args": ["--enable-threaded-compositing",
-             "--enable-prefer-compositing-to-lcd-text"]
+             "--enable-prefer-compositing-to-lcd-text"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "gpu-rasterization",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["images",
               "external/wpt/css/css-images/gradient"],
-    "args": ["--enable-gpu-rasterization"]
+    "args": ["--enable-gpu-rasterization"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "gpu-rasterization-disable-yuv",
@@ -156,14 +170,16 @@
     "bases": ["images/yuv-decode-eligible"],
     "args": ["--enable-gpu-rasterization",
              "--disable-blink-features=DecodeLossyWebPImagesToYUV",
-             "--disable-blink-features=DecodeJpeg420ImagesToYUV"]
+             "--disable-blink-features=DecodeJpeg420ImagesToYUV"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "exotic-color-space",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["images"],
     "args": ["--force-color-profile=srgb",
-             "--force-raster-color-profile=color-spin-gamma24"]
+             "--force-raster-color-profile=color-spin-gamma24"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "stable",
@@ -185,7 +201,8 @@
     "exclusive_tests": ["media/stable"],
     "args": ["--stable-release-mode",
              "--disable-auto-wpt-origin-isolation",
-             "--disable-field-trial-config"]
+             "--disable-field-trial-config"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "feature-policy-permissions",
@@ -193,14 +210,16 @@
     "bases": ["external/wpt/mediacapture-streams"],
     "exclusive_tests": ["external/wpt/mediacapture-streams/MediaStream-default-feature-policy.https.html"],
     "args": ["--use-fake-device-for-media-stream",
-             "--use-fake-ui-for-media-stream"]
+             "--use-fake-ui-for-media-stream"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "origin-trials-runtimeflags-disabled",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["http/tests/origin_trials/webexposed"],
     "args": ["--disable-origin-trial-controlled-blink-features",
-             "--stable-release-mode"]
+             "--stable-release-mode"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "android",
@@ -212,7 +231,8 @@
              "--enable-overscroll-notifications",
              "--enable-viewport",
              "--disable-canvas-aa",
-             "--disable-composited-antialiasing"]
+             "--disable-composited-antialiasing"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "media-foundation-for-clear-dcomp",
@@ -220,7 +240,8 @@
     "bases": ["external/wpt/media-source",
               "media"],
     "args": ["--use-gpu-in-tests",
-             "--enable-features=MediaFoundationClearPlayback,MediaFoundationClearRendering:strategy/direct-composition"]
+             "--enable-features=MediaFoundationClearPlayback,MediaFoundationClearRendering:strategy/direct-composition"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "media-foundation-for-clear-frameserver",
@@ -229,14 +250,16 @@
               "media"],
     "args": ["--use-gpu-in-tests",
              "--force-mfmediaengine-renderer",
-             "--enable-features=MediaFoundationClearRendering:strategy/frame-server"]
+             "--enable-features=MediaFoundationClearRendering:strategy/frame-server"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "media-gpu-accelerated",
     "platforms": ["Linux", "Mac", "Win", "Fuchsia"],
     "bases": ["external/wpt/media-source",
               "media"],
-    "args": ["--use-gpu-in-tests"]
+    "args": ["--use-gpu-in-tests"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "shared_array_buffer_on_desktop",
@@ -246,7 +269,8 @@
               "fast/workers/worker-sharedarraybuffer-transfer.html",
               "fast/workers/chromium/worker-sharedarraybuffer-transfer-two-workers.html",
               "http/tests/inspector-protocol/issues"],
-    "args": ["--enable-features=SharedArrayBuffer"]
+    "args": ["--enable-features=SharedArrayBuffer"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "mse-1mb-buffers",
@@ -254,28 +278,32 @@
     "bases": ["http/tests/media/media-source/stream_memory_tests"],
     "exclusive_tests": ["http/tests/media/media-source/stream_memory_tests/mediasource-appendbuffer-quota-exceeded-1mb-buffers.html"],
     "args": ["--mse-audio-buffer-size-limit-mb=1",
-             "--mse-video-buffer-size-limit-mb=1"]
+             "--mse-video-buffer-size-limit-mb=1"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "composite-clip-path-animation",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/css/css-masking/clip-path/animations"],
     "args": ["--enable-blink-features=CompositeClipPathAnimation",
-             "--enable-threaded-compositing"]
+             "--enable-threaded-compositing"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "fractional-scroll-offsets",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/css/css-position/sticky/",
               "fast/scrolling/"],
-    "args": ["--enable-blink-features=FractionalScrollOffsets"]
+    "args": ["--enable-blink-features=FractionalScrollOffsets"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "compute-pressure",
     "platforms": ["Linux", "Mac"],
     "bases": ["external/wpt/compute-pressure"],
     "exclusive_tests": "ALL",
-    "args": ["--enable-features=ComputePressure"]
+    "args": ["--enable-features=ComputePressure"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "highdpi-threaded",
@@ -283,7 +311,8 @@
     "bases": ["external/wpt/css/css-backgrounds/hidpi",
               "external/wpt/css/css-paint-api/hidpi"],
     "args": ["--force-device-scale-factor=2",
-             "--enable-threaded-compositing"]
+             "--enable-threaded-compositing"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "scalefactor200",
@@ -300,7 +329,8 @@
               "http/tests/images/document-policy",
               "http/tests/inspector-protocol/page/page-captureScreenshot-clip-emulation.js"],
     "exclusive_tests": ["fast/hidpi/static"],
-    "args": ["--force-device-scale-factor=2"]
+    "args": ["--force-device-scale-factor=2"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "jxl-enabled",
@@ -308,7 +338,8 @@
     "bases": ["http/tests/inspector-protocol/emulation/emulation-set-disabled-image-types-jxl.js",
               "images/jxl"],
     "exclusive_tests": ["http/tests/inspector-protocol/emulation/emulation-set-disabled-image-types-jxl.js"],
-    "args": ["--enable-features=JXL"]
+    "args": ["--enable-features=JXL"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "scalefactor150",
@@ -316,53 +347,61 @@
     "bases": ["fast/events/synthetic-events",
               "fast/hidpi/static"],
     "exclusive_tests": ["fast/hidpi/static"],
-    "args": ["--force-device-scale-factor=1.5"]
+    "args": ["--force-device-scale-factor=1.5"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "schemeful-same-site",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/cookies"],
-    "args": ["--disable-features=SchemefulSameSite"]
+    "args": ["--disable-features=SchemefulSameSite"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "dark-mode-classifier-transparency-and-num-colors",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["dark-mode/images"],
     "args": ["--blink-settings=preferredColorScheme=0,forceDarkModeEnabled=true",
-             "--dark-mode-settings=ImageClassifierPolicy=1"]
+             "--dark-mode-settings=ImageClassifierPolicy=1"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "dark-mode-default",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["dark-mode/colors",
               "dark-mode/images"],
-    "args": ["--blink-settings=preferredColorScheme=0,forceDarkModeEnabled=true"]
+    "args": ["--blink-settings=preferredColorScheme=0,forceDarkModeEnabled=true"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "dark-mode-images-filter-all",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["dark-mode/images"],
     "args": ["--blink-settings=preferredColorScheme=0,forceDarkModeEnabled=true",
-             "--dark-mode-settings=ImagePolicy=0"]
+             "--dark-mode-settings=ImagePolicy=0"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "dark-mode-images-filter-none",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["dark-mode/images"],
     "args": ["--blink-settings=preferredColorScheme=0,forceDarkModeEnabled=true",
-             "--dark-mode-settings=ImagePolicy=1"]
+             "--dark-mode-settings=ImagePolicy=1"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "presentation",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": [],
-    "args": ["--force-presentation-receiver-for-testing"]
+    "args": ["--force-presentation-receiver-for-testing"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "single-renderer-process",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/longtask-timing/shared-renderer"],
-    "args": ["--renderer-process-limit=1"]
+    "args": ["--renderer-process-limit=1"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "compositor_threaded_scrollbar_scrolling",
@@ -372,7 +411,8 @@
     "args": ["--enable-features=CompositorThreadedScrollbarScrolling",
              "--enable-threaded-compositing",
              "--enable-prefer-compositing-to-lcd-text",
-             "--disable-smooth-scrolling"]
+             "--disable-smooth-scrolling"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "percent-based-scrolling",
@@ -381,7 +421,8 @@
     "args": ["--enable-features=WindowsScrollingPersonality",
              "--enable-threaded-compositing",
              "--enable-prefer-compositing-to-lcd-text",
-             "--disable-features=CompositorThreadedScrollbarScrolling"]
+             "--disable-features=CompositorThreadedScrollbarScrolling"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "main-threaded-percent-based-scrolling",
@@ -389,7 +430,8 @@
     "bases": ["fast/events/wheel",
               "fast/scrolling",
               "virtual/percent-based-scrolling"],
-    "args": ["--enable-features=WindowsScrollingPersonality"]
+    "args": ["--enable-features=WindowsScrollingPersonality"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "compositor-threaded-percent-based-scrolling",
@@ -399,7 +441,8 @@
               "virtual/percent-based-scrolling"],
     "args": ["--enable-features=WindowsScrollingPersonality",
              "--enable-threaded-compositing",
-             "--enable-prefer-compositing-to-lcd-text"]
+             "--enable-prefer-compositing-to-lcd-text"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "compositor-threaded-percent-based-scrolling-dsf-2",
@@ -409,7 +452,8 @@
     "args": ["--enable-features=WindowsScrollingPersonality",
              "--enable-threaded-compositing",
              "--enable-prefer-compositing-to-lcd-text",
-             "--force-device-scale-factor=2"]
+             "--force-device-scale-factor=2"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "smooth_compositor_threaded_scrollbar_scrolling",
@@ -418,14 +462,16 @@
     "args": ["--enable-features=CompositorThreadedScrollbarScrolling",
              "--enable-threaded-compositing",
              "--enable-prefer-compositing-to-lcd-text",
-             "--enable-smooth-scrolling"]
+             "--enable-smooth-scrolling"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "hidpi",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["fast/scrolling/scrollbars/dsf-ready"],
     "args": ["--disable-smooth-scrolling",
-             "--force-device-scale-factor=2"]
+             "--force-device-scale-factor=2"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "compositor_threaded_scrollbar_scrolling_hidpi",
@@ -435,26 +481,30 @@
              "--enable-threaded-compositing",
              "--enable-prefer-compositing-to-lcd-text",
              "--disable-smooth-scrolling",
-             "--force-device-scale-factor=2"]
+             "--force-device-scale-factor=2"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "speech-with-unified-autoplay",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/speech-api"],
-    "args": ["--autoplay-policy=document-user-activation-required"]
+    "args": ["--autoplay-policy=document-user-activation-required"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "unified-autoplay",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/feature-policy"],
-    "args": ["--autoplay-policy=document-user-activation-required"]
+    "args": ["--autoplay-policy=document-user-activation-required"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "wbn-from-network",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/web-bundle"],
     "exclusive_tests": ["external/wpt/web-bundle/wbn-from-network"],
-    "args": ["--enable-features=WebBundlesFromNetwork"]
+    "args": ["--enable-features=WebBundlesFromNetwork"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "plz-dedicated-worker",
@@ -478,13 +528,15 @@
               "http/tests/workers",
               "inspector-protocol/worker"
             ],
-    "args": ["--enable-features=PlzDedicatedWorker"]
+    "args": ["--enable-features=PlzDedicatedWorker"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "service-worker-storage-control-on-thread-pool",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/service-workers/service-worker/fetch-event.https.html"],
-    "args": ["--enable-features=ServiceWorkerStorageControlOnThreadPool"]
+    "args": ["--enable-features=ServiceWorkerStorageControlOnThreadPool"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "direct-sockets",
@@ -493,21 +545,24 @@
     	      "wpt_internal/direct-sockets"],
     "exclusive_tests": "ALL",
     "args": ["--enable-features=IsolatedWebApps",
-             "--isolated-app-origins=https://web-platform.test"]
+             "--isolated-app-origins=https://web-platform.test"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "display-compositor-pixel-dump",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": [],
     "args": ["--enable-display-compositor-pixel-dump",
-             "--enable-accelerated-2d-canvas"]
+             "--enable-accelerated-2d-canvas"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "webgl-extra-video-texture-metadata",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["fast/webgl/video-metadata"],
     "exclusive_tests": ["fast/webgl/video-metadata/texImage-video-last-uploaded-metadata.html"],
-    "args": ["--enable-blink-features=ExtraWebGLVideoTextureMetadata"]
+    "args": ["--enable-blink-features=ExtraWebGLVideoTextureMetadata"],
+    "expires": "Jul 1, 2023"
   },
 
   "The Wasm code cache test requires access to V8 internals, so only the",
@@ -517,7 +572,8 @@
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["http/tests/wasm/caching"],
     "exclusive_tests": "ALL",
-    "args": ["--js-flags=--allow-natives-syntax"]
+    "args": ["--js-flags=--allow-natives-syntax"],
+    "expires": "Jul 1, 2023"
   },
 
   "==== Tests incompatible with the default WPT Origin Isolation start here ==VV",
@@ -564,7 +620,8 @@
       "external/wpt/navigation-api/navigate-event/cross-window/submit-samedocument-crossorigin-sameorigindomain.sub.html"
     ],
     "exclusive_tests": "ALL",
-    "args": ["--disable-site-isolation-trials"]
+    "args": ["--disable-site-isolation-trials"],
+    "expires": "Jul 1, 2023"
   },
 
   "----------------------- origin-keyed agent clusters --------------------",
@@ -584,7 +641,8 @@
     ],
     "exclusive_tests": ["external/wpt/html/browsers/origin/origin-keyed-agent-clusters"],
     "args": ["--disable-auto-wpt-origin-isolation",
-             "--reset-browsing-instance-between-tests"]
+             "--reset-browsing-instance-between-tests"],
+    "expires": "Jul 1, 2023"
   },
 
   {
@@ -592,7 +650,8 @@
     "platforms": ["Linux", "Mac", "Win"],
     "bases": [],
     "args": ["--enable-blink-features=FocuslessSpatialNavigation",
-             "--enable-spatial-navigation"]
+             "--enable-spatial-navigation"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "passive-fingerprinting",
@@ -600,26 +659,30 @@
     "bases": ["http/tests/navigation/frozen-useragent.html",
               "http/tests/navigation/useragent.php"],
     "exclusive_tests": ["http/tests/navigation/frozen-useragent.html"],
-    "args": ["--enable-features=ReduceUserAgent"]
+    "args": ["--enable-features=ReduceUserAgent"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "fsa-incognito",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/file-system-access"],
-    "args": ["--enable-features=IncognitoFileSystemContextForTesting"]
+    "args": ["--enable-features=IncognitoFileSystemContextForTesting"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "controls-refresh-hc",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["fast/forms/color-scheme"],
     "args": ["--enable-features=ForcedColors",
-             "--force-high-contrast"]
+             "--force-high-contrast"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "use-common-select-popup",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["fast/forms/color-scheme/select"],
-    "args": ["--enable-features=UseCommonSelectPopup"]
+    "args": ["--enable-features=UseCommonSelectPopup"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "forced-high-contrast-colors",
@@ -628,7 +691,8 @@
               "html/details_summary/color-scheme-validation"],
     "exclusive_tests": ["external/wpt/forced-colors-mode"],
     "args": ["--force-high-contrast",
-             "--enable-blink-features=ForcedColors,ForcedColorsPreserveParentColor"]
+             "--enable-blink-features=ForcedColors,ForcedColorsPreserveParentColor"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "dark-color-scheme",
@@ -640,20 +704,23 @@
               "fast/forms/validation-bubble-appearance-wrap.html",
               "fast/loader/plain-text-document-appearance.html",
               "http/tests/eye-dropper"],
-    "args": ["--blink-settings=preferredColorScheme=0"]
+    "args": ["--blink-settings=preferredColorScheme=0"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "force-eager",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/measure-memory"],
     "exclusive_tests": "ALL",
-    "args": ["--enable-blink-features=MeasureMemory,ForceEagerMeasureMemory"]
+    "args": ["--enable-blink-features=MeasureMemory,ForceEagerMeasureMemory"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "payment-request-mandatory-total",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["http/tests/payments/payment-request-app-store-billing-mandatory-total.html"],
-    "args": ["--disable-blink-features=PaymentRequestTotalOptional"]
+    "args": ["--disable-blink-features=PaymentRequestTotalOptional"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "css-trigonometric-functions-disabled",
@@ -666,19 +733,22 @@
       "external/wpt/css/css-values/acos-asin-atan-atan2-computed.html",
       "external/wpt/css/css-values/acos-asin-atan-atan2-invalid.html"
     ],
-    "args": ["--disable-blink-features=CSSTrigonometricFunctions"]
+    "args": ["--disable-blink-features=CSSTrigonometricFunctions"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "import-maps-disabled",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/import-maps/not-as-classic-script.html"],
-    "args": ["--disable-blink-features=ImportMaps"]
+    "args": ["--disable-blink-features=ImportMaps"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "overlay-scrollbar",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": [],
-    "args": ["--enable-features=OverlayScrollbar"]
+    "args": ["--enable-features=OverlayScrollbar"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "elastic-overscroll",
@@ -686,13 +756,15 @@
     "bases": [],
     "args": ["--enable-features=ElasticOverscroll",
              "--enable-blink-features=FixedElementsDontOverscroll",
-             "--enable-threaded-compositing"]
+             "--enable-threaded-compositing"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "non-overlay-scrollbar",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": [],
-    "args": ["--disable-features=OverlayScrollbar"]
+    "args": ["--disable-features=OverlayScrollbar"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "fluent-non-overlay-scrollbar",
@@ -700,7 +772,8 @@
     "bases": ["fast/scrolling/scrollbars"],
     "args": ["--enable-features=FluentScrollbar",
              "--enable-threaded-compositing",
-             "--disable-smooth-scrolling"]
+             "--disable-smooth-scrolling"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "fluent-non-overlay-scrollbar-dsf-150",
@@ -708,7 +781,8 @@
     "bases": ["virtual/fluent-non-overlay-scrollbar/composited"],
     "args": ["--enable-features=FluentScrollbar",
              "--enable-threaded-compositing",
-             "--force-device-scale-factor=1.5"]
+             "--force-device-scale-factor=1.5"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "fluent-non-overlay-scrollbar-dsf-200",
@@ -716,51 +790,59 @@
     "bases": ["virtual/fluent-non-overlay-scrollbar/composited"],
     "args": ["--enable-features=FluentScrollbar",
              "--enable-threaded-compositing",
-             "--force-device-scale-factor=2"]
+             "--force-device-scale-factor=2"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "fluent-non-overlay-scrollbar-dark-mode",
     "platforms": ["Win"],
     "bases": ["fast/forms/color-scheme/scrollbar"],
     "args": ["--enable-features=FluentScrollbar",
-             "--blink-settings=preferredColorScheme=0"]
+             "--blink-settings=preferredColorScheme=0"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "text-antialias",
     "platforms": ["Linux", "Mac", "Win", "Fuchsia"],
     "bases": [],
-    "args": ["--enable-font-antialiasing"]
+    "args": ["--enable-font-antialiasing"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "mathml-disabled",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": [],
-    "args": ["--disable-blink-features=MathMLCore"]
+    "args": ["--disable-blink-features=MathMLCore"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "hdr",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": [],
-    "args": ["--force-color-profile=scrgb-linear"]
+    "args": ["--force-color-profile=scrgb-linear"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "color-spin",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": [],
-    "args": ["--force-color-profile=color-spin-gamma24"]
+    "args": ["--force-color-profile=color-spin-gamma24"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "wide-gamut",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": [],
-    "args": ["--force-color-profile=display-p3-d65"]
+    "args": ["--force-color-profile=display-p3-d65"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "split-cache-by-include-credentials",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/fetch/http-cache"],
     "exclusive_tests": "ALL",
-    "args": ["--enable-features=SplitCacheByIncludeCredentials"]
+    "args": ["--enable-features=SplitCacheByIncludeCredentials"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "split-http-cache",
@@ -768,44 +850,51 @@
     "bases": ["external/wpt/fetch/http-cache",
               "external/wpt/signed-exchange"],
     "exclusive_tests": ["external/wpt/fetch/http-cache"],
-    "args": ["--enable-features=SplitCacheByNetworkIsolationKey"]
+    "args": ["--enable-features=SplitCacheByNetworkIsolationKey"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "not-split-http-cache",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/fetch/http-cache"],
     "exclusive_tests": "ALL",
-    "args": ["--disable-features=SplitCacheByNetworkIsolationKey"]
+    "args": ["--disable-features=SplitCacheByNetworkIsolationKey"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "disable-ua-client-hint",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/client-hints", "wpt_internal/client-hints"],
-    "args": ["--disable-features=UserAgentClientHint"]
+    "args": ["--disable-features=UserAgentClientHint"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "disable-prefers-reduced-motion-client-hint",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/client-hints", "wpt_internal/client-hints"],
-    "args": ["--disable-features=PrefersReducedMotionClientHintHeader"]
+    "args": ["--disable-features=PrefersReducedMotionClientHintHeader"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "storage-access-api",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": [ "external/wpt/storage-access-api" ],
-    "args": [ "--enable-features=StorageAccessAPI" ]
+    "args": [ "--enable-features=StorageAccessAPI" ],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "storage-access-api-for-origin-extension",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": [ "wpt_internal/storage-access-api" ],
-    "args": [ "--enable-features=StorageAccessAPI,StorageAccessAPIForOriginExtension" ]
+    "args": [ "--enable-features=StorageAccessAPI,StorageAccessAPIForOriginExtension" ],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "web-bluetooth-new-permissions-backend",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["wpt_internal/bluetooth", "external/wpt/bluetooth"],
-    "args": ["--enable-features=WebBluetoothNewPermissionsBackend"]
+    "args": ["--enable-features=WebBluetoothNewPermissionsBackend"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "trust-tokens",
@@ -821,7 +910,8 @@
         "--enable-features=PrivateStateTokens",
         "--enable-blink-features=PrivateStateTokens,PrivateStateTokensAlwaysAllowIssuance",
         "--additional-trust-token-key-commitments={\"https://web-platform.test:8444\":{\"TrustTokenV3VOPRF\":{\"protocol_version\":\"TrustTokenV3VOPRF\",\"id\":1,\"batchsize\":1,\"keys\":{\"0\":{\"Y\":\"AAAAAASqh8oivosFN46xxx7zIK10bh07Younm5hZ90HgglQqOFUC8l2/VSlsOlReOHJ2CrfJ6CG1adnTkKJhZ0BtbSPWBwviQtdl64MWJc7sSg9HPvWfTjDigX5ihbzihG8V8aA=\",\"expiry\":\"253402300799000000\"}}}}}"
-    ]
+    ],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "offsetparent-old-behavior",
@@ -831,7 +921,8 @@
       "external/wpt/shadow-dom",
       "fast/dom/shadow"
     ],
-    "args": ["--disable-features=OffsetParentNewSpecBehavior"]
+    "args": ["--disable-features=OffsetParentNewSpecBehavior"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "streaming-declarative-shadow-dom-disabled",
@@ -839,7 +930,8 @@
     "bases": [
       "external/wpt/shadow-dom/declarative"
     ],
-    "args": ["--disable-features=StreamingDeclarativeShadowDOM"]
+    "args": ["--disable-features=StreamingDeclarativeShadowDOM"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "document-domain-disabled-by-default",
@@ -847,13 +939,15 @@
     "bases": [
       "external/wpt/document-policy/experimental-features/document-domain"
     ],
-    "args": [ "--enable-features=DisableDocumentDomainByDefault" ]
+    "args": [ "--enable-features=DisableDocumentDomainByDefault" ],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "backface-visibility-interop",
     "platforms": ["Linux"],
     "bases": [ "external/wpt/css/css-transforms" ],
-    "args": [ "--enable-features=BackfaceVisibilityInterop" ]
+    "args": [ "--enable-features=BackfaceVisibilityInterop" ],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "portals",
@@ -865,13 +959,15 @@
                "http/tests/portals",
                "wpt_internal/portals" ],
     "exclusive_tests": "ALL",
-    "args": [ "--enable-features=Portals,PortalsCrossOrigin" ]
+    "args": [ "--enable-features=Portals,PortalsCrossOrigin" ],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "restrict-gamepad",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": [ "external/wpt/gamepad" ],
-    "args": [ "--enable-features=RestrictGamepadAccess" ]
+    "args": [ "--enable-features=RestrictGamepadAccess" ],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "third-party-storage-partitioning",
@@ -903,25 +999,29 @@
       "http/tests/inspector-protocol/storage/indexed-db-set-items-by-storage-key.js",
       "http/tests/storage/partitioned-storage"
     ],
-    "args": [ "--enable-features=ThirdPartyStoragePartitioning" ]
+    "args": [ "--enable-features=ThirdPartyStoragePartitioning" ],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "post-message-first-party-to-third-party-different-bucket-same-origin-blocked",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/html/browsers/windows/post-message"],
-    "args": ["--enable-features=PostMessageFirstPartyToThirdPartyDifferentBucketSameOriginBlocked"]
+    "args": ["--enable-features=PostMessageFirstPartyToThirdPartyDifferentBucketSameOriginBlocked"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "post-message-third-party-to-first-party-different-bucket-same-origin-blocked",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/html/browsers/windows/post-message"],
-    "args": ["--enable-features=PostMessageThirdPartyToFirstPartyDifferentBucketSameOriginBlocked"]
+    "args": ["--enable-features=PostMessageThirdPartyToFirstPartyDifferentBucketSameOriginBlocked"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "post-message-third-party-to-third-party-different-bucket-same-origin-blocked",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/html/browsers/windows/post-message"],
-    "args": ["--enable-features=PostMessageThirdPartyToThirdPartyDifferentBucketSameOriginBlocked"]
+    "args": ["--enable-features=PostMessageThirdPartyToThirdPartyDifferentBucketSameOriginBlocked"],
+    "expires": "Jul 1, 2023"
   },
 
   "isInputPending requires threaded compositing and layerized iframes",
@@ -931,7 +1031,8 @@
     "bases": ["external/wpt/is-input-pending"],
     "exclusive_tests": "ALL",
     "args": ["--enable-threaded-compositing",
-             "--disable-auto-wpt-origin-isolation"]
+             "--disable-auto-wpt-origin-isolation"],
+    "expires": "Jul 1, 2023"
   },
 
   {
@@ -940,20 +1041,23 @@
     "bases": [ "fast/canvas" ],
     "args": [ "--enable-features=CanvasOopRasterization",
               "--enable-accelerated-2d-canvas",
-              "--enable-gpu-rasterization" ]
+              "--enable-gpu-rasterization" ],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "disable-frequency-capping-for-overlay-popup-detection",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["http/tests/subresource_filter/overlay_popup_ad"],
     "exclusive_tests": "ALL",
-    "args": ["--disable-features=FrequencyCappingForOverlayPopupDetection"]
+    "args": ["--disable-features=FrequencyCappingForOverlayPopupDetection"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "web-app-window-controls-overlay",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/html/webappapis/system-state-and-capabilities/the-navigator-object/navigator-window-controls-overlay.html"],
-    "args": [ "--enable-features=WebAppWindowControlsOverlay"]
+    "args": [ "--enable-features=WebAppWindowControlsOverlay"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "first-party-sets",
@@ -962,7 +1066,8 @@
       "http/tests/inspector-protocol/network",
       "http/tests/inspector-protocol/issues"
     ],
-    "args": ["--use-first-party-set={\"primary\":\"https://firstparty.test\",\"associatedSites\":[\"https://cookie.test\"]}"]
+    "args": ["--use-first-party-set={\"primary\":\"https://firstparty.test\",\"associatedSites\":[\"https://cookie.test\"]}"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "partitioned-cookies",
@@ -971,7 +1076,8 @@
               "external/wpt/html/anonymous-iframe/",
               "http/tests/cookies/partitioned-cookies",
               "http/tests/inspector-protocol/network/"],
-    "args": ["--enable-features=PartitionedCookies"]
+    "args": ["--enable-features=PartitionedCookies"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "prerender",
@@ -983,14 +1089,16 @@
     "args": [
       "--enable-blink-features=SpeculationRulesReferrerPolicyKey",
       "--enable-features=SameSiteCrossOriginForSpeculationRulesPrerender"
-    ]
+    ],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "no-different-origin-dialogs",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/html/webappapis/user-prompts/cannot-show-simple-dialogs/confirm-different-origin-frame.sub.html",
               "external/wpt/html/webappapis/user-prompts/cannot-show-simple-dialogs/prompt-different-origin-frame.sub.html"],
-    "args": [ "--enable-features=SuppressDifferentOriginSubframeJSDialogs"]
+    "args": [ "--enable-features=SuppressDifferentOriginSubframeJSDialogs"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "force-renderer-accessibility",
@@ -1011,13 +1119,15 @@
               "external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-initially-empty-is-updated.html",
               "editing/text-iterator/auto-expand-details.html",
               "editing/text-iterator/auto-expand-details-shadowdom.html"],
-    "args": ["--force-renderer-accessibility"]
+    "args": ["--force-renderer-accessibility"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "no-alloc-direct-call",
     "platforms": ["Linux"],
     "bases": ["fast/canvas"],
-    "args": ["--enable-fake-no-alloc-direct-call-for-testing"]
+    "args": ["--enable-fake-no-alloc-direct-call-for-testing"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "view-transition",
@@ -1029,7 +1139,8 @@
     "exclusive_tests": "ALL",
     "args": ["--enable-features=ViewTransition",
              "--enable-threaded-compositing",
-             "--enable-gpu-rasterization"]
+             "--enable-gpu-rasterization"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "view-transition-on-navigation",
@@ -1038,7 +1149,8 @@
     "exclusive_tests": "ALL",
     "args": ["--enable-features=ViewTransition,ViewTransitionOnNavigation",
              "--enable-threaded-compositing",
-             "--enable-gpu-rasterization"]
+             "--enable-gpu-rasterization"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "view-transition-wide-gamut",
@@ -1051,25 +1163,29 @@
     "args": ["--enable-features=ViewTransition",
              "--enable-threaded-compositing",
              "--enable-gpu-rasterization",
-             "--force-color-profile=display-p3-d65"]
+             "--force-color-profile=display-p3-d65"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "popover-disabled",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": [],
-    "args": ["--disable-blink-features=HTMLSelectMenuElement,HTMLPopoverAttribute"]
+    "args": ["--disable-blink-features=HTMLSelectMenuElement,HTMLPopoverAttribute"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "object-param-url",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/html/semantics/embedded-content/the-object-element/object-param-url.html"],
-    "args": ["--disable-features=HTMLParamElementUrlSupport"]
+    "args": ["--disable-features=HTMLParamElementUrlSupport"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "parakeet",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/parakeet"],
-    "args": ["--enable-features=InterestGroupStorage,AdInterestGroupAPI,Parakeet"]
+    "args": ["--enable-features=InterestGroupStorage,AdInterestGroupAPI,Parakeet"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "fledge",
@@ -1084,7 +1200,8 @@
     ],
     "args": [
       "--enable-features=InterestGroupStorage,AdInterestGroupAPI,Fledge,PrivacySandboxAdsAPIsOverride,FencedFrames:implementation_type/mparch"
-    ]
+    ],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "automatic-lazy-frame-loading",
@@ -1097,55 +1214,64 @@
     "args": [
       "--enable-features=AutomaticLazyFrameLoadingToEmbeds:timeout/1000,AutomaticLazyFrameLoadingToEmbedUrls:allowed_websites/http%3A%2F%2Fbad3p.test%3A3001%7C%2Fembed,AutomaticLazyFrameLoadingToAds:timeout/5000,DelayAsyncScriptExecution:delay_async_exec_target/cross_site_with_allow_list/delay_async_exec_allow_list/http%3A%2F%2Fbad3p.test",
       "--disable-field-trial-config"
-    ]
+    ],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "automatic-lazy-frame-loading-ads",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": [],
-    "args": ["--enable-features=AutomaticLazyFrameLoadingToAds:timeout/1000"]
+    "args": ["--enable-features=AutomaticLazyFrameLoadingToAds:timeout/1000"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "async-script-scheduling-disabled",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["wpt_internal/async-script-scheduling"],
-    "args": ["--disable-features=DelayAsyncScriptExecution"]
+    "args": ["--disable-features=DelayAsyncScriptExecution"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "async-script-scheduling-apply-to-cross-site-only",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["wpt_internal/async-script-scheduling"],
-    "args": ["--enable-features=DelayAsyncScriptExecution:delay_async_exec_target/cross_site_only"]
+    "args": ["--enable-features=DelayAsyncScriptExecution:delay_async_exec_target/cross_site_only"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "async-script-scheduling-apply-to-allowlist",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["wpt_internal/async-script-scheduling"],
-    "args": ["--enable-features=DelayAsyncScriptExecution:delay_async_exec_target/cross_site_with_allow_list/delay_async_exec_allow_list/http%3A%2F%2Fbad3p.test%7C%2Fwpt_internal%2Fasync-script-scheduling%2Fresources%2Fscript.sub.js"]
+    "args": ["--enable-features=DelayAsyncScriptExecution:delay_async_exec_target/cross_site_with_allow_list/delay_async_exec_allow_list/http%3A%2F%2Fbad3p.test%7C%2Fwpt_internal%2Fasync-script-scheduling%2Fresources%2Fscript.sub.js"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "async-script-scheduling-finished-parsing",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["wpt_internal/async-script-scheduling"],
-    "args": ["--enable-features=DelayAsyncScriptExecution:delay_async_exec_delay_type/finished_parsing"]
+    "args": ["--enable-features=DelayAsyncScriptExecution:delay_async_exec_delay_type/finished_parsing"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "async-script-scheduling-finished-parsing-with-dom-content-loaded-wait-for-async-script",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["wpt_internal/async-script-scheduling"],
-    "args": ["--enable-features=DelayAsyncScriptExecution:delay_async_exec_delay_type/finished_parsing,DOMContentLoadedWaitForAsyncScript"]
+    "args": ["--enable-features=DelayAsyncScriptExecution:delay_async_exec_delay_type/finished_parsing,DOMContentLoadedWaitForAsyncScript"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "async-script-scheduling-first-paint-or-finished-parsing",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["wpt_internal/async-script-scheduling"],
-    "args": ["--enable-features=DelayAsyncScriptExecution:delay_async_exec_delay_type/first_paint_or_finished_parsing"]
+    "args": ["--enable-features=DelayAsyncScriptExecution:delay_async_exec_delay_type/first_paint_or_finished_parsing"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "low-priority-script-loading",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["http/tests/devtools/network/resource-priority.js"],
-    "args": ["--enable-features=LowPriorityScriptLoading"]
+    "args": ["--enable-features=LowPriorityScriptLoading"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "lcp-multiple-updates-per-element",
@@ -1155,7 +1281,8 @@
     ],
     "args": [
       "--enable-features=LCPMultipleUpdatesPerElement"
-    ]
+    ],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "css-highlight-inheritance",
@@ -1166,7 +1293,8 @@
       "external/wpt/css/css-highlight-api",
       "http/tests/inspector-protocol/css/highlight-pseudo-inheritance.js"
     ],
-    "args": ["--enable-blink-features=HighlightInheritance"]
+    "args": ["--enable-blink-features=HighlightInheritance"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "shared-storage-fenced-frame-mparch",
@@ -1183,14 +1311,16 @@
       "wpt_internal/shared_storage",
       "external/wpt/shared-storage"
     ],
-    "args": ["--enable-features=SharedStorageAPI,FencedFrames:implementation_type/mparch,PrivacySandboxAdsAPIsOverride"]
+    "args": ["--enable-features=SharedStorageAPI,FencedFrames:implementation_type/mparch,PrivacySandboxAdsAPIsOverride"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "task-tracking",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["wpt_internal/task-tracking"],
     "exclusive_tests": "ALL",
-    "args": ["--enable-blink-features=UnexposedTaskIds"]
+    "args": ["--enable-blink-features=UnexposedTaskIds"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "fenced-frame-mparch",
@@ -1207,25 +1337,29 @@
       "http/tests/inspector-protocol/fenced-frame"
     ],
     "args": ["--enable-features=FencedFrames:implementation_type/mparch,PrivacySandboxAdsAPIsOverride,SharedStorageAPI,NoncedPartitionedCookies",
-             "--enable-blink-features=FencedFramesAPIChanges"]
+             "--enable-blink-features=FencedFramesAPIChanges"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "cors-non-wildcard-request-headers",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/fetch/api/cors/cors-preflight.any.js"],
-    "args": ["--enable-features=CorsNonWildcardRequestHeadersSupport"]
+    "args": ["--enable-features=CorsNonWildcardRequestHeadersSupport"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "system-color-picker-appearance",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["fast/forms/color-scheme/color/color-picker-appearance.html"],
-    "args": ["--enable-features=SystemColorChooser"]
+    "args": ["--enable-features=SystemColorChooser"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "dark-system-color-picker-appearance",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["fast/forms/color-scheme/color/color-picker-appearance.html"],
-    "args": ["--blink-settings=preferredColorScheme=0", "--enable-features=SystemColorChooser"]
+    "args": ["--blink-settings=preferredColorScheme=0", "--enable-features=SystemColorChooser"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "css-highlight-overlay-painting",
@@ -1239,7 +1373,8 @@
       "paint/markers/inline-spelling-markers-hidpi-composited.html",
       "paint/invalidation/selection/selection-after-remove.html"
     ],
-    "args": ["--enable-blink-features=HighlightOverlayPainting"]
+    "args": ["--enable-blink-features=HighlightOverlayPainting"],
+    "expires": "Jul 1, 2023"
   },
 
   "The following tests never pass in the default Blink test runner due to",
@@ -1252,7 +1387,8 @@
       "external/wpt/html/dom/render-blocking"
     ],
     "exclusive_tests": "ALL",
-    "args": ["--enable-features=NoForcedFrameUpdatesForWebTests"]
+    "args": ["--enable-features=NoForcedFrameUpdatesForWebTests"],
+    "expires": "Jul 1, 2023"
   },
 
   {
@@ -1262,21 +1398,24 @@
     "args": [
       "--enable-features=SystemCursorSizeSupported",
       "--disable-headless-mode"
-    ]
+    ],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "document-pip",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": [],
     "args": ["--enable-features=DocumentPictureInPictureAPI",
-             "--enable-blink-features=DocumentPictureInPictureAPI"]
+             "--enable-blink-features=DocumentPictureInPictureAPI"],
+    "expires": "Jul 1, 2023"
   },
 
   {
     "prefix": "idna-2008",
     "platforms": ["Linux"],
     "bases": [ "external/wpt/url", "fast/url"],
-    "args": ["--enable-features=UseIDNA2008NonTransitional"]
+    "args": ["--enable-features=UseIDNA2008NonTransitional"],
+    "expires": "Jul 1, 2023"
   },
 
   "Tests in the virtual/origin-agent-cluster-default suite. These tests",
@@ -1291,7 +1430,8 @@
     "args": [
       "--enable-features=OriginAgentClusterDefaultWarning",
       "--disable-auto-wpt-origin-isolation"
-    ]
+    ],
+    "expires": "Jul 1, 2023"
   },
 
   {
@@ -1300,7 +1440,8 @@
     "bases": [ "external/wpt/webauthn/remote-desktop-client-override.tentative.https.html" ],
     "args": [
       "--webauthn-remote-desktop-support"
-    ]
+    ],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "mediastreamtrack-transfer",
@@ -1314,13 +1455,15 @@
       "--enable-blink-features=MediaStreamTrackTransfer",
       "--enable-features=MediaStreamTrackTransfer",
       "--use-fake-device-for-media-stream=display-media-type=browser"
-    ]
+    ],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "force-defer-script",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/html/semantics/scripting-1/the-script-element/defer-script/"],
-    "args": ["--enable-features=ForceDeferScriptIntervention"]
+    "args": ["--enable-features=ForceDeferScriptIntervention"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "force-in-order-script",
@@ -1328,7 +1471,8 @@
     "bases": ["wpt_internal/in-order-script-scheduling/force-in-order"],
     "args": [
       "--enable-features=ForceInOrderScript"
-    ]
+    ],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "selective-in-order-script",
@@ -1336,7 +1480,8 @@
     "bases": ["wpt_internal/in-order-script-scheduling/selective-in-order"],
     "args": [
       "--enable-features=SelectiveInOrderScript,SelectiveInOrderScriptTarget:allow_list/http%3A%2F%2Fbad3p.test%7Csync-script-1.js"
-    ]
+    ],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "threaded-preload-scanner",
@@ -1346,19 +1491,22 @@
       "fast/dom/HTMLScriptElement",
       "fast/preloader"
     ],
-    "args": ["--enable-features=ThreadedPreloadScanner,PrecompileInlineScripts"]
+    "args": ["--enable-features=ThreadedPreloadScanner,PrecompileInlineScripts"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "isolate-sandboxed-iframes",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": [ "external/wpt/html/infrastructure/urls/terminology-0/" ],
-    "args": [ "--enable-features=IsolateSandboxedIframes" ]
+    "args": [ "--enable-features=IsolateSandboxedIframes" ],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "coop-restrict-properties",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": [ "external/wpt/html/cross-origin-opener-policy/tentative/restrict-properties" ],
-    "args": [ "--enable-features=CoopRestrictProperties" ]
+    "args": [ "--enable-features=CoopRestrictProperties" ],
+    "expires": "Jul 1, 2023"
   },
 
   "These tests require the experimental speculative prefetch feature, and",
@@ -1377,7 +1525,8 @@
       "--enable-features=SpeculationRulesPrefetchProxy,PrefetchUseContentRefactor",
       "--bypass-prefetch-proxy-for-host=not-web-platform.test",
       "--isolated-prerender-allow-all-domains"
-    ]
+    ],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "sanitizer-api-namespaces",
@@ -1391,13 +1540,15 @@
       "external/wpt/sanitizer-api/sanitizer-names.https.tentative.html",
       "virtual/mathml-disabled/sanitizer-api-math-namespace-designator.html"
     ],
-    "args": ["--enable-features=SanitizerAPINamespacesForTesting"]
+    "args": ["--enable-features=SanitizerAPINamespacesForTesting"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "cookie-reject-domain-non-ascii",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": [ "http/tests/inspector-protocol/issues/cookie-domain-non-ascii.js" ],
-    "args": ["--enable-features=CookieDomainRejectNonASCII"]
+    "args": ["--enable-features=CookieDomainRejectNonASCII"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "pending-beacon",
@@ -1409,7 +1560,8 @@
     "exclusive_tests": "ALL",
     "args": [
       "--enable-features=PendingBeaconAPI:requires_origin_trial/false"
-    ]
+    ],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "pending-beacon-origin-trial",
@@ -1417,7 +1569,8 @@
     "bases": [
       "http/tests/origin_trials/webexposed/pending-beacon-origin-trial-interfaces.html"
     ],
-    "args": ["--enable-features=PendingBeaconAPI:requires_origin_trial/true"]
+    "args": ["--enable-features=PendingBeaconAPI:requires_origin_trial/true"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "pretokenize-css",
@@ -1434,7 +1587,8 @@
       "fast/css/sheet-collection-link.html",
       "fast/encoding/css-charset-default.xhtml"
     ],
-    "args": ["--enable-features=PretokenizeCSS"]
+    "args": ["--enable-features=PretokenizeCSS"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "close-watcher",
@@ -1442,17 +1596,19 @@
     "bases": [
       "external/wpt/close-watcher"
     ],
-    "args": ["--enable-blink-features=CloseWatcher"]
+    "args": ["--enable-blink-features=CloseWatcher"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "orb-v01",
     "platforms": ["Linux"],
-    "args": ["--enable-features=OpaqueResponseBlockingV01"],
     "bases": [
       "external/wpt/fetch/corb",
       "external/wpt/fetch/api",
       "external/wpt/fetch/nosniff"
-    ]
+    ],
+    "args": ["--enable-features=OpaqueResponseBlockingV01"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "orb-v02",
@@ -1460,27 +1616,31 @@
     "args": ["--enable-features=OpaqueResponseBlockingV01,OpaqueResponseBlockingV02"],
     "bases": [
       "external/wpt/fetch/corb"
-    ]
+    ],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "js-shared-memory",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["wpt_internal/js/shared_memory"],
     "exclusive_tests": "ALL",
-    "args": ["--enable-features=JavaScriptExperimentalSharedMemory"]
+    "args": ["--enable-features=JavaScriptExperimentalSharedMemory"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "fedcm-multi-idp",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/credential-management/fedcm-multi-idp/"],
     "exclusive_tests": "ALL",
-    "args": ["--enable-features=FedCmMultipleIdentityProviders"]
+    "args": ["--enable-features=FedCmMultipleIdentityProviders"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "scoped-custom-element-registry-disabled",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/custom-elements/scoped-registry"],
-    "args": ["--disable-blink-features=ScopedCustomElementRegistry"]
+    "args": ["--disable-blink-features=ScopedCustomElementRegistry"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "abort-signal-remove",
@@ -1490,13 +1650,15 @@
       "external/wpt/idle-detection",
       "external/wpt/web-nfc"
     ],
-    "args": ["--disable-features=AbortSignalHandleBasedRemoval"]
+    "args": ["--disable-features=AbortSignalHandleBasedRemoval"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "devtools-tab-target",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["http/tests/devtools/extensions", "http/tests/devtools/tracing", "http/tests/devtools/coverage"],
-    "args": ["--content-shell-devtools-tab-target"]
+    "args": ["--content-shell-devtools-tab-target"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "split-user-media-queues",
@@ -1504,12 +1666,14 @@
     "bases": [
       "external/wpt/mediacapture-streams/parallel-capture-requests.https.html"
     ],
-    "args": ["--enable-features=SplitUserMediaQueues"]
+    "args": ["--enable-features=SplitUserMediaQueues"],
+    "expires": "Jul 1, 2023"
   },
   {
     "prefix": "enable-persistent-origin-trials",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": [ "http/tests/persistent-origin-trials/" ],
-    "args": ["--enable-features=PersistentOriginTrials"]
+    "args": ["--enable-features=PersistentOriginTrials"],
+    "expires": "Jul 1, 2023"
   }
 ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index 9808fec..c16a21a 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -6096,6 +6096,13 @@
         null,
         {}
        ]
+      ],
+      "commitStyles-svg-crash.html": [
+       "7fc1fef9ce27f673ecba0692e9819f47072751bd",
+       [
+        null,
+        {}
+       ]
       ]
      }
     }
@@ -278063,10 +278070,6 @@
       "top-layer-dialog-backdrop-ref.html": [
        "49c46974c9de23284852d302b57b0ad206158d0f",
        []
-      ],
-      "transition-style-change-event-002-expected.txt": [
-       "3b126fc6ba31c414db348249246bae0fdab850c4",
-       []
       ]
      },
      "content-visibility": {
@@ -318892,7 +318895,7 @@
       []
      ],
      "CSSKeyframesRule-expected.txt": [
-      "af8c374f31f50be75dbd4e6ebbf63121ef53103a",
+      "6f222f34264993417ae8259aa48637656b7e4cba",
       []
      ],
      "CSSKeyframesRule.html.ini": [
@@ -331812,18 +331815,6 @@
      "12cf0e36d35303a5936a5a1f0fba87083b219262",
      []
     ],
-    "FileSystemDirectoryHandle-removeEntry.https.any-expected.txt": [
-     "4abcb231b2ff49eff985b75f9aec9252d10b01e7",
-     []
-    ],
-    "FileSystemDirectoryHandle-removeEntry.https.any.js.ini": [
-     "d3bc3cb028d96448174be414bd333ecf0af97abd",
-     []
-    ],
-    "FileSystemDirectoryHandle-removeEntry.https.any.worker-expected.txt": [
-     "4abcb231b2ff49eff985b75f9aec9252d10b01e7",
-     []
-    ],
     "META.yml": [
      "23d7765cdfa39689ef72ae6a0beb15b8b4292ecd",
      []
@@ -331836,10 +331827,6 @@
      "8b99a0140dbfcc1293c19105437d37577fd373db",
      []
     ],
-    "idlharness.https.any.js.ini": [
-     "f05a88d7c65a7c3900d7a8652d069dc435762892",
-     []
-    ],
     "opaque-origin.https.window-expected.txt": [
      "a4f8b49db924c9948f821ab077cf58f3dcb0348b",
      []
@@ -331956,7 +331943,7 @@
       []
      ],
      "FileSystemDirectoryHandle-removeEntry.js": [
-      "108b9135f973faa0cec73bde4cb5e8749ca11f53",
+      "93b03ef6ade2b44b5160dc8e42494b46a63d295f",
       []
      ],
      "FileSystemDirectoryHandle-resolve.js": [
@@ -331984,11 +331971,11 @@
       []
      ],
      "FileSystemWritableFileStream-write.js": [
-      "70ba72f2245d39b414ecd5eac3e59b6ee9efddde",
+      "43c8ec7ca87d39cc96dea7b8557fac272bedafc4",
       []
      ],
      "FileSystemWritableFileStream.js": [
-      "d9c4f35335cd9493397d5c3cd2ded70191cea80f",
+      "53e4fc1f28e4aeddac44df7b0bd4b08ce7a7dccf",
       []
      ]
     }
@@ -445209,7 +445196,7 @@
       ]
      ],
      "CSSKeyframesRule.html": [
-      "7d91127d1e022c35aad79715488eab32d4a37a84",
+      "a1adac383f675c25ee6ac820b21ea0a45a37f4ce",
       [
        null,
        {}
@@ -528187,7 +528174,7 @@
        ]
       ],
       "popover-events.tentative.html": [
-       "2f530d1adea7410083e11823a21693f664361bff",
+       "78d4a22c78e7be447eb1ef007c2ee29e192919b3",
        [
         null,
         {}
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa.https.any-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa.https.any-expected.txt
index 4453f4de..d9c753bc5 100644
--- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa.https.any-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa.https.any-expected.txt
@@ -1,5 +1,7 @@
 This is a testharness.js-based test.
 PASS setup
+PASS Sign and verify using generated Ed25519 keys.
+FAIL Sign and verify using generated Ed448 keys. promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name"
 FAIL importVectorKeys step: EdDSA Ed448 verification assert_unreached: importVectorKeys failed for EdDSA Ed448. Message: ''Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name'' Reached unreachable code
 FAIL importVectorKeys step: EdDSA Ed448 verification with altered signature after call assert_unreached: importVectorKeys failed for EdDSA Ed448. Message: ''Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name'' Reached unreachable code
 FAIL importVectorKeys step: EdDSA Ed448 with altered data after call assert_unreached: importVectorKeys failed for EdDSA Ed448. Message: ''Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name'' Reached unreachable code
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa.https.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa.https.any.worker-expected.txt
index 4453f4de..d9c753bc5 100644
--- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa.https.any.worker-expected.txt
@@ -1,5 +1,7 @@
 This is a testharness.js-based test.
 PASS setup
+PASS Sign and verify using generated Ed25519 keys.
+FAIL Sign and verify using generated Ed448 keys. promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name"
 FAIL importVectorKeys step: EdDSA Ed448 verification assert_unreached: importVectorKeys failed for EdDSA Ed448. Message: ''Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name'' Reached unreachable code
 FAIL importVectorKeys step: EdDSA Ed448 verification with altered signature after call assert_unreached: importVectorKeys failed for EdDSA Ed448. Message: ''Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name'' Reached unreachable code
 FAIL importVectorKeys step: EdDSA Ed448 with altered data after call assert_unreached: importVectorKeys failed for EdDSA Ed448. Message: ''Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name'' Reached unreachable code
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa.js
index 0a2e638..d425fec 100644
--- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa.js
+++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa.js
@@ -354,6 +354,18 @@
           .catch(function() {done();})
   }, "setup");
 
+  // Test that generated keys are valid for signing and verifying.
+  testVectors.forEach(function(vector) {
+      var algorithm = {name: vector.algorithmName};
+      promise_test(async() => {
+          let key = await subtle.generateKey(algorithm, false, ["sign", "verify"]);
+          let signature = await subtle.sign(algorithm, key.privateKey, vector.data);
+          let isVerified = await subtle.verify(algorithm, key.publicKey, signature, vector.data);
+          assert_true(isVerified, "Verificaton failed.");
+      }, "Sign and verify using generated " + vector.algorithmName + " keys.");
+  });
+
+
   // A test vector has all needed fields for signing and verifying, EXCEPT that the
   // key field may be null. This function replaces that null with the Correct
   // CryptoKey object.
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/move-newline-pre-text.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/move-newline-pre-text.html
new file mode 100644
index 0000000..86892a1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/move-newline-pre-text.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1386676">
+<div id="container" style="columns:10; column-fill:auto; height:30px; line-height:20px; orphans:1; widows:1; white-space:pre;">
+  <span id="htmlvar00001"><br><br></span>
+
+</div>
+<script>
+  requestAnimationFrame(()=> {
+    requestAnimationFrame(()=> {
+      document.body.style.color = "blue";
+      htmlvar00001.style.display = "none";
+      requestAnimationFrame(()=> {
+        requestAnimationFrame(()=> {
+          container.style.width = "88%";
+        });
+      });
+    });
+  });
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/CSSKeyframesRule-expected.txt b/third_party/blink/web_tests/external/wpt/css/cssom/CSSKeyframesRule-expected.txt
index af8c374f..6f222f3 100644
--- a/third_party/blink/web_tests/external/wpt/css/cssom/CSSKeyframesRule-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/CSSKeyframesRule-expected.txt
@@ -1,4 +1,5 @@
 This is a testharness.js-based test.
-FAIL CSSOM -  CSSKeyframesRule interface assert_equals: CSSKeyframesRule cssText attribute with CSS-wide keyword name expected "@keyframes\"initial\"{}" but got "@keyframesinitial{}"
+FAIL name, cssRules, appendRule, findRule, deleteRule assert_equals: CSSKeyframesRule cssText attribute with CSS-wide keyword name expected "@keyframes\"initial\"{}" but got "@keyframesinitial{}"
+FAIL indexed getter, length assert_equals: CSSKeyframesRule.length expected (number) 2 but got (undefined) undefined
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/CSSKeyframesRule.html b/third_party/blink/web_tests/external/wpt/css/cssom/CSSKeyframesRule.html
index 7d91127..a1adac38 100644
--- a/third_party/blink/web_tests/external/wpt/css/cssom/CSSKeyframesRule.html
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/CSSKeyframesRule.html
@@ -12,6 +12,10 @@
             100% { top: 200px; }
         }
         @keyframes empty {}
+        @keyframes indexed-access {
+            0% { top: 0px; }
+            100% { top: 200px; }
+        }
     </style>
 
     <script>
@@ -68,7 +72,14 @@
         empty.name = "none";
         assert_equals(empty.name, "none", "CSSKeyframesRule name setter, 'none'");
         assert_equals(empty.cssText.replace(/\s/g, ""), "@keyframes\"none\"{}", "CSSKeyframesRule cssText attribute with 'none' name");
-    });
+    }, 'name, cssRules, appendRule, findRule, deleteRule');
+
+    test(function () {
+        const keyframes = document.styleSheets[0].cssRules[2];
+        assert_equals(keyframes[0].cssText, "0% { top: 0px; }", "CSSKeyframesRule indexed getter [0]");
+        assert_equals(keyframes[1].cssText, "100% { top: 200px; }", "CSSKeyframesRule indexed getter [1]");
+        assert_equals(keyframes.length, 2, "CSSKeyframesRule.length");
+    }, 'indexed getter, length');
     </script>
 </head>
 </html>
diff --git a/third_party/blink/web_tests/images/resources/avif/star-animated-10bpc-with-alpha.avif b/third_party/blink/web_tests/images/resources/avif/star-animated-10bpc-with-alpha.avif
index 05c5a45..087a6096 100644
--- a/third_party/blink/web_tests/images/resources/avif/star-animated-10bpc-with-alpha.avif
+++ b/third_party/blink/web_tests/images/resources/avif/star-animated-10bpc-with-alpha.avif
Binary files differ
diff --git a/third_party/blink/web_tests/images/resources/avif/star-animated-12bpc-with-alpha.avif b/third_party/blink/web_tests/images/resources/avif/star-animated-12bpc-with-alpha.avif
index c6fe1a53..9d93308 100644
--- a/third_party/blink/web_tests/images/resources/avif/star-animated-12bpc-with-alpha.avif
+++ b/third_party/blink/web_tests/images/resources/avif/star-animated-12bpc-with-alpha.avif
Binary files differ
diff --git a/third_party/blink/web_tests/images/resources/avif/star-animated-8bpc-with-alpha.avif b/third_party/blink/web_tests/images/resources/avif/star-animated-8bpc-with-alpha.avif
index bb9dfa5..c92de67 100644
--- a/third_party/blink/web_tests/images/resources/avif/star-animated-8bpc-with-alpha.avif
+++ b/third_party/blink/web_tests/images/resources/avif/star-animated-8bpc-with-alpha.avif
Binary files differ
diff --git a/third_party/nearby/README.chromium b/third_party/nearby/README.chromium
index 72086d7..93317f7 100644
--- a/third_party/nearby/README.chromium
+++ b/third_party/nearby/README.chromium
@@ -1,7 +1,7 @@
 Name: Nearby Connections Library
 Short Name: Nearby
 URL: https://github.com/google/nearby
-Version: b1d1019541a36f32345b6238f09faa21d7e81a3e
+Version: 8679d3a370087b0da2eea508c3dd4892d14536cc
 License: Apache 2.0
 License File: LICENSE
 Security Critical: yes
diff --git a/third_party/webgpu-cts/ts_sources.txt b/third_party/webgpu-cts/ts_sources.txt
index 3b64b3a1..73688ee2 100644
--- a/third_party/webgpu-cts/ts_sources.txt
+++ b/third_party/webgpu-cts/ts_sources.txt
@@ -175,7 +175,7 @@
 src/webgpu/api/operation/render_pipeline/sample_mask.spec.ts
 src/webgpu/api/operation/render_pipeline/vertex_only_render_pipeline.spec.ts
 src/webgpu/api/operation/rendering/basic.spec.ts
-src/webgpu/api/operation/rendering/blending.spec.ts
+src/webgpu/api/operation/rendering/color_target_state.spec.ts
 src/webgpu/api/operation/rendering/depth.spec.ts
 src/webgpu/api/operation/rendering/depth_clip_clamp.spec.ts
 src/webgpu/api/operation/rendering/draw.spec.ts
diff --git a/third_party/wpt_tools/README.chromium b/third_party/wpt_tools/README.chromium
index 53307f3..a8254f0 100644
--- a/third_party/wpt_tools/README.chromium
+++ b/third_party/wpt_tools/README.chromium
@@ -1,7 +1,7 @@
 Name: web-platform-tests - Test Suites for Web Platform specifications
 Short Name: wpt
 URL: https://github.com/web-platform-tests/wpt/
-Version: 89689e140db42a808829cba077ee646f4c9167de
+Version: e40bcdf29002522fbf04e70f7dfd79f0e232dc13
 License: LICENSES FOR W3C TEST SUITES (https://www.w3.org/Consortium/Legal/2008/03-bsd-license.html)
 License File: NOT_SHIPPED
 Security Critical: no
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/firefox.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/firefox.py
index 36ab48a..3e005ef 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/firefox.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/firefox.py
@@ -251,7 +251,7 @@
     # Disable window occlusion. Bug 1733955
     env["MOZ_WINDOW_OCCLUSION"] = "0"
     if chaos_mode_flags is not None:
-        env["MOZ_CHAOSMODE"] = str(chaos_mode_flags)
+        env["MOZ_CHAOSMODE"] = hex(chaos_mode_flags)
     if headless:
         env["MOZ_HEADLESS"] = "1"
     return env
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/firefox_android.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/firefox_android.py
index a909e044..6e41854 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/firefox_android.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/firefox_android.py
@@ -106,7 +106,7 @@
     env["MOZ_DISABLE_NONLOCAL_CONNECTIONS"] = "1"
     env["STYLO_THREADS"] = str(stylo_threads)
     if chaos_mode_flags is not None:
-        env["MOZ_CHAOSMODE"] = str(chaos_mode_flags)
+        env["MOZ_CHAOSMODE"] = hex(chaos_mode_flags)
     return env
 
 
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executorcontentshell.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executorcontentshell.py
index fa72b1e..474bb716 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executorcontentshell.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executorcontentshell.py
@@ -5,7 +5,6 @@
 from time import time
 from queue import Empty
 from base64 import b64encode
-from os import linesep
 import json
 
 
@@ -41,7 +40,7 @@
     https://chromium.googlesource.com/chromium/src.git/+/HEAD/content/web_test/browser/test_info_extractor.h
     """
     name = "content_shell_test"
-    eof_marker = "#EOF" + linesep  # Marker sent by content_shell after blocks.
+    eof_marker = '#EOF\n'  # Marker sent by content_shell after blocks.
 
     def __init__(self, parent):
         super().__init__(parent)
@@ -67,7 +66,7 @@
     def _send_command(self, command):
         """Sends a single `command`, i.e. a URL to open, to content_shell.
         """
-        self.stdin_queue.put((command + linesep).encode("utf-8"))
+        self.stdin_queue.put((command + "\n").encode("utf-8"))
 
     def _read_block(self, deadline=None):
         """Tries to read a single block of content from stdout before the `deadline`.
@@ -95,6 +94,10 @@
             if line.endswith(self.eof_marker):
                 result += line[:-len(self.eof_marker)]
                 break
+            elif line.endswith('#EOF\r\n'):
+                result += line[:-len('#EOF\r\n')]
+                self.logger.warning('Got a CRLF-terminated #EOF - this is a driver bug.')
+                break
 
             result += line
 
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptcommandline.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptcommandline.py
index 22ce801..eec0130 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptcommandline.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptcommandline.py
@@ -333,7 +333,7 @@
                              choices=["always", "fail", "unexpected"], default=None,
                              help="With --reftest-internal, when to take a screenshot")
     gecko_group.add_argument("--chaos", dest="chaos_mode_flags", action="store",
-                             nargs="?", const=0xFFFFFFFF, type=int,
+                             nargs="?", const=0xFFFFFFFF, type=lambda x: int(x, 16),
                              help="Enable chaos mode with the specified feature flag "
                              "(see http://searchfox.org/mozilla-central/source/mfbt/ChaosMode.h for "
                              "details). If no value is supplied, all features are activated")
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index ee40f75..87d914b 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -363,6 +363,7 @@
       'Linux Builder (reclient compare)': 'gpu_tests_release_bot_reclient',
       'Linux CFI (reclient shadow)': 'cfi_full_cfi_icall_cfi_diag_thin_lto_release_static_dcheck_always_on_reclient',
       'Linux ChromiumOS MSan Focal': 'chromeos_msan_focal_release_bot_reclient',
+      'Linux MSan Focal': 'msan_focal_release_bot_reclient',
       'Linux Viz': 'release_trybot_minimal_symbols_reclient',
       # TODO(crbug.com/1260232): remove this after the migration.
       'Mac Builder (reclient compare)': 'gpu_tests_release_bot_minimal_symbols_reclient',
@@ -619,7 +620,7 @@
       'Linux CFI': 'cfi_full_cfi_icall_cfi_diag_thin_lto_release_static_dcheck_always_on_reclient',
       'Linux Chromium OS ASan LSan Builder': 'asan_lsan_chromeos_release_bot_dcheck_always_on_reclient',
       'Linux ChromiumOS MSan Builder': 'chromeos_msan_release_bot_reclient',
-      'Linux MSan Builder': 'msan_focal_release_bot_reclient',
+      'Linux MSan Builder': 'msan_release_bot_reclient',
       'Linux TSan Builder': 'tsan_disable_nacl_release_bot_reclient',
       'Mac ASan 64 Builder': 'asan_minimal_symbols_disable_nacl_release_bot_dcheck_always_on_reclient',
       'WebKit Linux ASAN': 'asan_lsan_release_bot_blink_reclient',
@@ -919,6 +920,7 @@
       'win-chrome': 'official_goma_x86',
       'win-chrome-beta': 'official_goma_x86',
       'win-chrome-stable': 'official_goma_x86',
+      'win-compile-chrome': 'official_goma_x86_minimal_symbols',
       'win-finch-smoke-chrome': 'official_goma',
       'win64-chrome': 'official_goma_x64',
       'win64-chrome-beta': 'official_goma_x64',
@@ -1180,7 +1182,8 @@
       # This is intentionally a release_bot and not a release_trybot;
       # enabling DCHECKs seems to cause flaky failures that don't show up
       # on the continuous builder.
-      'linux_chromium_msan_rel_ng': 'msan_focal_release_bot_reclient',
+      'linux_chromium_msan_focal': 'msan_focal_release_bot_reclient',
+      'linux_chromium_msan_rel_ng': 'msan_release_bot_reclient',
 
       'linux_chromium_tsan_rel_ng': 'tsan_disable_nacl_release_trybot_reclient',
 
@@ -3340,6 +3343,10 @@
       'official', 'goma', 'x86',
     ],
 
+    'official_goma_x86_minimal_symbols': [
+      'official', 'goma', 'x86', 'minimal_symbols',
+    ],
+
     'official_goma_x86_pgo': [
       'official', 'goma', 'x86', 'no_symbols', 'pgo_phase_1', 'release'
     ],
diff --git a/tools/mb/mb_config_expectations/chromium.fyi.json b/tools/mb/mb_config_expectations/chromium.fyi.json
index 7314e6f..7ec8fcf 100644
--- a/tools/mb/mb_config_expectations/chromium.fyi.json
+++ b/tools/mb/mb_config_expectations/chromium.fyi.json
@@ -438,6 +438,17 @@
       "use_remoteexec": true
     }
   },
+  "Linux MSan Focal": {
+    "gn_args": {
+      "dcheck_always_on": false,
+      "instrumented_libraries_release": "focal",
+      "is_component_build": false,
+      "is_debug": false,
+      "is_msan": true,
+      "msan_track_origins": 2,
+      "use_remoteexec": true
+    }
+  },
   "Linux Viz": {
     "gn_args": {
       "dcheck_always_on": true,
diff --git a/tools/mb/mb_config_expectations/chromium.memory.json b/tools/mb/mb_config_expectations/chromium.memory.json
index f026f05..b8ad634 100644
--- a/tools/mb/mb_config_expectations/chromium.memory.json
+++ b/tools/mb/mb_config_expectations/chromium.memory.json
@@ -50,7 +50,7 @@
   "Linux MSan Builder": {
     "gn_args": {
       "dcheck_always_on": false,
-      "instrumented_libraries_release": "focal",
+      "instrumented_libraries_release": "xenial",
       "is_component_build": false,
       "is_debug": false,
       "is_msan": true,
diff --git a/tools/mb/mb_config_expectations/tryserver.chrome.json b/tools/mb/mb_config_expectations/tryserver.chrome.json
index eff0052..0d91a95e 100644
--- a/tools/mb/mb_config_expectations/tryserver.chrome.json
+++ b/tools/mb/mb_config_expectations/tryserver.chrome.json
@@ -444,6 +444,15 @@
       "use_goma": true
     }
   },
+  "win-compile-chrome": {
+    "gn_args": {
+      "is_chrome_branded": true,
+      "is_official_build": true,
+      "symbol_level": 1,
+      "target_cpu": "x86",
+      "use_goma": true
+    }
+  },
   "win-finch-smoke-chrome": {
     "gn_args": {
       "is_chrome_branded": true,
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.linux.json b/tools/mb/mb_config_expectations/tryserver.chromium.linux.json
index 9fbf21b..62af472 100644
--- a/tools/mb/mb_config_expectations/tryserver.chromium.linux.json
+++ b/tools/mb/mb_config_expectations/tryserver.chromium.linux.json
@@ -682,7 +682,7 @@
       "use_remoteexec": true
     }
   },
-  "linux_chromium_msan_rel_ng": {
+  "linux_chromium_msan_focal": {
     "gn_args": {
       "dcheck_always_on": false,
       "instrumented_libraries_release": "focal",
@@ -693,6 +693,17 @@
       "use_remoteexec": true
     }
   },
+  "linux_chromium_msan_rel_ng": {
+    "gn_args": {
+      "dcheck_always_on": false,
+      "instrumented_libraries_release": "xenial",
+      "is_component_build": false,
+      "is_debug": false,
+      "is_msan": true,
+      "msan_track_origins": 2,
+      "use_remoteexec": true
+    }
+  },
   "linux_chromium_tsan_rel_ng": {
     "gn_args": {
       "dcheck_always_on": true,
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index b89c2737..8ab0573e 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -67312,36 +67312,6 @@
   <int value="5" label="Play/Pause"/>
 </enum>
 
-<enum name="MediaHistoryInitResult">
-  <int value="0" label="Success"/>
-  <int value="1" label="Failed due to no foreign key support"/>
-  <int value="2" label="Failed since database is too new"/>
-  <int value="3" label="Failed to create tables"/>
-  <int value="4" label="Failed to create directory"/>
-  <int value="5" label="Failed to open database"/>
-  <int value="6" label="Failed to establish DB transaction"/>
-  <int value="7" label="Failed to create meta table"/>
-  <int value="8" label="Failed to commit DB transaction"/>
-  <int value="9" label="Failed to delete old database (history clearing)"/>
-</enum>
-
-<enum name="MediaHistoryPlaybackWriteResult">
-  <int value="0" label="Success"/>
-  <int value="1" label="Failed to establish DB transaction"/>
-  <int value="2" label="Failed to write origin"/>
-  <int value="3" label="Failed to write playback"/>
-  <int value="4" label="Failed to increment aggregated watchtime"/>
-  <int value="5" label="Failed to store playback due to bad origin"/>
-</enum>
-
-<enum name="MediaHistorySessionWriteResult">
-  <int value="0" label="Success"/>
-  <int value="1" label="Failed to establish DB transaction"/>
-  <int value="2" label="Failed to write origin"/>
-  <int value="3" label="Failed to write session"/>
-  <int value="4" label="Failed to write image"/>
-</enum>
-
 <enum name="MediaKeyError">
   <int value="1" label="kUnknownError"/>
   <int value="2" label="kClientError"/>
@@ -92651,26 +92621,6 @@
   <int value="75" label="DMToken deletion succeeded."/>
 </enum>
 
-<enum name="SetupInstallServiceInstallResult">
-  <int value="0" label="Failed fresh install of service."/>
-  <int value="1" label="Failed install new service after upgrade failed."/>
-  <int value="2" label="Failed to open the SC manager."/>
-  <int value="3" label="Succeeded change service config."/>
-  <int value="4" label="Succeeded fresh install of service."/>
-  <int value="5" label="Succeeded install new and delete original service."/>
-  <int value="6"
-      label="Succeeded install new but failed delete original service."/>
-  <int value="7"
-      label="Succeeded, service correctly configured, nothing to be done."/>
-</enum>
-
-<enum name="SetupInstallServiceRollbackResult">
-  <int value="0" label="Failed to delete the currently installed service."/>
-  <int value="1" label="Failed to rollback to the original service config."/>
-  <int value="2" label="Succeeded deleting the currently installed service."/>
-  <int value="3" label="Succeeded rollback to the original service config."/>
-</enum>
-
 <enum name="SetupSingletonAcquisitionResult">
   <int value="0" label="The setup singleton was acquired successfully."/>
   <int value="1" label="Acquisition of the exit event mutex timed out."/>
diff --git a/tools/metrics/histograms/metadata/accessibility/histograms.xml b/tools/metrics/histograms/metadata/accessibility/histograms.xml
index d1dd0e8d..031e247 100644
--- a/tools/metrics/histograms/metadata/accessibility/histograms.xml
+++ b/tools/metrics/histograms/metadata/accessibility/histograms.xml
@@ -1683,7 +1683,7 @@
 </histogram>
 
 <histogram name="Accessibility.Reliability.Tree.UnserializeError"
-    enum="AccessibilityTreeUnserializeError" expires_after="2022-11-18">
+    enum="AccessibilityTreeUnserializeError" expires_after="2023-04-23">
   <owner>aleventhal@chromium.org</owner>
   <owner>janewman@microsoft.com</owner>
   <owner>chrome-a11y-core@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/apps/histograms.xml b/tools/metrics/histograms/metadata/apps/histograms.xml
index 4ca2823..3bbdd4d2 100644
--- a/tools/metrics/histograms/metadata/apps/histograms.xml
+++ b/tools/metrics/histograms/metadata/apps/histograms.xml
@@ -2418,7 +2418,7 @@
 </histogram>
 
 <histogram name="Apps.NoteTakingApp.DefaultLaunchResult"
-    enum="NoteTakingAppLaunchResult" expires_after="2022-12-01">
+    enum="NoteTakingAppLaunchResult" expires_after="2023-06-01">
   <owner>glenrob@chromium.org</owner>
   <owner>tbuckley@chromium.org</owner>
   <summary>
@@ -2428,7 +2428,7 @@
 </histogram>
 
 <histogram name="Apps.NoteTakingApp.PreferredLaunchResult"
-    enum="NoteTakingAppLaunchResult" expires_after="2023-02-19">
+    enum="NoteTakingAppLaunchResult" expires_after="2023-06-01">
   <owner>glenrob@chromium.org</owner>
   <owner>tbuckley@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/browser/histograms.xml b/tools/metrics/histograms/metadata/browser/histograms.xml
index 4a06b7f..f5e4b21 100644
--- a/tools/metrics/histograms/metadata/browser/histograms.xml
+++ b/tools/metrics/histograms/metadata/browser/histograms.xml
@@ -139,6 +139,18 @@
   </summary>
 </histogram>
 
+<histogram name="Browser.ERP.EventEnqueueResult"
+    enum="EnterpriseCloudReportingStatusCode" expires_after="2023-11-17">
+  <owner>lbaraz@chromium.org</owner>
+  <owner>xuhong@chromium.org</owner>
+  <owner>src/components/reporting/OWNERS</owner>
+  <summary>
+    Recorded when ReportQueue::Enqueue is called to post an event to ERP. It
+    counts occurrences of the call returning success or each possible error
+    Status.
+  </summary>
+</histogram>
+
 <histogram name="Browser.ERP.EventUploadSizeAdjustment.{Param}" units="bytes"
     expires_after="2023-06-30">
   <owner>xuhong@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/chromeos/histograms.xml b/tools/metrics/histograms/metadata/chromeos/histograms.xml
index 3059a74..e72f045 100644
--- a/tools/metrics/histograms/metadata/chromeos/histograms.xml
+++ b/tools/metrics/histograms/metadata/chromeos/histograms.xml
@@ -2256,7 +2256,7 @@
 
 <histogram
     name="ChromeOS.USB.ExternalDeviceAttached.{USBDeviceRecognized}.{USBDeviceClass}"
-    enum="ChromeOSUsbEventTiming" expires_after="2022-12-31">
+    enum="ChromeOSUsbEventTiming" expires_after="2023-09-30">
   <owner>wonchung@google.com</owner>
   <owner>allenwebb@chromium.org</owner>
   <owner>chromeos-usb@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/content/histograms.xml b/tools/metrics/histograms/metadata/content/histograms.xml
index 5806bb5..21d7291 100644
--- a/tools/metrics/histograms/metadata/content/histograms.xml
+++ b/tools/metrics/histograms/metadata/content/histograms.xml
@@ -257,7 +257,10 @@
 
 <histogram name="ContentSettings.ImagePressed" enum="ContentSettingImageType"
     expires_after="2021-02-01">
-  <owner>calamity@chromium.org</owner>
+  <obsolete>
+    Removed in Nov 2022.
+  </obsolete>
+  <owner>alancutter@chromium.org</owner>
   <owner>src/chrome/browser/ui/page_action/OWNERS</owner>
   <summary>
     Counts which content setting buttons are pressed by the user.
@@ -936,7 +939,7 @@
 </histogram>
 
 <histogram name="ContentSuggestions.Feed.BrokenNTPHierarchy"
-    enum="NTPBrokenViewHierarchyRelationship" expires_after="M107">
+    enum="NTPBrokenViewHierarchyRelationship" expires_after="M115">
   <owner>adamta@google.com</owner>
   <owner>sczs@chromium.org</owner>
   <owner>feed@chromium.org</owner>
@@ -2056,6 +2059,20 @@
   </token>
 </histogram>
 
+<histogram name="ContentSuggestions.{FeedType}.CardIndexOnSwitch" units="index"
+    expires_after="2023-04-21">
+  <owner>adamta@google.com</owner>
+  <owner>feed@chromium.org</owner>
+  <summary>
+    iOS: Before switching to a new feed type, logs the index of the last visible
+    card.
+  </summary>
+  <token key="FeedType">
+    <variant name="Feed" summary="For-You Feed"/>
+    <variant name="Feed.WebFeed" summary="Web Feed"/>
+  </token>
+</histogram>
+
 <histogram name="ContentSuggestions.{FeedType}.EngagementType"
     enum="FeedEngagementType" expires_after="never">
 <!-- expires-never: key feature metric.  We will need the Engagement
diff --git a/tools/metrics/histograms/metadata/custom_tabs/histograms.xml b/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
index 294bca1b..d26727f 100644
--- a/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
+++ b/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
@@ -518,6 +518,33 @@
   </summary>
 </histogram>
 
+<histogram name="CustomTabs.TabCounts.OnClosingAllTabs" units="count"
+    expires_after="2023-02-17">
+  <owner>wenyufu@chromium.org</owner>
+  <owner>chrome-connective-tissue@google.com</owner>
+  <summary>
+    Recorded only for Android. Records the number of tabs closed when closing
+    all the tabs (e.g. via hitting the close button). Only recorded when closing
+    is initiated by the user, so if custom tab is killed while in the background
+    this will not be recorded.
+  </summary>
+</histogram>
+
+<histogram name="CustomTabs.TabCounts.UniqueTabsSeen" units="count"
+    expires_after="2023-02-17">
+  <owner>wenyufu@chromium.org</owner>
+  <owner>chrome-connective-tissue@google.com</owner>
+  <summary>
+    Recorded only for Android. Records the number of unique tabs open in the
+    current custom tab session, when a new tab is opened. The count of this
+    histogram includes the initial tab being opened, and can be recorded more
+    than once in the same session.
+
+    Do not record nor increase the count when switching into the previous tab
+    (e.g. create new tab, close, and land onto an existing tab).
+  </summary>
+</histogram>
+
 <histogram name="CustomTabs.Visible" enum="VisibleTab" expires_after="never">
 <!-- expires-never: Used to classify UMA reports by the dashboards. -->
 
diff --git a/tools/metrics/histograms/metadata/histogram_suffixes_list.xml b/tools/metrics/histograms/metadata/histogram_suffixes_list.xml
index 721f586..1256000b6 100644
--- a/tools/metrics/histograms/metadata/histogram_suffixes_list.xml
+++ b/tools/metrics/histograms/metadata/histogram_suffixes_list.xml
@@ -5904,14 +5904,6 @@
   <affected-histogram name="SettingsResetPrompt.ResetState"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="SetupInstallWin32Apis" separator=".">
-  <suffix name="ChangeServiceConfig" label=""/>
-  <suffix name="CreateService" label=""/>
-  <suffix name="DeleteService" label=""/>
-  <suffix name="OpenSCManager" label=""/>
-  <affected-histogram name="Setup.Install.Win32ApiError"/>
-</histogram_suffixes>
-
 <histogram_suffixes name="SharingChannelType" separator=".">
   <suffix name="FcmSenderId" label="FCM Sender ID"/>
   <suffix name="FcmVapid" label="FCM VAPID"/>
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml
index cf4dda04..af4e9d4 100644
--- a/tools/metrics/histograms/metadata/media/histograms.xml
+++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -3041,63 +3041,6 @@
   </summary>
 </histogram>
 
-<histogram name="Media.History.DatabaseSize" units="KB"
-    expires_after="2021-08-09">
-  <owner>beccahughes@chromium.org</owner>
-  <owner>media-dev@chromium.org</owner>
-  <summary>
-    The size of the Media History database. Recorded once on startup.
-  </summary>
-</histogram>
-
-<histogram name="Media.History.Init.Result" enum="MediaHistoryInitResult"
-    expires_after="2021-08-09">
-  <owner>beccahughes@chromium.org</owner>
-  <owner>media-dev@chromium.org</owner>
-  <summary>
-    Recorded when Media History is initialized when the browser is started. This
-    is not recorded in incognito mode or if &quot;save browsing history&quot; is
-    disabled.
-  </summary>
-</histogram>
-
-<histogram name="Media.History.Init.ResultAfterDelete"
-    enum="MediaHistoryInitResult" expires_after="2021-08-09">
-  <owner>beccahughes@chromium.org</owner>
-  <owner>media-dev@chromium.org</owner>
-  <summary>
-    Recorded when Media History is recreated when the browser is started and the
-    Media History database has been corrupted to the point where we need to
-    delete it and start again. This is not recorded in incognito mode or if
-    &quot;save browsing history&quot; is disabled.
-  </summary>
-</histogram>
-
-<histogram name="Media.History.Playback.WriteResult"
-    enum="MediaHistoryPlaybackWriteResult" expires_after="2021-03-07">
-  <owner>beccahughes@chromium.org</owner>
-  <owner>media-dev@chromium.org</owner>
-  <summary>
-    Recorded when Media History records a playback to the database. Playbacks
-    are recorded when the player is destroyed and are are recorded on a
-    per-player level and might be called multiple times on a single page.
-    Playbacks are not recorded in incognito mode or if &quot;save browsing
-    history&quot; is disabled.
-  </summary>
-</histogram>
-
-<histogram name="Media.History.Session.WriteResult"
-    enum="MediaHistorySessionWriteResult" expires_after="2021-03-07">
-  <owner>beccahughes@chromium.org</owner>
-  <owner>media-dev@chromium.org</owner>
-  <summary>
-    Recorded when Media History records a sessions to the database. Sessions are
-    recorded once per WebContents on navigation if there was playback on the
-    page. Playbacks are not recorded in incognito mode or if &quot;save browsing
-    history&quot; is disabled.
-  </summary>
-</histogram>
-
 <histogram base="true" name="Media.InitialDecoderSelectionTime" units="ms"
     expires_after="2023-03-25">
   <owner>cassew@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml
index d9c3658..9ff0f4e 100644
--- a/tools/metrics/histograms/metadata/net/histograms.xml
+++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -4855,7 +4855,7 @@
 </histogram>
 
 <histogram name="Net.SSLRenegotiationInfoSupported" enum="BooleanSupported"
-    expires_after="2022-12-31">
+    expires_after="2023-11-20">
   <owner>davidben@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/network/histograms.xml b/tools/metrics/histograms/metadata/network/histograms.xml
index 21baf2c..9fcf4ac 100644
--- a/tools/metrics/histograms/metadata/network/histograms.xml
+++ b/tools/metrics/histograms/metadata/network/histograms.xml
@@ -167,7 +167,7 @@
 </histogram>
 
 <histogram name="Network.Ash.VPN.{VPNProviderType}.ConfigurationSource"
-    enum="VPNConfigurationSource" expires_after="2022-12-31">
+    enum="VPNConfigurationSource" expires_after="2023-12-31">
   <owner>chadduffin@chromium.org</owner>
   <owner>cros-connectivity@google.com</owner>
   <summary>
@@ -1137,7 +1137,7 @@
 </histogram>
 
 <histogram name="Network.DnsProxy.DnsOverHttpsQuery.HttpErrors"
-    enum="DnsProxy.HttpError" expires_after="2023-03-05">
+    enum="DnsProxy.HttpError" expires_after="2023-05-07">
   <owner>garrick@chromium.org</owner>
   <owner>cros-network-metrics@google.com</owner>
   <summary>
@@ -1159,7 +1159,7 @@
 </histogram>
 
 <histogram name="Network.DnsProxy.Query.Failed{Stage}Duration" units="ms"
-    expires_after="2022-12-31">
+    expires_after="2023-05-07">
   <owner>garrick@chromium.org</owner>
   <owner>cros-network-metrics@google.com</owner>
   <summary>
@@ -1195,7 +1195,7 @@
 </histogram>
 
 <histogram name="Network.DnsProxy.Query.{Stage}Duration" units="ms"
-    expires_after="2022-12-31">
+    expires_after="2023-05-07">
   <owner>garrick@chromium.org</owner>
   <owner>cros-network-metrics@google.com</owner>
   <summary>
@@ -1231,7 +1231,7 @@
 </histogram>
 
 <histogram name="Network.DnsProxy.{Family}Nameservers" units="units"
-    expires_after="2022-12-31">
+    expires_after="2023-05-07">
   <owner>garrick@chromium.org</owner>
   <owner>cros-network-metrics@google.com</owner>
   <summary>
@@ -1246,7 +1246,7 @@
 </histogram>
 
 <histogram name="Network.DnsProxy.{ProcessType}.Event"
-    enum="DnsProxy.ProcessEvent" expires_after="2022-12-31">
+    enum="DnsProxy.ProcessEvent" expires_after="2023-05-07">
   <owner>garrick@chromium.org</owner>
   <owner>cros-network-metrics@google.com</owner>
   <summary>
@@ -1264,7 +1264,7 @@
 </histogram>
 
 <histogram name="Network.DnsProxy.{Type}Query.Errors"
-    enum="DnsProxy.QueryError" expires_after="2022-12-31">
+    enum="DnsProxy.QueryError" expires_after="2023-05-07">
   <owner>garrick@chromium.org</owner>
   <owner>cros-network-metrics@google.com</owner>
   <summary>
@@ -1279,7 +1279,7 @@
 </histogram>
 
 <histogram name="Network.DnsProxy.{Type}Query.FailedResolveDuration" units="ms"
-    expires_after="2022-12-31">
+    expires_after="2023-05-07">
   <owner>garrick@chromium.org</owner>
   <owner>cros-network-metrics@google.com</owner>
   <summary>
@@ -1300,7 +1300,7 @@
 </histogram>
 
 <histogram name="Network.DnsProxy.{Type}Query.ResolveDuration" units="ms"
-    expires_after="2022-12-31">
+    expires_after="2023-05-07">
   <owner>garrick@chromium.org</owner>
   <owner>cros-network-metrics@google.com</owner>
   <summary>
@@ -1321,7 +1321,7 @@
 </histogram>
 
 <histogram name="Network.DnsProxy.{Type}Query.Results"
-    enum="DnsProxy.QueryResult" expires_after="2022-12-31">
+    enum="DnsProxy.QueryResult" expires_after="2023-05-07">
   <owner>garrick@chromium.org</owner>
   <owner>cros-network-metrics@google.com</owner>
   <summary>
@@ -1336,7 +1336,7 @@
 </histogram>
 
 <histogram name="Network.DnsProxy.{Type}Query.ResultsWithRetries"
-    enum="DnsProxy.QueryResult" expires_after="2022-12-31">
+    enum="DnsProxy.QueryResult" expires_after="2023-05-07">
   <owner>garrick@chromium.org</owner>
   <owner>cros-network-metrics@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml
index 3db37be..2c1f94f 100644
--- a/tools/metrics/histograms/metadata/others/histograms.xml
+++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -7324,7 +7324,10 @@
 
 <histogram name="HostedAppFrame.ContentSettings.ImagePressed"
     enum="ContentSettingImageType" expires_after="2021-02-01">
-  <owner>calamity@chromium.org</owner>
+  <obsolete>
+    Removed in Nov 2022.
+  </obsolete>
+  <owner>alancutter@chromium.org</owner>
   <owner>src/chrome/browser/ui/page_action/OWNERS</owner>
   <summary>
     Counts which content setting buttons in the hosted app frame are pressed by
@@ -12844,34 +12847,6 @@
   </summary>
 </histogram>
 
-<histogram name="Setup.Install.ServiceInstallResult"
-    enum="SetupInstallServiceInstallResult" expires_after="2020-12-30">
-  <owner>ganesh@chromium.org</owner>
-  <owner>sorin@chromium.org</owner>
-  <owner>xiaolingbao@chromium.org</owner>
-  <summary>The outcome of attempting to install a service on Windows.</summary>
-</histogram>
-
-<histogram name="Setup.Install.ServiceRollbackResult"
-    enum="SetupInstallServiceRollbackResult" expires_after="2020-12-30">
-  <owner>ganesh@chromium.org</owner>
-  <owner>sorin@chromium.org</owner>
-  <owner>xiaolingbao@chromium.org</owner>
-  <summary>
-    The outcome of attempting to rollback an install of a service on Windows.
-  </summary>
-</histogram>
-
-<histogram base="true" name="Setup.Install.Win32ApiError"
-    enum="WinGetLastError" expires_after="2020-12-30">
-<!-- Name completed by histogram_suffixes name="SetupInstallWin32Apis". -->
-
-  <owner>ganesh@chromium.org</owner>
-  <owner>sorin@chromium.org</owner>
-  <owner>xiaolingbao@chromium.org</owner>
-  <summary>Win32 APIs that error out during setup.</summary>
-</histogram>
-
 <histogram name="SharedMemory.MapBlockedForSecurity" enum="BooleanBlocked"
     expires_after="M85">
   <obsolete>
diff --git a/tools/metrics/histograms/metadata/power/histograms.xml b/tools/metrics/histograms/metadata/power/histograms.xml
index b2c2f743..6471604b 100644
--- a/tools/metrics/histograms/metadata/power/histograms.xml
+++ b/tools/metrics/histograms/metadata/power/histograms.xml
@@ -813,18 +813,6 @@
   </summary>
 </histogram>
 
-<histogram name="Power.BatteryDischargeMode2{UsageScenario}"
-    enum="BatteryDischargeMode" expires_after="2023-03-31">
-  <owner>etiennep@chromium.org</owner>
-  <owner>olivierli@chromium.org</owner>
-  <summary>
-    Battery discharge mode describing whether BatteryDischargeRate2 could be
-    reported or not, and why. This is recorded every 2 minutes for
-    {UsageScenario} (see go/chrome_power_use_per_scenario).
-  </summary>
-  <token key="UsageScenario" variants="UsageScenario"/>
-</histogram>
-
 <histogram name="Power.BatteryDischargeMode5{UsageScenario}{IntervalType}"
     enum="BatteryDischargeMode" expires_after="2023-03-31">
   <owner>etiennep@chromium.org</owner>
@@ -841,11 +829,6 @@
     This is recorded for {UsageScenario}.
 
     This contains {IntervalType}.
-
-    There are 2 differences with Power.BatteryDischargeRate2. 1: When possible,
-    the intervals are aligned with battery discharge notifications from the OS
-    (MacOS only for now), and 2: Intervals represents only 1 minute of Chrome
-    runtime (as opposed to 2 minutes).
   </summary>
   <token key="UsageScenario" variants="UsageScenario"/>
   <token key="IntervalType" variants="IntervalType"/>
@@ -861,23 +844,6 @@
   </summary>
 </histogram>
 
-<histogram name="Power.BatteryDischargeRate2{UsageScenario}"
-    units="hundredth of percent" expires_after="2023-03-31">
-  <owner>etiennep@chromium.org</owner>
-  <owner>olivierli@chromium.org</owner>
-  <owner>lgrey@chromium.org</owner>
-  <summary>
-    Battery discharge rate per minute, with 1/10000 of full charge resolution,
-    example: - Battery capacity = 4000 mAh; - Battery charge at the beginning of
-    the interval: 3900 mAh; - Battery charge at the end of the interval: 3700
-    mAh; - Discharge proportion: (3900-3700) / 4000 = 0.05 - Reported value:
-    500. This metric is only recorded when on battery power. This is reported on
-    Mac and Windows. This is recorded every 2 minutes for {UsageScenario} (see
-    go/chrome_power_use_per_scenario).
-  </summary>
-  <token key="UsageScenario" variants="UsageScenario"/>
-</histogram>
-
 <histogram
     name="Power.BatteryDischargeRateMilliwatts5{UsageScenario}{IntervalType}"
     units="milliwatts" expires_after="2023-03-31">
@@ -897,12 +863,6 @@
     This is recorded for {UsageScenario}.
 
     This contains {IntervalType}.
-
-    There are 3 differences with Power.BatteryDischargeRate2. 1: When possible,
-    the intervals are aligned with battery discharge notifications from the OS
-    (MacOS only for now), 2: Intervals represents only 1 minute of Chrome
-    runtime (as opposed to 2 minutes), and 3: The discharge rate is emitted in
-    milliwatts instead of hundredth of a percent.
   </summary>
   <token key="UsageScenario" variants="UsageScenario"/>
   <token key="IntervalType" variants="IntervalType"/>
@@ -929,11 +889,6 @@
     This is recorded for {UsageScenario}.
 
     This contains {IntervalType}.
-
-    There are 2 differences with Power.BatteryDischargeRate2. 1: When possible,
-    the intervals are aligned with battery discharge notifications from the OS
-    (MacOS only for now), and 2: Intervals represents only 1 minute of Chrome
-    runtime (as opposed to 2 minutes).
   </summary>
   <token key="UsageScenario" variants="UsageScenario"/>
   <token key="IntervalType" variants="IntervalType"/>
diff --git a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
index 201fbd3b..4b0105a9 100644
--- a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
+++ b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
@@ -903,7 +903,7 @@
 
 <histogram
     name="SafeBrowsing.NavigationObserver.DroppedReferrerChainEntries.ClientRedirect"
-    units="units" expires_after="2022-11-27">
+    units="units" expires_after="2023-10-27">
   <owner>drubery@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/service/histograms.xml b/tools/metrics/histograms/metadata/service/histograms.xml
index 42fc951..9aa0331 100644
--- a/tools/metrics/histograms/metadata/service/histograms.xml
+++ b/tools/metrics/histograms/metadata/service/histograms.xml
@@ -1215,7 +1215,7 @@
 </histogram>
 
 <histogram name="ServiceWorker.Storage.RetryCountForRecovery" units="retries"
-    expires_after="2023-01-04">
+    expires_after="2023-06-30">
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
diff --git a/tools/perf/benchmark.csv b/tools/perf/benchmark.csv
index 5fa6706..595089ddb 100644
--- a/tools/perf/benchmark.csv
+++ b/tools/perf/benchmark.csv
@@ -3,6 +3,7 @@
 Googlers can view additional information about internal perf infrastructure at,https://goto.google.com/chrome-benchmarking-sheet
 Benchmark name,Individual owners,Component,Documentation,Tags
 UNSCHEDULED_ad_frames.iframe,lbrady@google.com,Blink>FencedFrames,https://tinyurl.com/fenced-frame-benchmark,
+UNSCHEDULED_blink_perf.base64,csharrison@chromium.org,Blink>Internals>WTF,https://bit.ly/blink-perf-benchmarks,all
 UNSCHEDULED_blink_perf.performance_apis,yoavweiss@chromium.org,Blink>PerformanceAPIs,https://bit.ly/blink-perf-benchmarks,all
 UNSCHEDULED_blink_perf.service_worker,"shimazu@chromium.org, falken@chromium.org, ting.shao@intel.com",Blink>ServiceWorker,https://bit.ly/blink-perf-benchmarks,
 UNSCHEDULED_loading.mbi,blink-isolation-dev@chromium.org,Blink>Internals>Modularization,https://bit.ly/loading-benchmarks,many_agents
diff --git a/tools/perf/benchmarks/blink_perf.py b/tools/perf/benchmarks/blink_perf.py
index 4835edd..2cd9ce0 100644
--- a/tools/perf/benchmarks/blink_perf.py
+++ b/tools/perf/benchmarks/blink_perf.py
@@ -511,6 +511,18 @@
     return story_set
 
 
+@benchmark.Info(emails=['csharrison@chromium.org'],
+                component='Blink>Internals>WTF',
+                documentation_url='https://bit.ly/blink-perf-benchmarks')
+class BlinkPerfBase64(_BlinkPerfBenchmark):
+  SUBDIR = 'base64'
+  TAGS = _BlinkPerfBenchmark.TAGS + ['all']
+
+  @classmethod
+  def Name(cls):
+    return 'UNSCHEDULED_blink_perf.base64'
+
+
 @benchmark.Info(emails=['futhark@chromium.org', 'andruud@chromium.org'],
                 documentation_url='https://bit.ly/blink-perf-benchmarks',
                 component='Blink>CSS')
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index cbe6e1a..47da7fb 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,24 +5,24 @@
             "full_remote_path": "perfetto-luci-artifacts/v31.0/linux-arm64/trace_processor_shell"
         },
         "win": {
-            "hash": "2710fe3acd46370f2ff4d4634db0d783f44121a2",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/d8f0dc3d20c814236d97a042f06ffacd8f2d6b1f/trace_processor_shell.exe"
+            "hash": "e1749ec3ccf342d82cacfa512d84004106af46dd",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/ceec2c49ed86f6b95053262513f3171948a560bc/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "6373f26144aad58f230d11d6a91efda5a09c9873",
             "full_remote_path": "perfetto-luci-artifacts/v31.0/linux-arm/trace_processor_shell"
         },
         "mac": {
-            "hash": "0692cf90a8a019c0fb2a77426517793a197313b7",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/d8f0dc3d20c814236d97a042f06ffacd8f2d6b1f/trace_processor_shell"
+            "hash": "e7f28beaaa5fdb8f367181931079f5f4d20213a4",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/f5b6c4ed868219aefe172ac2d5bd683814a5f001/trace_processor_shell"
         },
         "mac_arm64": {
             "hash": "5f47ee79e59d00bf3889d30ca52315522c158040",
             "full_remote_path": "perfetto-luci-artifacts/v31.0/mac-arm64/trace_processor_shell"
         },
         "linux": {
-            "hash": "4bc08289d402692530fea7363630f5914fda63b5",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/f5b6c4ed868219aefe172ac2d5bd683814a5f001/trace_processor_shell"
+            "hash": "48b8b37f81f733ff0f92d5322fa94700065e336c",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/ceec2c49ed86f6b95053262513f3171948a560bc/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/ui/android/java/src/org/chromium/ui/KeyboardVisibilityDelegate.java b/ui/android/java/src/org/chromium/ui/KeyboardVisibilityDelegate.java
index 670c733..45d7057 100644
--- a/ui/android/java/src/org/chromium/ui/KeyboardVisibilityDelegate.java
+++ b/ui/android/java/src/org/chromium/ui/KeyboardVisibilityDelegate.java
@@ -7,7 +7,6 @@
 import android.annotation.SuppressLint;
 import android.content.Context;
 import android.graphics.Rect;
-import android.os.Build;
 import android.os.Handler;
 import android.os.StrictMode;
 import android.view.View;
@@ -16,6 +15,7 @@
 
 import org.chromium.base.Log;
 import org.chromium.base.ObserverList;
+import org.chromium.base.TraceEvent;
 
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -32,9 +32,6 @@
     /** Waiting time between attempts to show the keyboard. */
     private static final long KEYBOARD_RETRY_DELAY_MS = 100;
 
-    /** The minimum size of the bottom margin below the app to detect a keyboard. */
-    private static final float KEYBOARD_DETECT_BOTTOM_THRESHOLD_DP = 100;
-
     /** The delegate to determine keyboard visibility. */
     private static KeyboardVisibilityDelegate sInstance = new KeyboardVisibilityDelegate();
 
@@ -142,50 +139,25 @@
      * @return The size of the bottom margin which most likely is exactly the keyboard size.
      */
     public int calculateKeyboardHeight(View rootView) {
-        Rect appRect = new Rect();
-        rootView.getWindowVisibleDisplayFrame(appRect);
+        try (TraceEvent te =
+                        TraceEvent.scoped("KeyboardVisibilityDelegate.calculateKeyboardHeight")) {
+            Rect appRect = new Rect();
+            rootView.getWindowVisibleDisplayFrame(appRect);
 
-        // Assume status bar is always at the top of the screen.
-        final int statusBarHeight = appRect.top;
+            // Assume status bar is always at the top of the screen.
+            final int statusBarHeight = appRect.top;
 
-        int bottomMargin = rootView.getHeight() - (appRect.height() + statusBarHeight);
+            int bottomMargin = rootView.getHeight() - (appRect.height() + statusBarHeight);
 
-        // If there is no bottom margin, the keyboard is not showing.
-        if (bottomMargin <= 0) return 0;
-
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            // If there is no bottom margin, the keyboard is not showing.
+            if (bottomMargin <= 0) return 0;
             WindowInsets insets = rootView.getRootWindowInsets();
             if (insets != null) { // Either not supported or the rootView isn't attached.
                 bottomMargin -= insets.getStableInsetBottom();
             }
+
+            return bottomMargin; // This might include a bottom navigation.
         }
-
-        return bottomMargin; // This might include a bottom navigation.
-    }
-
-    protected int calculateKeyboardDetectionThreshold(Context context, View rootView) {
-        Rect appRect = new Rect();
-        rootView.getWindowVisibleDisplayFrame(appRect);
-
-        // If the display frame width is < root view width, controls are on the side of
-        // the screen. The inverse is not necessarily true; i.e. if navControlsOnSide is
-        // false, it doesn't mean the controls are not on the side or that they _are_ at
-        // the bottom. It might just mean the app is not responsible for drawing their
-        // background.
-        boolean navControlsOnSide = appRect.width() != rootView.getWidth();
-        // If the Android nav controls are on the sides instead of at the bottom, its
-        // height is not needed.
-        if (navControlsOnSide) return 0;
-
-        // Since M, window insets provide a good keyboard height - no guessing the nav required.
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
-            return 0;
-        }
-        // In the event we couldn't get the bottom nav height, use a best guess
-        // of the keyboard height. In certain cases this also means including
-        // the height of the Android navigation.
-        final float density = context.getResources().getDisplayMetrics().density;
-        return (int) (KEYBOARD_DETECT_BOTTOM_THRESHOLD_DP * density);
     }
 
     /**
@@ -208,9 +180,7 @@
      */
     protected boolean isAndroidSoftKeyboardShowing(Context context, View view) {
         View rootView = view.getRootView();
-        return rootView != null
-                && calculateKeyboardHeight(rootView)
-                > calculateKeyboardDetectionThreshold(context, rootView);
+        return rootView != null && calculateKeyboardHeight(rootView) > 0;
     }
 
     /**
diff --git a/ui/display/mojom/screen_info.mojom b/ui/display/mojom/screen_info.mojom
index 7991569..6a678028 100644
--- a/ui/display/mojom/screen_info.mojom
+++ b/ui/display/mojom/screen_info.mojom
@@ -40,6 +40,12 @@
   // this may be negative.
   gfx.mojom.Rect rect;
 
+  // This lets `window.screen` provide viewport dimensions while the frame is
+  // fullscreen as a speculative site compatibility measure, because web authors
+  // may assume that screen dimensions match window.innerWidth/innerHeight while
+  // a page is fullscreen, but that is not always true. crbug.com/1367416
+  gfx.mojom.Size? size_override;
+
   // The portion of the monitor's rectangle that can be used by applications.
   gfx.mojom.Rect available_rect;
 
diff --git a/ui/display/mojom/screen_info_mojom_traits.cc b/ui/display/mojom/screen_info_mojom_traits.cc
index 0cd3c57..c07d049 100644
--- a/ui/display/mojom/screen_info_mojom_traits.cc
+++ b/ui/display/mojom/screen_info_mojom_traits.cc
@@ -14,6 +14,7 @@
   if (!data.ReadDisplayColorSpaces(&out->display_color_spaces) ||
       !data.ReadRect(&out->rect) ||
       !data.ReadAvailableRect(&out->available_rect) ||
+      !data.ReadSizeOverride(&out->size_override) ||
       !data.ReadLabel(&out->label)) {
     return false;
   }
diff --git a/ui/display/mojom/screen_info_mojom_traits.h b/ui/display/mojom/screen_info_mojom_traits.h
index 57f37527..b5105b7 100644
--- a/ui/display/mojom/screen_info_mojom_traits.h
+++ b/ui/display/mojom/screen_info_mojom_traits.h
@@ -44,6 +44,11 @@
     return r.available_rect;
   }
 
+  static const absl::optional<gfx::Size>& size_override(
+      const display::ScreenInfo& r) {
+    return r.size_override;
+  }
+
   static display::mojom::ScreenOrientation orientation_type(
       const display::ScreenInfo& r) {
     return r.orientation_type;
diff --git a/ui/display/screen_info.cc b/ui/display/screen_info.cc
index 98e0d3b..7acf2096 100644
--- a/ui/display/screen_info.cc
+++ b/ui/display/screen_info.cc
@@ -19,6 +19,7 @@
          is_monochrome == other.is_monochrome &&
          display_frequency == other.display_frequency && rect == other.rect &&
          available_rect == other.available_rect &&
+         size_override == other.size_override &&
          orientation_type == other.orientation_type &&
          orientation_angle == other.orientation_angle &&
          is_extended == other.is_extended && is_primary == other.is_primary &&
diff --git a/ui/display/screen_info.h b/ui/display/screen_info.h
index 290ed4d..a8102f1 100644
--- a/ui/display/screen_info.h
+++ b/ui/display/screen_info.h
@@ -5,6 +5,7 @@
 #ifndef UI_DISPLAY_SCREEN_INFO_H_
 #define UI_DISPLAY_SCREEN_INFO_H_
 
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/display/display_export.h"
 #include "ui/display/mojom/screen_orientation.mojom-shared.h"
 #include "ui/display/types/display_constants.h"
@@ -54,6 +55,12 @@
   //   some of the rectangle's coordinates may be negative values".
   gfx::Rect available_rect;
 
+  // This lets `window.screen` provide viewport dimensions while the frame is
+  // fullscreen as a speculative site compatibility measure, because web authors
+  // may assume that screen dimensions match window.innerWidth/innerHeight while
+  // a page is fullscreen, but that is not always true. crbug.com/1367416
+  absl::optional<gfx::Size> size_override;
+
   // This is the orientation 'type' or 'name', as in landscape-primary or
   // portrait-secondary for examples.
   // See ui/display/mojom/screen_orientation.mojom for the full list.
diff --git a/ui/file_manager/file_manager/background/js/volume_manager_util.js b/ui/file_manager/file_manager/background/js/volume_manager_util.js
index e44589a..d03b18f 100644
--- a/ui/file_manager/file_manager/background/js/volume_manager_util.js
+++ b/ui/file_manager/file_manager/background/js/volume_manager_util.js
@@ -41,7 +41,7 @@
     'timeout(resolveIsolatedEntries)';
 
 /**
- * Throws an Error when the given error is not in
+ * Logs a warning message if the given error is not in
  * VolumeManagerCommon.VolumeError.
  *
  * @param {string} error Status string usually received from APIs.
@@ -53,7 +53,7 @@
     }
   }
 
-  throw new Error('Invalid mount error: ' + error);
+  console.warn(`Invalid mount error: ${error}`);
 };
 
 /**
diff --git a/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.cc b/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.cc
index 9116980a..04613449 100644
--- a/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.cc
+++ b/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.cc
@@ -427,8 +427,10 @@
 
   // `entered_output` can be null in unit tests, where it doesn't wait for
   // output events.
-  if (!entered_output)
+  if (!entered_output) {
+    DLOG(WARNING) << "Entered output is null, cannot request window bounds.";
     return;
+  }
 
   if (aura_toplevel_ && zaura_toplevel_get_version(aura_toplevel_.get()) >=
                             ZAURA_TOPLEVEL_SET_WINDOW_BOUNDS_SINCE_VERSION) {
diff --git a/ui/views/cocoa/immersive_mode_controller_unittest.mm b/ui/views/cocoa/immersive_mode_controller_unittest.mm
index af34dd3..47ad996 100644
--- a/ui/views/cocoa/immersive_mode_controller_unittest.mm
+++ b/ui/views/cocoa/immersive_mode_controller_unittest.mm
@@ -100,7 +100,7 @@
           &view_will_appear_ran));
   immersive_mode_controller->Enable();
   EXPECT_TRUE(view_will_appear_ran);
-  EXPECT_EQ(browser().titlebarAccessoryViewControllers.count, 1u);
+  EXPECT_EQ(browser().titlebarAccessoryViewControllers.count, 2u);
 }
 
 // Test that child windows in immersive mode properly balance the revealed lock
@@ -142,15 +142,23 @@
   immersive_mode_controller->RevealLock();
   EXPECT_EQ(immersive_mode_controller->revealed_lock_count(), 3);
 
-  // One controller for Top Chrome and another hidden controller that pins the
-  // Title Bar.
-  EXPECT_EQ(browser().titlebarAccessoryViewControllers.count, 2u);
+  // One controller for Top Chrome, one for an AppKit workaround
+  // (https://crbug.com/1369643) and another hidden controller that pins the
+  // titlebar.
+  EXPECT_EQ(browser().titlebarAccessoryViewControllers.count, 3u);
 
   // Ensure the clear controller's view covers the browser view.
   NSTitlebarAccessoryViewController* clear_controller =
-      browser().titlebarAccessoryViewControllers.lastObject;
+      browser().titlebarAccessoryViewControllers[2];
+  EXPECT_TRUE(clear_controller);
+
+  NSTitlebarAccessoryViewController* thin_controller =
+      browser().titlebarAccessoryViewControllers[1];
+  EXPECT_TRUE(thin_controller);
+
   EXPECT_EQ(clear_controller.view.frame.size.height,
-            browser().contentView.frame.size.height);
+            browser().contentView.frame.size.height -
+                thin_controller.view.frame.size.height);
   EXPECT_EQ(clear_controller.view.frame.size.width,
             browser().contentView.frame.size.width);
 
@@ -159,11 +167,11 @@
   immersive_mode_controller->RevealUnlock();
   immersive_mode_controller->RevealUnlock();
   EXPECT_EQ(immersive_mode_controller->revealed_lock_count(), 1);
-  EXPECT_EQ(browser().titlebarAccessoryViewControllers.count, 2u);
+  EXPECT_EQ(browser().titlebarAccessoryViewControllers.count, 3u);
 
   immersive_mode_controller->RevealUnlock();
   EXPECT_EQ(immersive_mode_controller->revealed_lock_count(), 0);
-  EXPECT_EQ(browser().titlebarAccessoryViewControllers.count, 1u);
+  EXPECT_EQ(browser().titlebarAccessoryViewControllers.count, 2u);
 }
 
 // Test ImmersiveModeController construction and destruction.
diff --git a/ui/webui/resources/cr_elements/cr_lottie/cr_lottie.ts b/ui/webui/resources/cr_elements/cr_lottie/cr_lottie.ts
index 9415086..8a4039e 100644
--- a/ui/webui/resources/cr_elements/cr_lottie/cr_lottie.ts
+++ b/ui/webui/resources/cr_elements/cr_lottie/cr_lottie.ts
@@ -17,14 +17,39 @@
 
 import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-import {assert} from '../../js/assert_ts.js';
+import {assert, assertNotReached} from '../../js/assert_ts.js';
+import {getTrustedScriptURL} from '../../js/static_types.js';
 
 import {getTemplate} from './cr_lottie.html.js';
 
-/**
- * The resource url for the lottier web worker script.
- */
-export const LOTTIE_JS_URL = 'chrome://resources/lottie/lottie_worker.min.js';
+let workerLoaderPolicy: TrustedTypePolicy|null = null;
+
+function getLottieWorkerURL(): TrustedScriptURL {
+  if (workerLoaderPolicy === null) {
+    workerLoaderPolicy =
+        window.trustedTypes!.createPolicy('lottie-worker-script-loader', {
+          createScriptURL: (_ignore: string) => {
+            const workerUrl =
+                getTrustedScriptURL`chrome://resources/lottie/lottie_worker.min.js`;
+            // Need to add a try-catch clause because in tests the parent
+            // element can be removed from the DOM before the importScripts()
+            // call  has finished loading, resulting in test errors.
+            const script = `try{ importScripts('${
+                workerUrl}'); } catch(e) { console.warn(e); };`;
+            // CORS blocks loading worker script from a different origin, even
+            // if chrome://resources/ is added in the 'worker-src' CSP header.
+            // (see https://crbug.com/1385477). Loading scripts as blob and then
+            // instantiating it as web worker is possible.
+            const blob = new Blob([script], {type: 'text/javascript'});
+            return URL.createObjectURL(blob);
+          },
+          createHTML: () => assertNotReached(),
+          createScript: () => assertNotReached(),
+        });
+  }
+
+  return workerLoaderPolicy.createScriptURL('');
+}
 
 interface OffscreenCanvas {
   width: number;
@@ -128,18 +153,9 @@
   override connectedCallback() {
     super.connectedCallback();
 
-    // CORS blocks loading worker script from a different origin but
-    // loading scripts as blob and then instantiating it as web worker
-    // is possible.
-    this.sendXmlHttpRequest_(
-        LOTTIE_JS_URL, 'blob', (response: Blob|MediaSource|object|null) => {
-          if (this.isConnected) {
-            this.worker_ =
-                new Worker(URL.createObjectURL(response as Blob | MediaSource));
-            this.worker_.onmessage = this.onMessage_.bind(this);
-            this.initialize_();
-          }
-        });
+    this.worker_ = new Worker(getLottieWorkerURL() as unknown as URL);
+    this.worker_.onmessage = this.onMessage_.bind(this);
+    this.initialize_();
   }
 
   override disconnectedCallback() {